diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml index 35f42462b8..5b44517ec5 100644 --- a/.github/actions/setup-bun/action.yml +++ b/.github/actions/setup-bun/action.yml @@ -33,8 +33,9 @@ runs: shell: bash run: echo "dir=$(bun pm cache)" >> "$GITHUB_OUTPUT" - - name: Cache Bun dependencies - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + - name: Restore Bun dependencies + id: bun-cache + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ steps.cache.outputs.dir }} key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }} @@ -56,3 +57,10 @@ runs: bun install ${{ inputs.install-flags }} fi shell: bash + + - name: Save Bun dependencies + if: steps.bun-cache.outputs.cache-hit != 'true' && github.event_name != 'pull_request' && github.event_name != 'pull_request_target' + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ${{ steps.cache.outputs.dir }} + key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index bef1e70293..5f8bac973a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -244,9 +244,9 @@ jobs: - host: "blacksmith-4vcpu-ubuntu-2404" target: x86_64-unknown-linux-gnu platform_flag: --linux - - host: "blacksmith-4vcpu-ubuntu-2404" + - host: "blacksmith-4vcpu-ubuntu-2404-arm" target: aarch64-unknown-linux-gnu - platform_flag: --linux + platform_flag: --linux --arm64 runs-on: ${{ matrix.settings.host }} steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 diff --git a/AGENTS.md b/AGENTS.md index 7913ddabd2..0b1998ec50 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -73,6 +73,29 @@ function foo() { } ``` +### Complex Logic + +When a function has several validation branches or supporting details, make the main function read as the happy path and move supporting details into small helpers below it. + +```ts +// Good +export function loadThing(input: unknown) { + const config = requireConfig(input) + const metadata = readMetadata(input) + return createThing({ config, metadata }) +} + +function requireConfig(input: unknown) { + ... +} +``` + +- Keep helpers close to the code they support, below the main export when that improves readability. +- Do not over-abstract simple expressions into many single-use helpers; extract only when it names a real concept like `requireConfig` or `readMetadata`. +- Do not return `Effect` from helpers unless they actually perform effectful work. Synchronous parsing, validation, and option building should stay synchronous. +- Prefer Effect schema helpers such as `Schema.UnknownFromJsonString` and `Schema.decodeUnknownOption` over manual `JSON.parse` wrapped in `Effect.try` when parsing untrusted JSON strings. +- Add comments for non-obvious constraints and surprising behavior, not for obvious assignments or control flow. + ### Schema Definitions (Drizzle) Use snake_case for field names so column names don't need to be redefined as strings. diff --git a/bun.lock b/bun.lock index 4268e5fb7d..2a79552b9e 100644 --- a/bun.lock +++ b/bun.lock @@ -65,7 +65,6 @@ "solid-list": "catalog:", "tailwindcss": "catalog:", "virtua": "catalog:", - "zod": "catalog:", }, "devDependencies": { "@happy-dom/global-registrator": "20.0.11", @@ -198,21 +197,48 @@ "opencode": "./bin/opencode", }, "dependencies": { + "@ai-sdk/alibaba": "1.0.17", + "@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/cohere": "3.0.27", + "@ai-sdk/deepinfra": "2.0.41", + "@ai-sdk/gateway": "3.0.104", + "@ai-sdk/google": "3.0.63", + "@ai-sdk/google-vertex": "4.0.112", + "@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/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", + "@aws-sdk/credential-providers": "3.993.0", "@effect/opentelemetry": "catalog:", "@effect/platform-node": "catalog:", "@npmcli/arborist": "9.4.0", "@npmcli/config": "10.8.1", + "@openrouter/ai-sdk-provider": "2.8.1", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.6.1", "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", + "ai-gateway-provider": "3.1.2", "cross-spawn": "catalog:", "effect": "catalog:", + "gitlab-ai-provider": "6.6.0", "glob": "13.0.5", + "google-auth-library": "10.5.0", + "immer": "11.1.4", "mime-types": "3.0.2", "minimatch": "10.2.5", "npm-package-arg": "13.0.2", "semver": "^7.6.3", + "venice-ai-sdk-provider": "2.0.1", "xdg-basedir": "5.1.0", "zod": "catalog:", }, @@ -382,7 +408,6 @@ "@ai-sdk/openai-compatible": "2.0.41", "@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", @@ -399,6 +424,7 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", + "@opencode-ai/ui": "workspace:*", "@openrouter/ai-sdk-provider": "2.8.1", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.6.1", @@ -420,7 +446,6 @@ "bonjour-service": "1.3.0", "bun-pty": "0.4.8", "chokidar": "4.0.3", - "cli-sound": "1.1.3", "clipboardy": "4.0.0", "cross-spawn": "catalog:", "decimal.js": "10.5.0", @@ -432,6 +457,7 @@ "glob": "13.0.5", "google-auth-library": "10.5.0", "gray-matter": "4.0.3", + "htmlparser2": "8.0.2", "ignore": "7.0.5", "immer": "11.1.4", "jsonc-parser": "3.3.1", @@ -510,9 +536,9 @@ "typescript": "catalog:", }, "peerDependencies": { - "@opentui/core": ">=0.2.6", - "@opentui/keymap": ">=0.2.6", - "@opentui/solid": ">=0.2.6", + "@opentui/core": ">=0.2.8", + "@opentui/keymap": ">=0.2.8", + "@opentui/solid": ">=0.2.8", }, "optionalPeers": [ "@opentui/core", @@ -679,6 +705,9 @@ "@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch", }, "overrides": { + "@opentui/core": "catalog:", + "@opentui/keymap": "catalog:", + "@opentui/solid": "catalog:", "@types/bun": "catalog:", "@types/node": "catalog:", }, @@ -692,9 +721,9 @@ "@npmcli/arborist": "9.4.0", "@octokit/rest": "22.0.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@opentui/core": "0.2.6", - "@opentui/keymap": "0.2.6", - "@opentui/solid": "0.2.6", + "@opentui/core": "0.2.8", + "@opentui/keymap": "0.2.8", + "@opentui/solid": "0.2.8", "@pierre/diffs": "1.1.0-beta.18", "@playwright/test": "1.59.1", "@sentry/solid": "10.36.0", @@ -1073,8 +1102,6 @@ "@develar/schema-utils": ["@develar/schema-utils@2.6.5", "", { "dependencies": { "ajv": "^6.12.0", "ajv-keywords": "^3.4.1" } }, "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig=="], - "@dimforge/rapier2d-simd-compat": ["@dimforge/rapier2d-simd-compat@0.17.3", "", {}, "sha512-bijvwWz6NHsNj5e5i1vtd3dU2pDhthSaTUZSh14DUGGKJfw8eMnlWZsxwHBxB/a3AXVNDjL9abuHw1k9FGR+jg=="], - "@dot/log": ["@dot/log@0.1.5", "", { "dependencies": { "chalk": "^4.1.2", "loglevelnext": "^6.0.0", "p-defer": "^3.0.0" } }, "sha512-ECraEVJWv2f2mWK93lYiefUkphStVlKD6yKDzisuoEmxuLKrxO9iGetHK2DoEAkj7sxjE886n0OUVVCUx0YPNg=="], "@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="], @@ -1291,62 +1318,6 @@ "@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", {}, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="], - "@jimp/core": ["@jimp/core@1.6.0", "", { "dependencies": { "@jimp/file-ops": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^16.0.0", "mime": "3" } }, "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w=="], - - "@jimp/diff": ["@jimp/diff@1.6.0", "", { "dependencies": { "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "pixelmatch": "^5.3.0" } }, "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw=="], - - "@jimp/file-ops": ["@jimp/file-ops@1.6.0", "", {}, "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ=="], - - "@jimp/js-bmp": ["@jimp/js-bmp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "bmp-ts": "^1.0.9" } }, "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw=="], - - "@jimp/js-gif": ["@jimp/js-gif@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "gifwrap": "^0.10.1", "omggif": "^1.0.10" } }, "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g=="], - - "@jimp/js-jpeg": ["@jimp/js-jpeg@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "jpeg-js": "^0.4.4" } }, "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA=="], - - "@jimp/js-png": ["@jimp/js-png@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "pngjs": "^7.0.0" } }, "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg=="], - - "@jimp/js-tiff": ["@jimp/js-tiff@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "utif2": "^4.1.0" } }, "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw=="], - - "@jimp/plugin-blit": ["@jimp/plugin-blit@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA=="], - - "@jimp/plugin-blur": ["@jimp/plugin-blur@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw=="], - - "@jimp/plugin-circle": ["@jimp/plugin-circle@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw=="], - - "@jimp/plugin-color": ["@jimp/plugin-color@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "tinycolor2": "^1.6.0", "zod": "^3.23.8" } }, "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA=="], - - "@jimp/plugin-contain": ["@jimp/plugin-contain@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ=="], - - "@jimp/plugin-cover": ["@jimp/plugin-cover@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA=="], - - "@jimp/plugin-crop": ["@jimp/plugin-crop@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang=="], - - "@jimp/plugin-displace": ["@jimp/plugin-displace@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q=="], - - "@jimp/plugin-dither": ["@jimp/plugin-dither@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0" } }, "sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ=="], - - "@jimp/plugin-fisheye": ["@jimp/plugin-fisheye@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA=="], - - "@jimp/plugin-flip": ["@jimp/plugin-flip@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg=="], - - "@jimp/plugin-hash": ["@jimp/plugin-hash@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "any-base": "^1.1.0" } }, "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q=="], - - "@jimp/plugin-mask": ["@jimp/plugin-mask@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA=="], - - "@jimp/plugin-print": ["@jimp/plugin-print@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/types": "1.6.0", "parse-bmfont-ascii": "^1.0.6", "parse-bmfont-binary": "^1.0.6", "parse-bmfont-xml": "^1.1.6", "simple-xml-to-json": "^1.2.2", "zod": "^3.23.8" } }, "sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A=="], - - "@jimp/plugin-quantize": ["@jimp/plugin-quantize@1.6.0", "", { "dependencies": { "image-q": "^4.0.0", "zod": "^3.23.8" } }, "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg=="], - - "@jimp/plugin-resize": ["@jimp/plugin-resize@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA=="], - - "@jimp/plugin-rotate": ["@jimp/plugin-rotate@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw=="], - - "@jimp/plugin-threshold": ["@jimp/plugin-threshold@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w=="], - - "@jimp/types": ["@jimp/types@1.6.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg=="], - - "@jimp/utils": ["@jimp/utils@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "tinycolor2": "^1.6.0" } }, "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA=="], - "@joshwooding/vite-plugin-react-docgen-typescript": ["@joshwooding/vite-plugin-react-docgen-typescript@0.7.0", "", { "dependencies": { "glob": "^13.0.1", "react-docgen-typescript": "^2.2.2" }, "peerDependencies": { "typescript": ">= 4.3.x", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["typescript"] }, "sha512-qvsTEwEFefhdirGOPnu9Wp6ChfIwy2dBCRuETU3uE+4cC+PFoxMSiiEhxk4lOluA34eARHA0OxqsEUYDqRMgeQ=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -1619,23 +1590,23 @@ "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="], - "@opentui/core": ["@opentui/core@0.2.6", "", { "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.6", "@opentui/core-darwin-x64": "0.2.6", "@opentui/core-linux-arm64": "0.2.6", "@opentui/core-linux-x64": "0.2.6", "@opentui/core-win32-arm64": "0.2.6", "@opentui/core-win32-x64": "0.2.6" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-dBpMaWVM7wtW2/2TlGPrkPjg6gOL3MVU/5XXk+U1LDJB8L4q4NeYWVdzfAVNcEvgmuuCy/cVqdY2D4ei+e7MMg=="], + "@opentui/core": ["@opentui/core@0.2.8", "", { "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.8", "@opentui/core-darwin-x64": "0.2.8", "@opentui/core-linux-arm64": "0.2.8", "@opentui/core-linux-x64": "0.2.8", "@opentui/core-win32-arm64": "0.2.8", "@opentui/core-win32-x64": "0.2.8" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-bRRiCXuwjS8/6mN1oA5iVaf55z9APyalm7FnoxkLkEyIU1VDaQeTpYtElBbfo1rxtcO6Rj53XywH9oW8auNO9A=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.2.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hR5nsxNj+059utzenTCF0kealUlibON6fLuebFUCGM/5kJnqa+shIh0XbUDFm0+F47vqVUgZufBdUuieQZIbvQ=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.2.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Qh6VCMQgW3hWh/7MR51y+XuQezh8NOLwKS8EQSoKzAr4VOc/W5P0/DvgMKgwaqXw2Mz0AIba/BvZ6by20yc4zA=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.2.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-pJ/bH4WC/mbBaakM1YdH6TVo67jhy0KPd61bCz97w0I/PJGr8fmNKvhmMt/AwyFgOQi3FYZiEKLMpGdvUcSsrQ=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.2.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-wQjJ38C3IiVx/gwwBYxnCarzgD75FdS7IyUErt3lhn57XriNiCbb7ScphWnRMwwtL8CI+bBGzClroDRA2lCfvg=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.2.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Pnd3kOxig8ii+/IqYheOPEgferylsQA0L6tKBnHQ9jRlCJOcu0Rv65Jepueh212vevdV9DzPURJnhejG06J6g=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.2.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-fx4ADeWSSSVU1O/MkMnklCRxtWRy6CLeAvktLlNdPb+BhmQIDg1kpZcdv7m/3cgD1/ksFEXIwO6VTvfKYE0umw=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.2.6", "", { "os": "linux", "cpu": "x64" }, "sha512-458Mx9tBzEPzfft8cSt5ZaIpEepoxBXBOL6AUVmDTKWaZ3uouraPcEKraGAyvOTDQp2XDI3R8c/2GdaR77FaUQ=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.2.8", "", { "os": "linux", "cpu": "x64" }, "sha512-4ekUyzopBj2ClsUbneLnUOrmZtvU67FCVFLgmBfKL4IvVl/P0YobGNg71gN1JNiYpY7hK77qOpidVLHcNMIE7w=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.2.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-BDUrdrT1RCcVnQoHJmUut4y811jDBAEtc6GJFB4Gs265Be8SrTjVCus6p2fSQ7j9sZQ1OcjO+5+4NkheSZICDQ=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.2.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-63K046wpzTzQOLOG9LTsp3+Ld0TNTxeQczexkg0pKSBxZFhws+/9YIGjTctZmJUfE1g1X4tI31dO+KNRpXRHQw=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.2.6", "", { "os": "win32", "cpu": "x64" }, "sha512-SUYAzRJ9TSoD2Qt8kn6FJz6dbTrFEPVig5mScB4zFGgGQO/Bbod2/Q31vLS/IQrX+FDb67WaErD+kuMCnMPPLA=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.2.8", "", { "os": "win32", "cpu": "x64" }, "sha512-+WDiTlTyDpgkis8rPAhW1fS7TwXJih+fk+RYXS2bC3tAKsRD+O3PRSkVABRbjkuXbtfJZf2cjOHZFGN4Vf5qDg=="], - "@opentui/keymap": ["@opentui/keymap@0.2.6", "", { "dependencies": { "@opentui/core": "0.2.6" }, "peerDependencies": { "@opentui/react": "0.2.6", "@opentui/solid": "0.2.6", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-+6OYuedrFCKVo4ryGFNwws++2VOmPcXU3PwpY0mP47gYQY2nvQ+etWIs2Y7r5eMIqUfxVCldkKsrzcEcA4tb/A=="], + "@opentui/keymap": ["@opentui/keymap@0.2.8", "", { "dependencies": { "@opentui/core": "0.2.8" }, "peerDependencies": { "@opentui/react": "0.2.8", "@opentui/solid": "0.2.8", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-/H9j8fP64cf3/nFDCvVP8+7cwU/oRh4sgfQH2NhcPp8illgBb/e9pG5x3vM0nK4RVyTqUvkPXsOeIX5u7vltlg=="], - "@opentui/solid": ["@opentui/solid@0.2.6", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.2.6", "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-2y225WlOGi/fCaajkxBmLyVW8Cr+OmhowHdvrYcz5w2kBD15sKbJLIYu1G9DxceirT1uIyasGy2TGzRRcVkTDg=="], + "@opentui/solid": ["@opentui/solid@0.2.8", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.2.8", "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-f2g0riBuzk4/ZmcJnp1k13odUmNZcfA3nF7RzdSlEfpkwNDfc4xqnRAwYbNNDwGNrJX0JDCTEZY5ZEhuL155MQ=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], @@ -2287,8 +2258,6 @@ "@thisbeyond/solid-dnd": ["@thisbeyond/solid-dnd@0.7.5", "", { "peerDependencies": { "solid-js": "^1.5" } }, "sha512-DfI5ff+yYGpK9M21LhYwIPlbP2msKxN2ARwuu6GF8tT1GgNVDTI8VCQvH4TJFoVApP9d44izmAcTh/iTCH2UUw=="], - "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], - "@tsconfig/bun": ["@tsconfig/bun@1.0.9", "", {}, "sha512-4M0/Ivfwcpz325z6CwSifOBZYji3DFOEpY6zEUt0+Xi2qRhzwvmqQN9XAHJh3OVvRJuAqVTLU2abdCplvp6mwQ=="], "@tsconfig/node22": ["@tsconfig/node22@22.0.2", "", {}, "sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA=="], @@ -2553,8 +2522,6 @@ "ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="], - "any-base": ["any-base@1.1.0", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="], - "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -2623,8 +2590,6 @@ "avvio": ["avvio@9.2.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ=="], - "await-to-js": ["await-to-js@3.0.0", "", {}, "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="], - "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=="], @@ -2689,8 +2654,6 @@ "blob-to-buffer": ["blob-to-buffer@1.2.9", "", {}, "sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA=="], - "bmp-ts": ["bmp-ts@1.0.9", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="], - "body-parser": ["body-parser@1.20.4", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.14.0", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA=="], "bonjour-service": ["bonjour-service@1.3.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA=="], @@ -2733,16 +2696,6 @@ "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="], - "bun-webgpu": ["bun-webgpu@0.1.5", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.5", "bun-webgpu-darwin-x64": "^0.1.5", "bun-webgpu-linux-x64": "^0.1.5", "bun-webgpu-win32-x64": "^0.1.5" } }, "sha512-91/K6S5whZKX7CWAm9AylhyKrLGRz6BUiiPiM/kXadSnD4rffljCD/q9cNFftm5YXhx4MvLqw33yEilxogJvwA=="], - - "bun-webgpu-darwin-arm64": ["bun-webgpu-darwin-arm64@0.1.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lIsDkPzJzPl6yrB5CUOINJFPnTRv6fF/Q8J1mAr43ogSp86WZEg9XZKaT6f3EUJ+9ETogGoMnoj1q0AwHUTbAQ=="], - - "bun-webgpu-darwin-x64": ["bun-webgpu-darwin-x64@0.1.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-uEddf5U7GvKIkM/BV18rUKtYHL6d0KeqBjNHwfqDH9QgEo9KVSKvJXS5I/sMefk5V5pIYE+8tQhtrREevhocng=="], - - "bun-webgpu-linux-x64": ["bun-webgpu-linux-x64@0.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-Y/f15j9r8ba0xUz+3lATtS74OE+PPzQXO7Do/1eCluJcuOlfa77kMjvBK/ShWnem3Y9xqi59pebTPOGRB+CaJA=="], - - "bun-webgpu-win32-x64": ["bun-webgpu-win32-x64@0.1.6", "", { "os": "win32", "cpu": "x64" }, "sha512-MHSFAKqizISb+C5NfDrFe3g0Al5Njnu0j/A+oO2Q+bIWX+fUYjBSowiYE1ZXJx65KuryuB+tiM7Qh6cQbVvkEg=="], - "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], @@ -2813,8 +2766,6 @@ "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], - "cli-sound": ["cli-sound@1.1.3", "", { "dependencies": { "find-exec": "^1.0.3" }, "bin": { "cli-sound": "dist/esm/cli.js" } }, "sha512-dpdF3KS3wjo1fobKG5iU9KyKqzQWAqueymHzZ9epus/dZ40487gAvS6aXFeBul+GiQAQYUTAtUWgQvw6Jftbyg=="], - "cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="], "cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="], @@ -3165,8 +3116,6 @@ "execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], - "exif-parser": ["exif-parser@0.1.12", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="], - "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], @@ -3229,8 +3178,6 @@ "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], - "file-type": ["file-type@16.5.4", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="], - "filelist": ["filelist@1.0.6", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], @@ -3239,8 +3186,6 @@ "find-babel-config": ["find-babel-config@2.1.2", "", { "dependencies": { "json5": "^2.2.3" } }, "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg=="], - "find-exec": ["find-exec@1.0.3", "", { "dependencies": { "shell-quote": "^1.8.1" } }, "sha512-gnG38zW90mS8hm5smNcrBnakPEt+cGJoiMkJwCU0IYnEb0H2NQk0NIljhNW+48oniCriFek/PH6QXbwsJo/qug=="], - "find-my-way": ["find-my-way@9.5.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ=="], "find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="], @@ -3323,8 +3268,6 @@ "ghostty-web": ["ghostty-web@github:anomalyco/ghostty-web#20bd361", {}, "anomalyco-ghostty-web-20bd361", "sha512-dW0nwaiBBcun9y5WJSvm3HxDLe5o9V0xLCndQvWonRVubU8CS1PHxZpLffyPt1YujPWC13ez03aWxcuKBPYYGQ=="], - "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], - "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], @@ -3477,8 +3420,6 @@ "ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="], - "image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="], - "immer": ["immer@11.1.4", "", {}, "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw=="], "import-local": ["import-local@3.2.0", "", { "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" }, "bin": { "import-local-fixture": "fixtures/cli.js" } }, "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA=="], @@ -3621,16 +3562,12 @@ "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], - "jimp": ["jimp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="], - "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=="], - "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="], - "js-base64": ["js-base64@3.7.7", "", {}, "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="], "js-beautify": ["js-beautify@1.15.4", "", { "dependencies": { "config-chain": "^1.1.13", "editorconfig": "^1.0.4", "glob": "^10.4.2", "js-cookie": "^3.0.5", "nopt": "^7.2.1" }, "bin": { "css-beautify": "js/bin/css-beautify.js", "html-beautify": "js/bin/html-beautify.js", "js-beautify": "js/bin/js-beautify.js" } }, "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA=="], @@ -4091,8 +4028,6 @@ "oidc-token-hash": ["oidc-token-hash@5.2.0", "", {}, "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw=="], - "omggif": ["omggif@1.0.10", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="], - "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], @@ -4167,12 +4102,6 @@ "param-case": ["param-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="], - "parse-bmfont-ascii": ["parse-bmfont-ascii@1.0.6", "", {}, "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="], - - "parse-bmfont-binary": ["parse-bmfont-binary@1.0.6", "", {}, "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="], - - "parse-bmfont-xml": ["parse-bmfont-xml@1.1.6", "", { "dependencies": { "xml-parse-from-string": "^1.0.0", "xml2js": "^0.5.0" } }, "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA=="], - "parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="], "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], @@ -4217,8 +4146,6 @@ "peberminta": ["peberminta@0.9.0", "", {}, "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ=="], - "peek-readable": ["peek-readable@4.1.0", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="], - "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], "perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="], @@ -4239,8 +4166,6 @@ "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], - "pixelmatch": ["pixelmatch@5.3.0", "", { "dependencies": { "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q=="], - "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], @@ -4249,16 +4174,12 @@ "pkg-up": ["pkg-up@3.1.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="], - "planck": ["planck@1.5.0", "", { "peerDependencies": { "stage-js": "^1.0.0-alpha.12" } }, "sha512-dlvqJE+FscZgrGUXJ5ybd0o5bvZ5XXyZNbm08xGsXp9WjXeAyWSFT6n9s/1PQcUBo4546fDXA5RMA4wbDyZw6g=="], - "playwright": ["playwright@1.59.1", "", { "dependencies": { "playwright-core": "1.59.1" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw=="], "playwright-core": ["playwright-core@1.59.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg=="], "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], - "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="], - "poe-oauth": ["poe-oauth@0.0.6", "", {}, "sha512-dI8xrVl7RSFh0B+cb4GGuCjIfGtDT9VpbpVkP0UKcunpXF0eFw+6GencoJ7k+E02ZYqopBQApMVWGq70/GP69w=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], @@ -4383,8 +4304,6 @@ "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], - "readable-web-to-node-stream": ["readable-web-to-node-stream@3.0.4", "", { "dependencies": { "readable-stream": "^4.7.0" } }, "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw=="], - "readdir-glob": ["readdir-glob@1.1.3", "", { "dependencies": { "minimatch": "^5.1.0" } }, "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA=="], "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], @@ -4569,8 +4488,6 @@ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], - "shiki": ["shiki@3.20.0", "", { "dependencies": { "@shikijs/core": "3.20.0", "@shikijs/engine-javascript": "3.20.0", "@shikijs/engine-oniguruma": "3.20.0", "@shikijs/langs": "3.20.0", "@shikijs/themes": "3.20.0", "@shikijs/types": "3.20.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg=="], "shikiji": ["shikiji@0.6.13", "", { "dependencies": { "hast-util-to-html": "^9.0.0" } }, "sha512-4T7X39csvhT0p7GDnq9vysWddf2b6BeioiN3Ymhnt3xcy9tXmDcnsEFVxX18Z4YcQgEE/w48dLJ4pPPUcG9KkA=="], @@ -4593,8 +4510,6 @@ "simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="], - "simple-xml-to-json": ["simple-xml-to-json@1.2.7", "", {}, "sha512-mz9VXphOxQWX3eQ/uXCtm6upltoN0DLx8Zb5T4TFC4FHB7S9FDPGre8CfLWqPWQQH/GrQYd2AXhhVM5LDpYx6Q=="], - "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], "sitemap": ["sitemap@9.0.1", "", { "dependencies": { "@types/node": "^24.9.2", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.4.1" }, "bin": { "sitemap": "dist/esm/cli.js" } }, "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ=="], @@ -4681,8 +4596,6 @@ "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], - "stage-js": ["stage-js@1.0.2", "", {}, "sha512-EWTRBYlg7Qv9wGUao99/PfRe3KaiQqWmgSvTOXvaWnu1Jk/q/vV8yJVu6bi/3EqDZeMVnCPAjheba6OFc5k1GQ=="], - "standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="], "stat-mode": ["stat-mode@1.0.0", "", {}, "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg=="], @@ -4731,8 +4644,6 @@ "strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="], - "strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="], - "stubborn-fs": ["stubborn-fs@2.0.0", "", { "dependencies": { "stubborn-utils": "^1.0.1" } }, "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA=="], "stubborn-utils": ["stubborn-utils@1.0.2", "", {}, "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg=="], @@ -4785,8 +4696,6 @@ "thread-stream": ["thread-stream@4.0.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA=="], - "three": ["three@0.177.0", "", {}, "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg=="], - "thunky": ["thunky@1.1.0", "", {}, "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="], "tiny-async-pool": ["tiny-async-pool@1.3.0", "", { "dependencies": { "semver": "^5.5.0" } }, "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA=="], @@ -4799,8 +4708,6 @@ "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], - "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], - "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], @@ -4821,8 +4728,6 @@ "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], - "token-types": ["token-types@4.2.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ=="], - "toml": ["toml@4.1.1", "", {}, "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw=="], "toolbeam-docs-theme": ["toolbeam-docs-theme@0.4.8", "", { "peerDependencies": { "@astrojs/starlight": "^0.34.3", "astro": "^5.7.13" } }, "sha512-b+5ynEFp4Woe5a22hzNQm42lD23t13ZMihVxHbzjA50zdcM9aOSJTIjdJ0PDSd4/50HbBXcpHiQsz6rM4N88ww=="], @@ -4975,8 +4880,6 @@ "utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="], - "utif2": ["utif2@4.1.0", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="], - "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=="], @@ -5105,8 +5008,6 @@ "xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="], - "xml-parse-from-string": ["xml-parse-from-string@1.0.1", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="], - "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=="], @@ -5459,46 +5360,10 @@ "@gitlab/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=="], - "@happy-dom/global-registrator/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "@hey-api/openapi-ts/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="], "@hey-api/openapi-ts/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "@jimp/core/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], - - "@jimp/plugin-blit/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-circle/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-color/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-contain/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-cover/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-crop/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-displace/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-fisheye/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-flip/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-mask/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-print/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-quantize/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-resize/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-rotate/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/plugin-threshold/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "@jimp/types/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@jsx-email/cli/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "@jsx-email/cli/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="], @@ -5585,6 +5450,12 @@ "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + "@opencode-ai/core/@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.71", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg=="], + + "@opencode-ai/core/@ai-sdk/openai": ["@ai-sdk/openai@3.0.53", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ=="], + + "@opencode-ai/core/@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-ai/desktop/@actions/artifact": ["@actions/artifact@4.0.0", "", { "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^6.0.1", "@actions/http-client": "^2.1.0", "@azure/core-http": "^3.0.5", "@azure/storage-blob": "^12.15.0", "@octokit/core": "^5.2.1", "@octokit/plugin-request-log": "^1.0.4", "@octokit/plugin-retry": "^3.0.9", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@protobuf-ts/plugin": "^2.2.3-alpha.1", "archiver": "^7.0.1", "jwt-decode": "^3.1.2", "unzip-stream": "^0.3.1" } }, "sha512-HCc2jMJRAfviGFAh0FsOR/jNfWhirxl7W6z8zDtttt0GltwxBLdEIjLiweOPFl9WbyJRW1VWnPUSAixJqcWUMQ=="], "@opencode-ai/desktop/marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], @@ -5637,24 +5508,16 @@ "@slack/bolt/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], - "@slack/logger/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "@slack/oauth/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], - "@slack/oauth/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "@slack/socket-mode/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], - "@slack/socket-mode/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "@slack/socket-mode/@types/ws": ["@types/ws@7.4.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww=="], "@slack/socket-mode/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], "@slack/web-api/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="], - "@slack/web-api/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "@slack/web-api/eventemitter3": ["eventemitter3@3.1.2", "", {}, "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="], "@slack/web-api/form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="], @@ -5715,62 +5578,8 @@ "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], - "@types/body-parser/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/cacache/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/cacheable-request/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/connect/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/cross-spawn/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/express-serve-static-core/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/fontkit/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/fs-extra/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/is-stream/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/jsonwebtoken/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/keyv/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/mssql/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/node-fetch/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/npm-registry-fetch/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/npmcli__arborist/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/npmlog/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/pacote/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/plist/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "@types/plist/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], - "@types/readable-stream/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/responselike/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/sax/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/send/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/serve-static/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/ssri/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/tunnel/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/ws/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "@types/yauzl/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "@vitest/expect/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], "@vitest/expect/tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], @@ -5847,18 +5656,12 @@ "builder-util-runtime/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], - "bun-types/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - - "bun-webgpu/@webgpu/types": ["@webgpu/types@0.1.69", "", {}, "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="], - "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "c12/dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="], "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], - "cloudflare/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], "condense-newlines/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], @@ -5893,8 +5696,6 @@ "effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], - "electron/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "electron-builder/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "electron-builder/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], @@ -5949,8 +5750,6 @@ "gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], - "happy-dom/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "happy-dom/ws": ["ws@8.20.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA=="], "html-minifier-terser/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], @@ -5963,8 +5762,6 @@ "iconv-corefoundation/node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="], - "image-q/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "js-beautify/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "js-beautify/nopt": ["nopt@7.2.1", "", { "dependencies": { "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w=="], @@ -6037,9 +5834,9 @@ "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.1.105", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.105", "@opentui/core-darwin-x64": "0.1.105", "@opentui/core-linux-arm64": "0.1.105", "@opentui/core-linux-x64": "0.1.105", "@opentui/core-win32-arm64": "0.1.105", "@opentui/core-win32-x64": "0.1.105", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-vllSOOCW6VIThV/96GRLJ1IxIBuR+ci6FDvnPIAG4s7SJ/FW6zAkqDn1xrtBwwk/lM3QWjLqy8BZc+zwWvveJA=="], + "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.1.105", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.105", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-uxnaMP802sCI487pv/Hk9xdFdIj9mkg3eNliAqbqR0Shmd4phcjKEZvPRpijjmI99j4s9nul71jzF3h1oz31Nw=="], + "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=="], @@ -6053,14 +5850,10 @@ "p-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], - "parse-bmfont-xml/xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], - "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "pixelmatch/pngjs": ["pngjs@6.0.0", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="], - "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], "pkg-up/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], @@ -6085,8 +5878,6 @@ "proper-lockfile/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - "protobufjs/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "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=="], @@ -6117,8 +5908,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/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "sitemap/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], @@ -6141,20 +5930,14 @@ "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "stripe/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "tedious/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "tiny-async-pool/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], - "token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "tree-sitter-bash/node-addon-api": ["node-addon-api@8.7.0", "", {}, "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA=="], "tw-to-css/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], @@ -6171,8 +5954,6 @@ "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "utif2/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], - "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=="], @@ -6487,8 +6268,6 @@ "@gitlab/opencode-gitlab-auth/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], - "@happy-dom/global-registrator/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "@jsx-email/cli/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="], "@jsx-email/cli/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="], @@ -6683,14 +6462,6 @@ "@sentry/cli/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "@slack/logger/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@slack/oauth/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@slack/socket-mode/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@slack/web-api/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "@slack/web-api/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], "@slack/web-api/p-queue/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], @@ -6717,60 +6488,6 @@ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "@types/body-parser/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/cacache/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/cacheable-request/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/connect/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/cross-spawn/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/express-serve-static-core/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/fontkit/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/fs-extra/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/is-stream/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/jsonwebtoken/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/keyv/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/mssql/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/node-fetch/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/npm-registry-fetch/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/npmcli__arborist/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/npmlog/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/pacote/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/plist/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/readable-stream/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/responselike/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/sax/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/send/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/serve-static/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/ssri/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/tunnel/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/ws/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "@types/yauzl/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], @@ -6819,12 +6536,8 @@ "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "bun-types/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], - "cloudflare/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "crc/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -6843,8 +6556,6 @@ "electron-winstaller/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - "electron/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "esbuild-plugin-copy/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -6857,14 +6568,10 @@ "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - "happy-dom/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "iconv-corefoundation/cli-truncate/slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="], "iconv-corefoundation/cli-truncate/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "image-q/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "js-beautify/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "js-beautify/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], @@ -6883,8 +6590,6 @@ "motion/framer-motion/motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], - "mssql/tedious/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], - "mssql/tedious/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "opencode-gitlab-auth/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], @@ -6903,24 +6608,22 @@ "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.1.105", "", { "os": "darwin", "cpu": "arm64" }, "sha512-1pIL7aer9amwj8EpYoMNtvavKetIe+nX8uBRmYsMQb+KvJoUAZUqENfRW+qHE5WrsOyxx8/QoyXTHw15GG5iLQ=="], + "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.1.105", "", { "os": "darwin", "cpu": "x64" }, "sha512-hLIRSWlK3gY2NRXJGWiTBiMYSmRDjOYFZF6WtUVXhY2SL3sp08dhmr/6dmAVH+3pKCsCipLEsrrcQX6SAihCTA=="], + "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.1.105", "", { "os": "linux", "cpu": "arm64" }, "sha512-jlRKfPkozTZEkHEePuCWYcTIUtPm+ieInAwGVqGmjbvqjxdVv1/W/Dt6LEZ/9jpRiOPd+FjXAfLe6wa/XWHr+w=="], + "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.1.105", "", { "os": "linux", "cpu": "x64" }, "sha512-kfWS1WMg6qHShmxZX9s1tZc/8JcXw6uyy2UtyTbJdRFExtXGH37oKHi8QK8iPL2ExCx4z7zqVnVJfO3X/Wh7lA=="], + "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.1.105", "", { "os": "win32", "cpu": "arm64" }, "sha512-UFx6A8OpBVbGWK6OAw4GqAqKZgIITJfSOd35pG9yDVKQouHN2OGc2HeeXrH2A4h42p40Xl6IfcqqfllkpC13Dg=="], + "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.1.105", "", { "os": "win32", "cpu": "x64" }, "sha512-f9FqqUmxehwhF+cgyazm0YT0v0BYTTCPzd6eztqhl74N3x/kC+jOOz2rdJDC/tTBo1JVsF64KupOnhIs6/Cogg=="], + "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/bun-ffi-structs": ["bun-ffi-structs@0.1.2", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-Lh1oQAYHDcnesJauieA4UNkWGXY9hYck7OA5IaRwE3Bp6K2F2pJSNYqq+hIy7P3uOvo3km3oxS8304g5gDMl/w=="], + "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=="], - "opentui-spinner/@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.10", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.3" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.10" }, "optionalPeers": ["solid-js"] }, "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ=="], - "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=="], @@ -6929,14 +6632,10 @@ "p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "parse-bmfont-xml/xml2js/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], - "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "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=="], - "protobufjs/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "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=="], @@ -6947,16 +6646,10 @@ "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "sitemap/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "storybook/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "stripe/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "tedious/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "tw-to-css/tailwindcss/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=="], "tw-to-css/tailwindcss/glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], @@ -7259,8 +6952,6 @@ "js-beautify/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "mssql/tedious/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - "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=="], diff --git a/bunfig.toml b/bunfig.toml index 36a21d9332..47c4ac5396 100644 --- a/bunfig.toml +++ b/bunfig.toml @@ -1,6 +1,8 @@ [install] exact = true +# Only install newly resolved package versions published at least 3 days ago. +minimumReleaseAge = 259200 +minimumReleaseAgeExcludes = ["@opentui/core", "@opentui/core-darwin-arm64", "@opentui/core-darwin-x64", "@opentui/core-linux-arm64", "@opentui/core-linux-x64", "@opentui/core-win32-arm64", "@opentui/core-win32-x64", "@opentui/keymap", "@opentui/solid"] [test] root = "./do-not-run-tests-from-root" - diff --git a/infra/console.ts b/infra/console.ts index ab6502a8f8..56befe6268 100644 --- a/infra/console.ts +++ b/infra/console.ts @@ -293,3 +293,13 @@ new sst.cloudflare.x.SolidStart("Console", { }, }, }) + +//////////////// +// HELPERS +//////////////// + +export const stat = new sst.cloudflare.Worker("Stat", { + handler: "packages/console/function/src/stat.ts", + link: [database], + url: true, +}) diff --git a/infra/monitoring.ts b/infra/monitoring.ts index c08d39f262..240e6c97ee 100644 --- a/infra/monitoring.ts +++ b/infra/monitoring.ts @@ -111,6 +111,34 @@ const providerHttpErrorsQuery = (product: "go" | "zen") => { }).json } +const modelLowTpsQuery = (product: "go" | "zen") => { + const filters = [ + { column: "model", op: "exists" }, + { column: "event_type", op: "=", value: "completions" }, + { column: "user_agent", op: "contains", value: "opencode" }, + { column: "isGoTier", op: "=", value: product === "go" ? "true" : "false" }, + { column: "status", op: ">=", value: "200" }, + { column: "status", op: "<", value: "400" }, + { column: "tps.output", op: "exists" }, + ] + + return honeycomb.getQuerySpecificationOutput({ + breakdowns: ["model"], + calculations: [ + { op: "COUNT", name: "TOTAL", filterCombination: "AND", filters }, + { + op: "P50", + name: "TPS", + column: "tps.output", + filterCombination: "AND", + filters, + }, + ], + formulas: [{ name: "LOW_TPS", expression: "IF(GTE($TOTAL, 100), $TPS, 999)" }], + timeRange: 1800, + }).json +} + new honeycomb.Trigger("IncreasedModelHttpErrorsGo", { name: "Increased Model HTTP Errors [Go]", description, @@ -149,6 +177,44 @@ new honeycomb.Trigger("IncreasedModelHttpErrorsZen", { ], }) +new honeycomb.Trigger("LowModelTpsGo", { + name: "Low Model TPS [Go]", + description, + queryJson: modelLowTpsQuery("go"), + alertType: "on_change", + frequency: 600, + thresholds: [{ op: "<=", value: 10, exceededLimit: 1 }], + recipients: [ + { + id: webhookRecipient.id, + notificationDetails: [ + { + variables: [{ name: "type", value: "model_low_tps" }], + }, + ], + }, + ], +}) + +new honeycomb.Trigger("LowModelTpsZen", { + name: "Low Model TPS [Zen]", + description, + queryJson: modelLowTpsQuery("zen"), + alertType: "on_change", + frequency: 600, + thresholds: [{ op: "<=", value: 10, exceededLimit: 1 }], + recipients: [ + { + id: webhookRecipient.id, + notificationDetails: [ + { + variables: [{ name: "type", value: "model_low_tps" }], + }, + ], + }, + ], +}) + new honeycomb.Trigger("IncreasedProviderHttpErrorsGo", { name: "Increased Provider HTTP Errors [Go]", description, diff --git a/nix/hashes.json b/nix/hashes.json index 33003919af..876b969608 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-Q9r1S15YL9LQK7DRhuOpw3Fxi24BPovEM995GZJayKw=", - "aarch64-linux": "sha256-C0rRTLnxxuuEkCBc3JZbkR66TUVwpcPFif3BU9GRAuA=", - "aarch64-darwin": "sha256-1HvalOO/pOkRlYH8CZ93psapt90C+pYzui1JCadBE1Q=", - "x86_64-darwin": "sha256-RrndyLWfhWm4mZ88XytFF2NI+ly8la550Z5LBN/g5u4=" + "x86_64-linux": "sha256-cRhvzZoW6gBbE0sQm1+e+6/WgajuA6MSIL5iroFsfqs=", + "aarch64-linux": "sha256-0knZfxBULqkt5u6sXFx+a/vqw2rc6IC1+LeAd4TNFhM=", + "aarch64-darwin": "sha256-jL4tO+EHSmUF+gQGEaLzAbTxxjkL8OyhTk13vsbomgM=", + "x86_64-darwin": "sha256-bsa7IpS3GaxagcigTa0yqZTkf4e/nbcTQ9aZeb+5eHQ=" } } diff --git a/package.json b/package.json index 6d82864d6d..f1cc7da5c3 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,9 @@ "@types/cross-spawn": "6.0.6", "@octokit/rest": "22.0.0", "@hono/zod-validator": "0.4.2", - "@opentui/core": "0.2.6", - "@opentui/keymap": "0.2.6", - "@opentui/solid": "0.2.6", + "@opentui/core": "0.2.8", + "@opentui/keymap": "0.2.8", + "@opentui/solid": "0.2.8", "ulid": "3.0.1", "@kobalte/core": "0.13.11", "@types/luxon": "3.7.1", @@ -128,6 +128,9 @@ "electron" ], "overrides": { + "@opentui/core": "catalog:", + "@opentui/keymap": "catalog:", + "@opentui/solid": "catalog:", "@types/bun": "catalog:", "@types/node": "catalog:" }, diff --git a/packages/app/package.json b/packages/app/package.json index 9eb4083725..86999ed45a 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -73,7 +73,6 @@ "solid-js": "catalog:", "solid-list": "catalog:", "tailwindcss": "catalog:", - "virtua": "catalog:", - "zod": "catalog:" + "virtua": "catalog:" } } diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index eaeedf087e..1e1be28b59 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -240,13 +240,7 @@ export const PromptInput: Component = (props) => { return paths }) const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined)) - const status = createMemo( - () => - sync.data.session_status[params.id ?? ""] ?? { - type: "idle", - }, - ) - const working = createMemo(() => status()?.type !== "idle") + const working = createMemo(() => sync.data.session_working(params.id ?? "")) const imageAttachments = createMemo(() => prompt.current().filter((part): part is ImageAttachmentPart => part.type === "image"), ) diff --git a/packages/app/src/context/global-sdk.tsx b/packages/app/src/context/global-sdk.tsx index e53d60d5a0..001b90b42e 100644 --- a/packages/app/src/context/global-sdk.tsx +++ b/packages/app/src/context/global-sdk.tsx @@ -3,15 +3,13 @@ import { createSimpleContext } from "@opencode-ai/ui/context" import { createGlobalEmitter } from "@solid-primitives/event-bus" import { makeEventListener } from "@solid-primitives/event-listener" import { batch, onCleanup, onMount } from "solid-js" -import z from "zod" import { createSdkForServer } from "@/utils/server" import { useLanguage } from "./language" import { usePlatform } from "./platform" import { useServer } from "./server" -const abortError = z.object({ - name: z.literal("AbortError"), -}) +const isAbortError = (error: unknown) => + error !== null && typeof error === "object" && "name" in error && error.name === "AbortError" export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleContext({ name: "GlobalSDK", @@ -103,7 +101,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo let streamErrorLogged = false const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) - const aborted = (error: unknown) => abortError.safeParse(error).success + const aborted = isAbortError let attempt: AbortController | undefined let run: Promise | undefined diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts index e8ca597d15..08299b3017 100644 --- a/packages/app/src/context/global-sync/child-store.ts +++ b/packages/app/src/context/global-sync/child-store.ts @@ -208,6 +208,10 @@ export function createChildStoreManager(input: { session: [], sessionTotal: 0, session_status: {}, + session_working(id: string) { + const type = this.session_status[id]?.type + return (type ?? "idle") !== "idle" + }, session_diff: {}, todo: {}, permission: {}, diff --git a/packages/app/src/context/global-sync/types.ts b/packages/app/src/context/global-sync/types.ts index 6bf42a0737..43837ac97f 100644 --- a/packages/app/src/context/global-sync/types.ts +++ b/packages/app/src/context/global-sync/types.ts @@ -46,6 +46,7 @@ export type State = { session_status: { [sessionID: string]: SessionStatus } + session_working(id: string): boolean session_diff: { [sessionID: string]: SnapshotFileDiff[] } diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index f27a9bb7a9..77d9a03d9d 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -166,18 +166,7 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => { }) const isWorking = createMemo(() => { if (hasPermissions()) return false - const pending = (sessionStore.message[props.session.id] ?? []).findLast( - (message) => - message.role === "assistant" && - typeof (message as { time?: { completed?: unknown } }).time?.completed !== "number", - ) - const status = sessionStore.session_status[props.session.id] - return ( - pending !== undefined || - status?.type === "busy" || - status?.type === "retry" || - (status !== undefined && status.type !== "idle") - ) + return sessionStore.session_working(props.session.id) }) const tint = createMemo(() => messageAgentColor(sessionStore.message[props.session.id], sessionStore.agent)) diff --git a/packages/app/src/pages/layout/sidebar-project.tsx b/packages/app/src/pages/layout/sidebar-project.tsx index 58595c25b9..b910dd2098 100644 --- a/packages/app/src/pages/layout/sidebar-project.tsx +++ b/packages/app/src/pages/layout/sidebar-project.tsx @@ -305,7 +305,7 @@ export const SortableProject = (props: { const isWorking = createMemo(() => dirs().some((directory) => { const [store] = globalSync.child(directory, { bootstrap: false }) - return Object.values(store.session_status).some((status) => status?.type === "busy" || status?.type === "retry") + return Object.keys(store.session_status).some((id) => store.session_working(id)) }), ) const projectSessions = createMemo(() => sortedRootSessions(projectStore(), props.sortNow())) diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 1345e355eb..1e73ed590f 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -1496,12 +1496,7 @@ export default function Page() { return out }) - const busy = (sessionID: string) => { - if ((sync.data.session_status[sessionID] ?? { type: "idle" as const }).type !== "idle") return true - return (sync.data.message[sessionID] ?? []).some( - (item) => item.role === "assistant" && typeof item.time.completed !== "number", - ) - } + const busy = (sessionID: string) => sync.data.session_working(sessionID) const queuedFollowups = createMemo(() => { const id = params.id diff --git a/packages/app/src/pages/session/composer/session-composer-state.ts b/packages/app/src/pages/session/composer/session-composer-state.ts index 525766dcfa..a7213c4a7d 100644 --- a/packages/app/src/pages/session/composer/session-composer-state.ts +++ b/packages/app/src/pages/session/composer/session-composer-state.ts @@ -57,14 +57,7 @@ export function createSessionComposerState(options?: { closeMs?: number | (() => () => todos().length > 0 && todos().every((todo) => todo.status === "completed" || todo.status === "cancelled"), ) - const status = createMemo(() => { - const id = params.id - if (!id) return idle - return sync.data.session_status[id] ?? idle - }) - - const busy = createMemo(() => status().type !== "idle") - const live = createMemo(() => busy() || blocked()) + const live = createMemo(() => sync.data.session_working(params.id ?? "") || blocked()) const [store, setStore] = createStore({ responding: undefined as string | undefined, diff --git a/packages/app/src/pages/session/review-tab.tsx b/packages/app/src/pages/session/review-tab.tsx index 5719fce318..92288c63b0 100644 --- a/packages/app/src/pages/session/review-tab.tsx +++ b/packages/app/src/pages/session/review-tab.tsx @@ -32,7 +32,7 @@ export interface SessionReviewTabProps { focusedComment?: { file: string; id: string } | null onFocusedCommentChange?: (focus: { file: string; id: string } | null) => void focusedFile?: string - onScrollRef?: (el: HTMLDivElement) => void + onScrollRef?: (el: HTMLDivElement | undefined) => void commentMentions?: { items: (query: string) => string[] | Promise } @@ -126,6 +126,7 @@ export function SessionReviewTab(props: SessionReviewTabProps) { onCleanup(() => { if (restoreFrame !== undefined) cancelAnimationFrame(restoreFrame) + props.onScrollRef?.(undefined) }) return ( diff --git a/packages/app/src/pages/session/session-side-panel.tsx b/packages/app/src/pages/session/session-side-panel.tsx index 66f5269bf9..9a745891a3 100644 --- a/packages/app/src/pages/session/session-side-panel.tsx +++ b/packages/app/src/pages/session/session-side-panel.tsx @@ -221,239 +221,241 @@ export function SessionSidePanel(props: { }} style={{ width: panelWidth() }} > -
-
-
- - - - -
- { - const stop = createFileTabListSync({ el, contextOpen }) - onCleanup(stop) - }} - > - - -
-
{language.t("session.tab.review")}
- -
{props.reviewCount()}
-
-
-
-
- - - tabs().close("context")} - aria-label={language.t("common.closeTab")} - /> - - } - hideCloseButton - onMiddleClick={() => tabs().close("context")} - > -
- -
{language.t("session.tab.context")}
-
-
-
- - {(tab) => } - -
- - { - void import("@/components/dialog-select-file").then((x) => { - dialog.show(() => ) - }) - }} - aria-label={language.t("command.file.open")} - /> - -
-
-
- - - - {props.reviewPanel()} - - - - - -
-
- -
- {language.t("session.files.selectToOpen")} -
-
-
-
-
- - - - -
- -
-
-
-
- - - {(tab) => } - -
- - - {(tab) => { - const path = file.pathFromTab(tab) - return ( -
- {(p) => } -
- ) - }} -
-
-
-
-
- - + +
-
- + - - - {props.reviewCount()}{" "} - {language.t( - props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other", - )} - - - {language.t("session.files.all")} - - - - - - - {language.t("common.loading")} - {language.t("common.loading.ellipsis")} + + + +
+ { + const stop = createFileTabListSync({ el, contextOpen }) + onCleanup(stop) + }} + > + + +
+
{language.t("session.tab.review")}
+ +
{props.reviewCount()}
+
- } - > +
+
+ + + tabs().close("context")} + aria-label={language.t("common.closeTab")} + /> + + } + hideCloseButton + onMiddleClick={() => tabs().close("context")} + > +
+ +
{language.t("session.tab.context")}
+
+
+
+ + {(tab) => } + +
+ + { + void import("@/components/dialog-select-file").then((x) => { + dialog.show(() => ) + }) + }} + aria-label={language.t("command.file.open")} + /> + +
+
+
+ + + + {props.reviewPanel()} + + + + + +
+
+ +
+ {language.t("session.files.selectToOpen")} +
+
+
+
+
+ + + + +
+ +
+
+
+
+ + + {(tab) => } + +
+ + + {(tab) => { + const path = file.pathFromTab(tab) + return ( +
+ {(p) => } +
+ ) + }} +
+
+
+
+
+ + +
+
+ + + + {props.reviewCount()}{" "} + {language.t( + props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other", + )} + + + {language.t("session.files.all")} + + + + + + + {language.t("common.loading")} + {language.t("common.loading.ellipsis")} +
+ } + > + props.focusReviewDiff(node.path)} + /> + + + + + + + {empty(language.t("session.files.empty"))} + props.focusReviewDiff(node.path)} + onFileClick={(node) => openTab(file.tab(node.path))} /> - - - - - - - {empty(language.t("session.files.empty"))} - - openTab(file.tab(node.path))} - /> - - - - -
- -
props.size.start()}> - { - props.size.touch() - layout.fileTree.resize(width) - }} - /> + + + +
-
-
-
-
+ +
props.size.start()}> + { + props.size.touch() + layout.fileTree.resize(width) + }} + /> +
+
+ + + + ) diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx index 922299bec1..b45d110b94 100644 --- a/packages/app/src/pages/session/use-session-commands.tsx +++ b/packages/app/src/pages/session/use-session-commands.tsx @@ -75,8 +75,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => { import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" || settings.general.showFileTree() - const idle = { type: "idle" as const } - const status = () => sync.data.session_status[params.id ?? ""] ?? idle const messages = () => { const id = params.id if (!id) return [] @@ -290,7 +288,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => { const sessionID = params.id if (!sessionID) return - if (status().type !== "idle") { + if (sync.data.session_working(params.id ?? "")) { await sdk.client.session.abort({ sessionID }).catch(() => {}) } diff --git a/packages/app/src/utils/id.ts b/packages/app/src/utils/id.ts index fa27cf4c5f..dba7a8d951 100644 --- a/packages/app/src/utils/id.ts +++ b/packages/app/src/utils/id.ts @@ -1,5 +1,3 @@ -import z from "zod" - const prefixes = { session: "ses", message: "msg", @@ -15,10 +13,6 @@ let counter = 0 type Prefix = keyof typeof prefixes export namespace Identifier { - export function schema(prefix: Prefix) { - return z.string().startsWith(prefixes[prefix]) - } - export function ascending(prefix: Prefix, given?: string) { return generateID(prefix, false, given) } diff --git a/packages/app/src/utils/server-errors.test.ts b/packages/app/src/utils/server-errors.test.ts index 1f53bb8cf6..84f7c07d60 100644 --- a/packages/app/src/utils/server-errors.test.ts +++ b/packages/app/src/utils/server-errors.test.ts @@ -128,4 +128,17 @@ describe("formatServerError", () => { ["Modelo nao encontrado: x/y", "Voce quis dizer: x/y2, x/y3", "Revise provider/model no config"].join("\n"), ) }) + + test("unwraps SDK-wrapped errors from cause.body", () => { + const body = { + name: "ConfigInvalidError", + data: { + message: "Missing host", + }, + } satisfies ConfigInvalidError + + const wrapped = new Error("ConfigInvalidError", { cause: { body, status: 400 } }) + + expect(formatServerError(wrapped, language.t)).toBe("Arquivo de config em config invalido: Missing host") + }) }) diff --git a/packages/app/src/utils/server-errors.ts b/packages/app/src/utils/server-errors.ts index 2c3a8c54db..8a8db17811 100644 --- a/packages/app/src/utils/server-errors.ts +++ b/packages/app/src/utils/server-errors.ts @@ -26,14 +26,22 @@ function tr(translator: Translator | undefined, key: string, text: string, vars? } export function formatServerError(error: unknown, translate?: Translator, fallback?: string) { - if (isConfigInvalidErrorLike(error)) return parseReadableConfigInvalidError(error, translate) - if (isProviderModelNotFoundErrorLike(error)) return parseReadableProviderModelNotFoundError(error, translate) + const unwrapped = unwrapNamedError(error) + if (isConfigInvalidErrorLike(unwrapped)) return parseReadableConfigInvalidError(unwrapped, translate) + if (isProviderModelNotFoundErrorLike(unwrapped)) return parseReadableProviderModelNotFoundError(unwrapped, translate) if (error instanceof Error && error.message) return error.message if (typeof error === "string" && error) return error if (fallback) return fallback return tr(translate, "error.chain.unknown", "Unknown error") } +function unwrapNamedError(error: unknown): unknown { + if (error instanceof Error && error.cause && typeof error.cause === "object" && "body" in error.cause) { + return (error.cause as Record).body + } + return error +} + function isConfigInvalidErrorLike(error: unknown): error is ConfigInvalidError { if (typeof error !== "object" || error === null) return false const o = error as Record diff --git a/packages/console/app/src/routes/honeycomb/webhook.ts b/packages/console/app/src/routes/honeycomb/webhook.ts index 367a93aeb0..05be683535 100644 --- a/packages/console/app/src/routes/honeycomb/webhook.ts +++ b/packages/console/app/src/routes/honeycomb/webhook.ts @@ -12,13 +12,22 @@ const basePayload = z.object({ url: z.string(), }) -const groups = z.object({ group: z.object({ key: z.string(), value: z.string() }).array() }).array() +const groups = z + .object({ + result: z.union([z.number(), z.string()]).nullish(), + group: z.object({ key: z.string(), value: z.string() }).array(), + }) + .array() const honeycombWebhookPayload = z.discriminatedUnion("type", [ basePayload.extend({ type: z.literal("model_http_errors"), groups, }), + basePayload.extend({ + type: z.literal("model_low_tps"), + groups, + }), basePayload.extend({ type: z.literal("provider_http_errors"), groups, @@ -29,14 +38,25 @@ const honeycombWebhookPayload = z.discriminatedUnion("type", [ ]) const postDiscordMessage = async (payload: z.infer) => { - const group = - payload.type === "model_http_errors" ? "model" : payload.type === "provider_http_errors" ? "provider" : undefined - const names = payload.type === "custom" ? [] : payload.groups.flatMap((item) => item.group.map((g) => g.value)) + const names = + payload.type === "custom" + ? [] + : payload.groups.flatMap((item) => + item.group.map((g) => { + const result = item.result == null ? undefined : Number(item.result) + return `- ${g.value}${ + result !== undefined && Number.isFinite(result) + ? payload.type === "model_low_tps" + ? ` (${Math.round(result)} TPS)` + : ` (${Math.round(result * 100)}% errors)` + : "" + }` + }), + ) const content = [ `[**${payload.isTest ? "[TEST] " : ""}${payload.name ?? "Honeycomb alert"}**](${payload.url})`, - group && names.length > 0 ? `Affected ${group}s:` : undefined, - ...names.map((name) => `- ${name}`), + ...names, "", `<@&${DISCORD_ALERT_ROLE_ID}>`, ] diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 2e46df0366..d9e5641690 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -123,7 +123,7 @@ export async function handler( ? createIpRateLimiter(modelInfo.id, modelInfo.rateLimit, ip, input.request) : createKeyRateLimiter(modelInfo.id, modelInfo.rateLimit, zenApiKey, input.request) await rateLimiter?.check() - const stickyTracker = createStickyTracker(modelInfo.stickyProvider, sessionId) + const stickyTracker = createStickyTracker(modelInfo.id, modelInfo.stickyProvider, sessionId) const stickyProvider = await stickyTracker?.get() const authInfo = await authenticate(modelInfo, zenApiKey) const billingSource = validateBilling(authInfo, modelInfo) @@ -238,7 +238,7 @@ export async function handler( dataDumper?.provideRequest(reqBody) // Store sticky provider - await stickyTracker?.set(providerInfo.id) + if (res.status === 200) await stickyTracker?.set(providerInfo.id) // Temporarily change 404 to 400 status code b/c solid start automatically override 404 response const resStatus = res.status === 404 ? 400 : res.status @@ -299,7 +299,6 @@ export async function handler( let buffer = "" let responseLength = 0 let timestampFirstByte = 0 - let timestampLastByte = 0 function pump(): Promise { return ( @@ -321,6 +320,7 @@ export async function handler( await modelTpsLimiter?.track( providerInfo.id, providerInfo.model, + providerInfo.tpsGoal, timestampFirstByte, timestampLastByte, usageInfo, @@ -526,7 +526,7 @@ export async function handler( }) .filter((provider) => { if (!provider.tpsGoal) return true - const isLowTps = modelTpsLimits?.[`${provider.id}/${provider.model}`] ?? false + const isLowTps = modelTpsLimits?.[`${provider.id}/${provider.model}/${provider.tpsGoal}`] ?? false return !isLowTps }) .map((provider) => { diff --git a/packages/console/app/src/routes/zen/util/modelTpsLimiter.ts b/packages/console/app/src/routes/zen/util/modelTpsLimiter.ts index 428272eecd..477d08ce68 100644 --- a/packages/console/app/src/routes/zen/util/modelTpsLimiter.ts +++ b/packages/console/app/src/routes/zen/util/modelTpsLimiter.ts @@ -5,7 +5,7 @@ import { UsageInfo } from "./provider/provider" export function createModelTpsLimiter(providers: { id: string; model: string; tpsGoal?: number }[]) { const tpsGoals = Object.fromEntries( providers.flatMap((p) => { - return p.tpsGoal ? [[`${p.id}/${p.model}`, p.tpsGoal]] : [] + return p.tpsGoal ? [[`${p.id}/${p.model}/${p.tpsGoal}`, p.tpsGoal]] : [] }), ) const ids = Object.keys(tpsGoals) @@ -56,11 +56,17 @@ export function createModelTpsLimiter(providers: { id: string; model: string; tp }), ) }, - track: async (provider: string, model: string, tsFirstByte: number, tsLastByte: number, usageInfo: UsageInfo) => { - const id = `${provider}/${model}` - if (!ids.includes(id)) return - const tpsGoal = tpsGoals[id] + track: async ( + provider: string, + model: string, + tpsGoal: number | undefined, + tsFirstByte: number, + tsLastByte: number, + usageInfo: UsageInfo, + ) => { if (!tpsGoal) return + const id = `${provider}/${model}/${tpsGoal}` + if (!ids.includes(id)) return if (tsFirstByte <= 0 || tsLastByte <= 0) return const tokens = usageInfo.outputTokens if (tokens <= 10) return diff --git a/packages/console/app/src/routes/zen/util/stickyProviderTracker.ts b/packages/console/app/src/routes/zen/util/stickyProviderTracker.ts index 8029757c5b..fae0cdf03c 100644 --- a/packages/console/app/src/routes/zen/util/stickyProviderTracker.ts +++ b/packages/console/app/src/routes/zen/util/stickyProviderTracker.ts @@ -1,16 +1,42 @@ -import { Resource } from "@opencode-ai/console-resource" +import { Database, eq } from "@opencode-ai/console-core/drizzle/index.js" +import { ModelStickyProviderTable } from "@opencode-ai/console-core/schema/ip.sql.js" -export function createStickyTracker(stickyProvider: "strict" | "prefer" | undefined, session: string) { +export function createStickyTracker(modelId: string, stickyProvider: "strict" | "prefer" | undefined, session: string) { if (!stickyProvider) return if (!session) return - const key = `sticky:${session}` + const id = `${modelId}/${session}` + let _providerId: string | undefined return { get: async () => { - return await Resource.GatewayKv.get(key) + const data = await Database.use((tx) => + tx + .select({ + providerId: ModelStickyProviderTable.providerId, + }) + .from(ModelStickyProviderTable) + .where(eq(ModelStickyProviderTable.id, id)) + .limit(1), + ) + _providerId = data[0]?.providerId + return _providerId }, set: async (providerId: string) => { - await Resource.GatewayKv.put(key, providerId, { expirationTtl: 86400 }) + if (_providerId === providerId) return + + await Database.use((tx) => + tx + .insert(ModelStickyProviderTable) + .values({ + id, + providerId, + }) + .onDuplicateKeyUpdate({ + set: { + providerId, + }, + }), + ) }, } } diff --git a/packages/console/core/migrations/20260513163955_tearful_whistler/migration.sql b/packages/console/core/migrations/20260513163955_tearful_whistler/migration.sql new file mode 100644 index 0000000000..a2bcc164ca --- /dev/null +++ b/packages/console/core/migrations/20260513163955_tearful_whistler/migration.sql @@ -0,0 +1,7 @@ +CREATE TABLE `model_sticky_provider` ( + `id` varchar(255) PRIMARY KEY, + `time_created` timestamp(3) NOT NULL DEFAULT (now()), + `time_updated` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + `time_deleted` timestamp(3), + `provider_id` varchar(255) NOT NULL +); diff --git a/packages/console/core/migrations/20260513163955_tearful_whistler/snapshot.json b/packages/console/core/migrations/20260513163955_tearful_whistler/snapshot.json new file mode 100644 index 0000000000..b791735228 --- /dev/null +++ b/packages/console/core/migrations/20260513163955_tearful_whistler/snapshot.json @@ -0,0 +1,2765 @@ +{ + "version": "6", + "dialect": "mysql", + "id": "1f04bd59-35b0-493b-9d55-cfa08207ba8e", + "prevIds": ["c742e0f2-5d89-4216-b843-059d00680f13"], + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "name": "auth", + "entityType": "tables" + }, + { + "name": "benchmark", + "entityType": "tables" + }, + { + "name": "billing", + "entityType": "tables" + }, + { + "name": "coupon", + "entityType": "tables" + }, + { + "name": "lite", + "entityType": "tables" + }, + { + "name": "payment", + "entityType": "tables" + }, + { + "name": "subscription", + "entityType": "tables" + }, + { + "name": "usage", + "entityType": "tables" + }, + { + "name": "ip_rate_limit", + "entityType": "tables" + }, + { + "name": "ip", + "entityType": "tables" + }, + { + "name": "key_rate_limit", + "entityType": "tables" + }, + { + "name": "model_sticky_provider", + "entityType": "tables" + }, + { + "name": "model_tpm_rate_limit", + "entityType": "tables" + }, + { + "name": "model_tps_rate_limit", + "entityType": "tables" + }, + { + "name": "key", + "entityType": "tables" + }, + { + "name": "model", + "entityType": "tables" + }, + { + "name": "provider", + "entityType": "tables" + }, + { + "name": "user", + "entityType": "tables" + }, + { + "name": "workspace", + "entityType": "tables" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "account" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "account" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "auth" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "auth" + }, + { + "type": "enum('email','github','google')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subject", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "entityType": "columns", + "table": "auth" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "agent", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "mediumtext", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "result", + "entityType": "columns", + "table": "benchmark" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(32)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_type", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(4)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_method_last4", + "entityType": "columns", + "table": "billing" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "balance", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "entityType": "columns", + "table": "billing" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "entityType": "columns", + "table": "billing" + }, + { + "type": "boolean", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_trigger", + "entityType": "columns", + "table": "billing" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_amount", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reload_error", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_error", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_reload_locked_till", + "entityType": "columns", + "table": "billing" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "enum('20','100','200')", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "subscription_plan", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_booked", + "entityType": "columns", + "table": "billing" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_subscription_selected", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(28)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "lite_subscription_id", + "entityType": "columns", + "table": "billing" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "lite", + "entityType": "columns", + "table": "billing" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "coupon" + }, + { + "type": "enum('BUILDATHON','GOFREEMONTH','GO3MONTHS100','GO6MONTHS100','GO12MONTHS100')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "coupon" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_redeemed", + "entityType": "columns", + "table": "coupon" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "lite" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "lite" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "lite" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "entityType": "columns", + "table": "lite" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "weekly_usage", + "entityType": "columns", + "table": "lite" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_weekly_updated", + "entityType": "columns", + "table": "lite" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_updated", + "entityType": "columns", + "table": "lite" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "customer_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "invoice_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "payment_id", + "entityType": "columns", + "table": "payment" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "amount", + "entityType": "columns", + "table": "payment" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_refunded", + "entityType": "columns", + "table": "payment" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "entityType": "columns", + "table": "payment" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "rolling_usage", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "fixed_usage", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_rolling_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_fixed_updated", + "entityType": "columns", + "table": "subscription" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "usage" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "input_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "output_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "reasoning_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_read_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_5m_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cache_write_1h_tokens", + "entityType": "columns", + "table": "usage" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "cost", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "session_id", + "entityType": "columns", + "table": "usage" + }, + { + "type": "json", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "enrichment", + "entityType": "columns", + "table": "usage" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "varchar(10)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "entityType": "columns", + "table": "ip_rate_limit" + }, + { + "type": "varchar(45)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "ip", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "ip" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "ip" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "usage", + "entityType": "columns", + "table": "ip" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "entityType": "columns", + "table": "key_rate_limit" + }, + { + "type": "varchar(40)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "entityType": "columns", + "table": "key_rate_limit" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "entityType": "columns", + "table": "key_rate_limit" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "model_sticky_provider" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "model_sticky_provider" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "model_sticky_provider" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "model_sticky_provider" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider_id", + "entityType": "columns", + "table": "model_sticky_provider" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "model_tpm_rate_limit" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "entityType": "columns", + "table": "model_tpm_rate_limit" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "count", + "entityType": "columns", + "table": "model_tpm_rate_limit" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "model_tps_rate_limit" + }, + { + "type": "bigint", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "interval", + "entityType": "columns", + "table": "model_tps_rate_limit" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "qualify", + "entityType": "columns", + "table": "model_tps_rate_limit" + }, + { + "type": "int", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "unqualify", + "entityType": "columns", + "table": "model_tps_rate_limit" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "key", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "key" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_used", + "entityType": "columns", + "table": "key" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "model" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "model", + "entityType": "columns", + "table": "model" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "provider" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(64)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "provider", + "entityType": "columns", + "table": "provider" + }, + { + "type": "text", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "credentials", + "entityType": "columns", + "table": "provider" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "workspace_id", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "account_id", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_seen", + "entityType": "columns", + "table": "user" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "color", + "entityType": "columns", + "table": "user" + }, + { + "type": "enum('admin','member')", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "role", + "entityType": "columns", + "table": "user" + }, + { + "type": "int", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_limit", + "entityType": "columns", + "table": "user" + }, + { + "type": "bigint", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "monthly_usage", + "entityType": "columns", + "table": "user" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_monthly_usage_updated", + "entityType": "columns", + "table": "user" + }, + { + "type": "varchar(30)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "varchar(255)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "slug", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "varchar(255)", + "notNull": true, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(now())", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": true, + "autoIncrement": false, + "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))", + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "workspace" + }, + { + "type": "timestamp(3)", + "notNull": false, + "autoIncrement": false, + "default": null, + "onUpdateNow": false, + "onUpdateNowFsp": null, + "charSet": null, + "collation": null, + "generated": null, + "name": "time_deleted", + "entityType": "columns", + "table": "workspace" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "account", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "auth", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "benchmark", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "billing", + "entityType": "pks" + }, + { + "columns": ["email", "type"], + "name": "PRIMARY", + "table": "coupon", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "lite", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "payment", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "subscription", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "usage", + "entityType": "pks" + }, + { + "columns": ["ip", "interval"], + "name": "PRIMARY", + "table": "ip_rate_limit", + "entityType": "pks" + }, + { + "columns": ["ip"], + "name": "PRIMARY", + "table": "ip", + "entityType": "pks" + }, + { + "columns": ["key", "interval"], + "name": "PRIMARY", + "table": "key_rate_limit", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "model_sticky_provider", + "entityType": "pks" + }, + { + "columns": ["id", "interval"], + "name": "PRIMARY", + "table": "model_tpm_rate_limit", + "entityType": "pks" + }, + { + "columns": ["id", "interval"], + "name": "PRIMARY", + "table": "model_tps_rate_limit", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "key", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "model", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "provider", + "entityType": "pks" + }, + { + "columns": ["workspace_id", "id"], + "name": "PRIMARY", + "table": "user", + "entityType": "pks" + }, + { + "columns": ["id"], + "name": "PRIMARY", + "table": "workspace", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "provider", + "isExpression": false + }, + { + "value": "subject", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "provider", + "entityType": "indexes", + "table": "auth" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "account_id", + "entityType": "indexes", + "table": "auth" + }, + { + "columns": [ + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "time_created", + "entityType": "indexes", + "table": "benchmark" + }, + { + "columns": [ + { + "value": "customer_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_customer_id", + "entityType": "indexes", + "table": "billing" + }, + { + "columns": [ + { + "value": "subscription_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_subscription_id", + "entityType": "indexes", + "table": "billing" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "entityType": "indexes", + "table": "lite" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_user_id", + "entityType": "indexes", + "table": "subscription" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "time_created", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "usage_time_created", + "entityType": "indexes", + "table": "usage" + }, + { + "columns": [ + { + "value": "key", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_key", + "entityType": "indexes", + "table": "key" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "model", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "model_workspace_model", + "entityType": "indexes", + "table": "model" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "provider", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "workspace_provider", + "entityType": "indexes", + "table": "provider" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_account_id", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "workspace_id", + "isExpression": false + }, + { + "value": "email", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "user_email", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "account_id", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_account_id", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "global_email", + "entityType": "indexes", + "table": "user" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "using": null, + "algorithm": null, + "lock": null, + "nameExplicit": true, + "name": "slug", + "entityType": "indexes", + "table": "workspace" + } + ], + "renames": [] +} diff --git a/packages/console/core/src/schema/ip.sql.ts b/packages/console/core/src/schema/ip.sql.ts index 975dcfa186..a80fa474ca 100644 --- a/packages/console/core/src/schema/ip.sql.ts +++ b/packages/console/core/src/schema/ip.sql.ts @@ -51,3 +51,13 @@ export const ModelTpsRateLimitTable = mysqlTable( }, (table) => [primaryKey({ columns: [table.id, table.interval] })], ) + +export const ModelStickyProviderTable = mysqlTable( + "model_sticky_provider", + { + id: varchar("id", { length: 255 }).notNull(), + ...timestamps, + providerId: varchar("provider_id", { length: 255 }).notNull(), + }, + (table) => [primaryKey({ columns: [table.id] })], +) diff --git a/packages/console/core/sst-env.d.ts b/packages/console/core/sst-env.d.ts index 9680a53aab..088db5be2c 100644 --- a/packages/console/core/sst-env.d.ts +++ b/packages/console/core/sst-env.d.ts @@ -298,6 +298,7 @@ declare module "sst" { "EnterpriseStorage": cloudflare.R2Bucket "GatewayKv": cloudflare.KVNamespace "LogProcessor": cloudflare.Service + "Stat": cloudflare.Service "ZenData": cloudflare.R2Bucket "ZenDataNew": cloudflare.R2Bucket } diff --git a/packages/console/function/src/stat.ts b/packages/console/function/src/stat.ts new file mode 100644 index 0000000000..54d38bc311 --- /dev/null +++ b/packages/console/function/src/stat.ts @@ -0,0 +1,43 @@ +import { and, Database, inArray } from "@opencode-ai/console-core/drizzle/index.js" +import { ModelTpsRateLimitTable } from "@opencode-ai/console-core/schema/ip.sql.js" + +type Result = Record> + +export default { + async fetch(request: Request) { + if (request.method !== "POST") return new Response("Method Not Allowed", { status: 405 }) + + const body = (await request.json()) as { ids: string[] } + const ids = body.ids + + if (ids.length === 0) return Response.json({} satisfies Result) + + const toInterval = (date: Date) => + parseInt( + date + .toISOString() + .replace(/[^0-9]/g, "") + .substring(0, 12), + ) + const now = Date.now() + const intervals = Array.from({ length: 30 }, (_, i) => toInterval(new Date(now - i * 60 * 1000))) + + const rows = await Database.use((tx) => + tx + .select() + .from(ModelTpsRateLimitTable) + .where(and(inArray(ModelTpsRateLimitTable.id, body.ids), inArray(ModelTpsRateLimitTable.interval, intervals))), + ) + + const result: Result = Object.fromEntries( + body.ids.map((id) => [ + id, + Object.fromEntries(intervals.map((interval) => [interval, { qualify: 0, unqualify: 0 }])), + ]), + ) + for (const row of rows) { + result[row.id][row.interval] = { qualify: row.qualify, unqualify: row.unqualify } + } + return Response.json(result) + }, +} diff --git a/packages/console/function/sst-env.d.ts b/packages/console/function/sst-env.d.ts index 9680a53aab..088db5be2c 100644 --- a/packages/console/function/sst-env.d.ts +++ b/packages/console/function/sst-env.d.ts @@ -298,6 +298,7 @@ declare module "sst" { "EnterpriseStorage": cloudflare.R2Bucket "GatewayKv": cloudflare.KVNamespace "LogProcessor": cloudflare.Service + "Stat": cloudflare.Service "ZenData": cloudflare.R2Bucket "ZenDataNew": cloudflare.R2Bucket } diff --git a/packages/console/resource/sst-env.d.ts b/packages/console/resource/sst-env.d.ts index 9680a53aab..088db5be2c 100644 --- a/packages/console/resource/sst-env.d.ts +++ b/packages/console/resource/sst-env.d.ts @@ -298,6 +298,7 @@ declare module "sst" { "EnterpriseStorage": cloudflare.R2Bucket "GatewayKv": cloudflare.KVNamespace "LogProcessor": cloudflare.Service + "Stat": cloudflare.Service "ZenData": cloudflare.R2Bucket "ZenDataNew": cloudflare.R2Bucket } diff --git a/packages/core/package.json b/packages/core/package.json index e2ffa31d8d..4c47fea8b9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -26,6 +26,27 @@ "@types/semver": "catalog:" }, "dependencies": { + "@ai-sdk/alibaba": "1.0.17", + "@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/cohere": "3.0.27", + "@ai-sdk/deepinfra": "2.0.41", + "@ai-sdk/gateway": "3.0.104", + "@ai-sdk/google": "3.0.63", + "@ai-sdk/google-vertex": "4.0.112", + "@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/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", + "@aws-sdk/credential-providers": "3.993.0", "@effect/opentelemetry": "catalog:", "@effect/platform-node": "catalog:", "@npmcli/arborist": "9.4.0", @@ -34,13 +55,19 @@ "@opentelemetry/context-async-hooks": "2.6.1", "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", - "effect": "catalog:", + "@openrouter/ai-sdk-provider": "2.8.1", + "ai-gateway-provider": "3.1.2", "cross-spawn": "catalog:", + "effect": "catalog:", + "gitlab-ai-provider": "6.6.0", "glob": "13.0.5", + "google-auth-library": "10.5.0", + "immer": "11.1.4", "mime-types": "3.0.2", "minimatch": "10.2.5", "npm-package-arg": "13.0.2", "semver": "^7.6.3", + "venice-ai-sdk-provider": "2.0.1", "xdg-basedir": "5.1.0", "zod": "catalog:" }, diff --git a/packages/core/src/aisdk.ts b/packages/core/src/aisdk.ts new file mode 100644 index 0000000000..5fa2294309 --- /dev/null +++ b/packages/core/src/aisdk.ts @@ -0,0 +1,172 @@ +export * as AISDK from "./aisdk" + +import type { LanguageModelV3 } from "@ai-sdk/provider" +import { Cause, Context, Effect, Layer, Schema } from "effect" +import { ModelV2 } from "./model" +import { PluginV2 } from "./plugin" +import { ProviderV2 } from "./provider" + +type SDK = any + +function wrapSSE(res: Response, ms: number, ctl: AbortController) { + if (typeof ms !== "number" || ms <= 0) return res + if (!res.body) return res + if (!res.headers.get("content-type")?.includes("text/event-stream")) return res + + const reader = res.body.getReader() + const body = new ReadableStream({ + async pull(ctrl) { + const part = await new Promise>>((resolve, reject) => { + const id = setTimeout(() => { + const err = new Error("SSE read timed out") + ctl.abort(err) + void reader.cancel(err) + reject(err) + }, ms) + + reader.read().then( + (part) => { + clearTimeout(id) + resolve(part) + }, + (err) => { + clearTimeout(id) + reject(err) + }, + ) + }) + + if (part.done) { + ctrl.close() + return + } + + ctrl.enqueue(part.value) + }, + async cancel(reason) { + ctl.abort(reason) + await reader.cancel(reason) + }, + }) + + return new Response(body, { + headers: new Headers(res.headers), + status: res.status, + statusText: res.statusText, + }) +} + +function prepareOptions(model: ModelV2.Info, pkg: string) { + const options: Record = { name: model.providerID, ...model.options.aisdk.provider } + if (model.endpoint.type === "aisdk" && model.endpoint.url) options.baseURL = model.endpoint.url + + const customFetch = options.fetch + const chunkTimeout = options.chunkTimeout + delete options.chunkTimeout + options.fetch = async (input: Parameters[0], init?: RequestInit) => { + const opts = { ...(init ?? {}) } + const signals = [ + opts.signal, + typeof chunkTimeout === "number" && chunkTimeout > 0 ? new AbortController() : undefined, + options.timeout !== undefined && options.timeout !== null && options.timeout !== false + ? AbortSignal.timeout(options.timeout) + : undefined, + ].filter((item): item is AbortSignal | AbortController => Boolean(item)) + const chunkAbortCtl = signals.find((item): item is AbortController => item instanceof AbortController) + const abortSignals = signals.map((item) => (item instanceof AbortController ? item.signal : item)) + if (abortSignals.length === 1) opts.signal = abortSignals[0] + if (abortSignals.length > 1) opts.signal = AbortSignal.any(abortSignals) + + if ((pkg === "@ai-sdk/openai" || pkg === "@ai-sdk/azure") && opts.body && opts.method === "POST") { + const body = JSON.parse(opts.body as string) + if (body.store !== true && Array.isArray(body.input)) { + for (const item of body.input) { + if ("id" in item) delete item.id + } + opts.body = JSON.stringify(body) + } + } + + const res = await (typeof customFetch === "function" ? customFetch : fetch)(input, { + ...opts, + timeout: false, + }) + if (!chunkAbortCtl || typeof chunkTimeout !== "number") return res + return wrapSSE(res, chunkTimeout, chunkAbortCtl) + } + + return options +} + +export class InitError extends Schema.TaggedErrorClass()("AISDK.InitError", { + providerID: ProviderV2.ID, + cause: Schema.Defect, +}) {} + +function initError(providerID: ProviderV2.ID) { + return Effect.catchCause((cause) => Effect.fail(new InitError({ providerID, cause: Cause.squash(cause) }))) +} + +export interface Interface { + readonly language: (model: ModelV2.Info) => Effect.Effect +} + +export class Service extends Context.Service()("@opencode/v2/AISDK") {} + +export const layer = Layer.effect( + Service, + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const languages = new Map() + const sdks = new Map() + + return Service.of({ + language: Effect.fn("AISDK.language")(function* (model) { + const key = `${model.providerID}/${model.id}/${model.options.variant ?? "default"}` + const existing = languages.get(key) + if (existing) return existing + if (model.endpoint.type !== "aisdk") + return yield* new InitError({ + providerID: model.providerID, + cause: new Error(`Unsupported endpoint ${model.endpoint.type}`), + }) + + const options = prepareOptions(model, model.endpoint.package) + const sdkKey = JSON.stringify({ + providerID: model.providerID, + endpoint: model.endpoint, + options, + }) + const sdk = + sdks.get(sdkKey) ?? + (yield* plugin + .trigger("aisdk.sdk", { model, package: model.endpoint.package, options }, {}) + .pipe(initError(model.providerID))).sdk + if (!sdk) + return yield* new InitError({ + providerID: model.providerID, + cause: new Error("No AISDK provider plugin returned an SDK"), + }) + sdks.set(sdkKey, sdk) + const result = yield* plugin + .trigger( + "aisdk.language", + { + model, + sdk, + options, + }, + {}, + ) + .pipe(initError(model.providerID)) + const language = yield* Effect.sync(() => result.language ?? sdk.languageModel(model.apiID)).pipe( + initError(model.providerID), + ) + languages.set(key, language) + return language + }), + }) + }), +) + +export const defaultLayer = layer.pipe(Layer.provide(PluginV2.defaultLayer)) diff --git a/packages/opencode/src/v2/auth.ts b/packages/core/src/auth.ts similarity index 86% rename from packages/opencode/src/v2/auth.ts rename to packages/core/src/auth.ts index 0ac6223a66..843c9504b4 100644 --- a/packages/opencode/src/v2/auth.ts +++ b/packages/core/src/auth.ts @@ -1,9 +1,9 @@ import path from "path" import { Effect, Layer, Option, Schema, Context, SynchronizedRef } from "effect" -import { Identifier } from "@opencode-ai/core/util/identifier" -import { NonNegativeInt, withStatics } from "@opencode-ai/core/schema" -import { Global } from "@opencode-ai/core/global" -import { AppFileSystem } from "@opencode-ai/core/filesystem" +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" @@ -106,27 +106,45 @@ export const layer = Layer.effect( 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 load: () => Effect.Effect = Effect.fnUntraced(function* () { - if (process.env.OPENCODE_AUTH_CONTENT) { - try { - return JSON.parse(process.env.OPENCODE_AUTH_CONTENT) - } catch {} - } - - const raw = yield* fsys.readJson(file).pipe(Effect.orElseSucceed(() => null)) - - if (!raw || typeof raw !== "object") return { version: 2, accounts: {}, active: {} } - - if ("version" in raw && raw.version === 2) return raw as Writable - - const migrated = migrate(raw as Record) + 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.OPENCODE_AUTH_CONTENT ?? "") + } catch {} + } + + const load: () => Effect.Effect = Effect.fnUntraced(function* () { + if (process.env.OPENCODE_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) diff --git a/packages/core/src/catalog.ts b/packages/core/src/catalog.ts new file mode 100644 index 0000000000..3aa5915420 --- /dev/null +++ b/packages/core/src/catalog.ts @@ -0,0 +1,258 @@ +export * as Catalog from "./catalog" + +import { Context, Effect, HashMap, Layer, Option, Order, pipe, Schema, Array } from "effect" +import { produce, type Draft } from "immer" +import { ModelV2 } from "./model" +import { PluginV2 } from "./plugin" +import { ProviderV2 } from "./provider" + +type ProviderRecord = { + provider: ProviderV2.Info + models: HashMap.HashMap +} + +export class ProviderNotFoundError extends Schema.TaggedErrorClass()( + "CatalogV2.ProviderNotFound", + { + providerID: ProviderV2.ID, + }, +) {} + +export class ModelNotFoundError extends Schema.TaggedErrorClass()("CatalogV2.ModelNotFound", { + providerID: ProviderV2.ID, + modelID: ModelV2.ID, +}) {} + +export interface Interface { + 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 + } + readonly model: { + readonly get: ( + 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> + readonly setDefault: ( + providerID: ProviderV2.ID, + modelID: ModelV2.ID, + ) => Effect.Effect + readonly small: (providerID: ProviderV2.ID) => Effect.Effect> + } +} + +export class Service extends Context.Service()("@opencode/v2/Catalog") {} + +export const layer = Layer.effect( + Service, + Effect.gen(function* () { + let records = HashMap.empty() + let defaultModel: { providerID: ProviderV2.ID; modelID: ModelV2.ID } | undefined + const plugin = yield* PluginV2.Service + + const resolve = (model: ModelV2.Info) => { + const provider = Option.getOrThrow(HashMap.get(records, model.providerID)).provider + const endpoint = + model.endpoint.type === "unknown" + ? provider.endpoint + : model.endpoint.type === "aisdk" && provider.endpoint.type === "aisdk" && !model.endpoint.url + ? { ...model.endpoint, url: provider.endpoint.url } + : model.endpoint + const options = { + headers: { + ...provider.options.headers, + ...model.options.headers, + }, + body: { + ...provider.options.body, + ...model.options.body, + }, + aisdk: { + provider: { + ...provider.options.aisdk.provider, + ...model.options.aisdk.provider, + }, + request: model.options.aisdk.request, + }, + variant: model.options.variant, + } + return new ModelV2.Info({ + ...model, + endpoint, + options, + }) + } + + function* getRecord(providerID: ProviderV2.ID) { + const match = HashMap.get(records, providerID) + if (!match.valueOrUndefined) return yield* new ProviderNotFoundError({ providerID }) + return match.value + } + + const result: Interface = { + 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) + }), + + available: Effect.fn("CatalogV2.provider.available")(function* () { + return globalThis.Array.from(HashMap.values(records)) + .map((record) => record.provider) + .filter((provider) => provider.enabled) + }), + }, + + model: { + get: Effect.fn("CatalogV2.model.get")(function* (providerID, modelID) { + const record = yield* getRecord(providerID) + const model = Option.getOrUndefined(HashMap.get(record.models, 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 + records = HashMap.set(records, providerID, { + provider: record.provider, + models: HashMap.set( + record.models, + modelID, + new ModelV2.Info({ ...updated.model, id: modelID, providerID }), + ), + }) + return + }), + + all: Effect.fn("CatalogV2.model.all")(function* () { + return pipe( + records, + HashMap.toValues, + Array.flatMap((record) => HashMap.toValues(record.models)), + Array.map(resolve), + Array.sortWith((item) => item.time.released.epochMilliseconds, Order.flip(Order.Number)), + ) + }), + + available: Effect.fn("CatalogV2.model.available")(function* () { + return (yield* result.model.all()).filter((model) => { + const record = Option.getOrUndefined(HashMap.get(records, model.providerID)) + return record?.provider.enabled !== false && model.enabled + }) + }), + + default: Effect.fn("CatalogV2.model.default")(function* () { + if (defaultModel) { + const model = yield* result.model.get(defaultModel.providerID, defaultModel.modelID).pipe(Effect.option) + if (Option.isSome(model) && model.value.enabled) return model + } + + return pipe( + yield* result.model.available(), + Array.sortWith((item) => item.time.released.epochMilliseconds, Order.flip(Order.Number)), + Array.head, + ) + }), + + setDefault: Effect.fn("CatalogV2.model.setDefault")(function* (providerID, modelID) { + yield* result.model.get(providerID, modelID) + defaultModel = { providerID, modelID } + }), + + small: Effect.fn("CatalogV2.model.small")(function* (providerID) { + const record = Option.getOrUndefined(HashMap.get(records, providerID)) + if (!record) return Option.none() + + if (providerID === ProviderV2.ID.opencode) { + const gpt5Nano = Option.getOrUndefined(HashMap.get(record.models, ModelV2.ID.make("gpt-5-nano"))) + if (gpt5Nano?.enabled && gpt5Nano.status === "active") return Option.some(resolve(gpt5Nano)) + } + + const candidates = pipe( + HashMap.toValues(record.models), + Array.filter( + (model) => + model.providerID === providerID && + model.enabled && + model.status === "active" && + model.capabilities.input.some((item) => item.startsWith("text")) && + model.capabilities.output.some((item) => item.startsWith("text")), + ), + Array.map((model) => ({ + model, + cost: model.cost[0] ? model.cost[0].input + model.cost[0].output : 999, + age: (Date.now() - model.time.released.epochMilliseconds) / (1000 * 60 * 60 * 24 * 30), + small: SMALL_MODEL_RE.test(`${model.id} ${model.family ?? ""} ${model.name}`.toLowerCase()), + })), + Array.filter((item) => item.cost > 0 && item.age <= 18), + ) + + const pick = (items: typeof candidates) => { + const maxCost = Math.max(...items.map((item) => item.cost), 0.01) + const maxAge = Math.max(...items.map((item) => item.age), 0.01) + return pipe( + items, + Array.sortWith((item) => (item.cost / maxCost) * 0.8 + (item.age / maxAge) * 0.2, Order.Number), + Array.map((item) => resolve(item.model)), + Array.head, + ) + } + + return pipe( + candidates, + Array.filter((item) => item.small), + (items) => (items.length > 0 ? pick(items) : pick(candidates)), + ) + }), + }, + } + + return Service.of(result) + }), +) + +const SMALL_MODEL_RE = /\b(nano|flash|lite|mini|haiku|small|fast)\b/ + +export const defaultLayer = layer.pipe(Layer.provide(PluginV2.defaultLayer)) diff --git a/packages/opencode/src/provider/sdk/copilot/README.md b/packages/core/src/github-copilot/README.md similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/README.md rename to packages/core/src/github-copilot/README.md diff --git a/packages/opencode/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts b/packages/core/src/github-copilot/chat/convert-to-openai-compatible-chat-messages.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts rename to packages/core/src/github-copilot/chat/convert-to-openai-compatible-chat-messages.ts diff --git a/packages/opencode/src/provider/sdk/copilot/chat/get-response-metadata.ts b/packages/core/src/github-copilot/chat/get-response-metadata.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/chat/get-response-metadata.ts rename to packages/core/src/github-copilot/chat/get-response-metadata.ts diff --git a/packages/opencode/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts b/packages/core/src/github-copilot/chat/map-openai-compatible-finish-reason.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts rename to packages/core/src/github-copilot/chat/map-openai-compatible-finish-reason.ts diff --git a/packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts b/packages/core/src/github-copilot/chat/openai-compatible-api-types.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts rename to packages/core/src/github-copilot/chat/openai-compatible-api-types.ts diff --git a/packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts b/packages/core/src/github-copilot/chat/openai-compatible-chat-language-model.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts rename to packages/core/src/github-copilot/chat/openai-compatible-chat-language-model.ts diff --git a/packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts b/packages/core/src/github-copilot/chat/openai-compatible-chat-options.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts rename to packages/core/src/github-copilot/chat/openai-compatible-chat-options.ts diff --git a/packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts b/packages/core/src/github-copilot/chat/openai-compatible-metadata-extractor.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts rename to packages/core/src/github-copilot/chat/openai-compatible-metadata-extractor.ts diff --git a/packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts b/packages/core/src/github-copilot/chat/openai-compatible-prepare-tools.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts rename to packages/core/src/github-copilot/chat/openai-compatible-prepare-tools.ts diff --git a/packages/opencode/src/provider/sdk/copilot/copilot-provider.ts b/packages/core/src/github-copilot/copilot-provider.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/copilot-provider.ts rename to packages/core/src/github-copilot/copilot-provider.ts diff --git a/packages/opencode/src/provider/sdk/copilot/openai-compatible-error.ts b/packages/core/src/github-copilot/openai-compatible-error.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/openai-compatible-error.ts rename to packages/core/src/github-copilot/openai-compatible-error.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts b/packages/core/src/github-copilot/responses/convert-to-openai-responses-input.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts rename to packages/core/src/github-copilot/responses/convert-to-openai-responses-input.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts b/packages/core/src/github-copilot/responses/map-openai-responses-finish-reason.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts rename to packages/core/src/github-copilot/responses/map-openai-responses-finish-reason.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/openai-config.ts b/packages/core/src/github-copilot/responses/openai-config.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/openai-config.ts rename to packages/core/src/github-copilot/responses/openai-config.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/openai-error.ts b/packages/core/src/github-copilot/responses/openai-error.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/openai-error.ts rename to packages/core/src/github-copilot/responses/openai-error.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/openai-responses-api-types.ts b/packages/core/src/github-copilot/responses/openai-responses-api-types.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/openai-responses-api-types.ts rename to packages/core/src/github-copilot/responses/openai-responses-api-types.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/openai-responses-language-model.ts b/packages/core/src/github-copilot/responses/openai-responses-language-model.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/openai-responses-language-model.ts rename to packages/core/src/github-copilot/responses/openai-responses-language-model.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts b/packages/core/src/github-copilot/responses/openai-responses-prepare-tools.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts rename to packages/core/src/github-copilot/responses/openai-responses-prepare-tools.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/openai-responses-settings.ts b/packages/core/src/github-copilot/responses/openai-responses-settings.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/openai-responses-settings.ts rename to packages/core/src/github-copilot/responses/openai-responses-settings.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/tool/code-interpreter.ts b/packages/core/src/github-copilot/responses/tool/code-interpreter.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/tool/code-interpreter.ts rename to packages/core/src/github-copilot/responses/tool/code-interpreter.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/tool/file-search.ts b/packages/core/src/github-copilot/responses/tool/file-search.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/tool/file-search.ts rename to packages/core/src/github-copilot/responses/tool/file-search.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/tool/image-generation.ts b/packages/core/src/github-copilot/responses/tool/image-generation.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/tool/image-generation.ts rename to packages/core/src/github-copilot/responses/tool/image-generation.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/tool/local-shell.ts b/packages/core/src/github-copilot/responses/tool/local-shell.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/tool/local-shell.ts rename to packages/core/src/github-copilot/responses/tool/local-shell.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/tool/web-search-preview.ts b/packages/core/src/github-copilot/responses/tool/web-search-preview.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/tool/web-search-preview.ts rename to packages/core/src/github-copilot/responses/tool/web-search-preview.ts diff --git a/packages/opencode/src/provider/sdk/copilot/responses/tool/web-search.ts b/packages/core/src/github-copilot/responses/tool/web-search.ts similarity index 100% rename from packages/opencode/src/provider/sdk/copilot/responses/tool/web-search.ts rename to packages/core/src/github-copilot/responses/tool/web-search.ts diff --git a/packages/core/src/model.ts b/packages/core/src/model.ts new file mode 100644 index 0000000000..77b8c60ebe --- /dev/null +++ b/packages/core/src/model.ts @@ -0,0 +1,116 @@ +import { DateTime, Schema } from "effect" +import { DateTimeUtcFromMillis } from "effect/Schema" +import { ProviderV2 } from "./provider" + +export const ID = Schema.String.pipe(Schema.brand("ModelV2.ID")) +export type ID = typeof ID.Type + +export const VariantID = Schema.String.pipe(Schema.brand("VariantID")) +export type VariantID = typeof VariantID.Type + +// Grouping of models, eg claude opus, claude sonnet +export const Family = Schema.String.pipe(Schema.brand("Family")) +export type Family = typeof Family.Type + +export const Capabilities = Schema.Struct({ + tools: Schema.Boolean, + // mime patterns, image, audio, video/*, text/* + input: Schema.String.pipe(Schema.Array), + output: Schema.String.pipe(Schema.Array), +}) +export type Capabilities = typeof Capabilities.Type + +export const Cost = Schema.Struct({ + tier: Schema.Struct({ + type: Schema.Literal("context"), + size: Schema.Int, + }).pipe(Schema.optional), + input: Schema.Finite, + output: Schema.Finite, + cache: Schema.Struct({ + read: Schema.Finite, + write: Schema.Finite, + }), +}) + +export const Ref = Schema.Struct({ + id: ID, + providerID: ProviderV2.ID, + variant: VariantID, +}) +export type Ref = typeof Ref.Type + +export class Info extends Schema.Class("ModelV2.Info")({ + id: ID, + apiID: ID, + providerID: ProviderV2.ID, + family: Family.pipe(Schema.optional), + name: Schema.String, + endpoint: ProviderV2.Endpoint, + capabilities: Capabilities, + options: Schema.Struct({ + ...ProviderV2.Options.fields, + variant: Schema.String.pipe(Schema.optional), + }), + variants: Schema.Struct({ + id: VariantID, + ...ProviderV2.Options.fields, + }).pipe(Schema.Array), + time: Schema.Struct({ + released: DateTimeUtcFromMillis, + }), + cost: Cost.pipe(Schema.Array), + status: Schema.Literals(["alpha", "beta", "deprecated", "active"]), + enabled: Schema.Boolean, + limit: Schema.Struct({ + context: Schema.Int, + input: Schema.Int.pipe(Schema.optional), + output: Schema.Int, + }), +}) { + static empty(providerID: ProviderV2.ID, modelID: ID) { + return new Info({ + id: modelID, + apiID: modelID, + providerID, + name: modelID, + endpoint: { + type: "unknown", + }, + capabilities: { + tools: false, + input: [], + output: [], + }, + options: { + headers: {}, + body: {}, + aisdk: { + provider: {}, + request: {}, + }, + }, + variants: [], + time: { + released: DateTime.makeUnsafe(0), + }, + cost: [], + status: "active", + enabled: true, + limit: { + context: 0, + output: 0, + }, + }) + } +} + +export function parse(input: string): { providerID: ProviderV2.ID; modelID: ID } { + const [providerID, ...modelID] = input.split("/") + return { + providerID: ProviderV2.ID.make(providerID), + modelID: ID.make(modelID.join("/")), + } +} + +export * as ModelV2 from "./model" diff --git a/packages/core/src/plugin.ts b/packages/core/src/plugin.ts new file mode 100644 index 0000000000..dfcae94685 --- /dev/null +++ b/packages/core/src/plugin.ts @@ -0,0 +1,146 @@ +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 type { ModelV2 } from "./model" + +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 + } + } + "model.update": { + input: {} + output: { + model: ModelV2.Info + cancel: boolean + } + } + "aisdk.language": { + input: { + model: ModelV2.Info + sdk: any + options: Record + } + output: { + language?: LanguageModelV3 + } + } + "aisdk.sdk": { + input: { + model: ModelV2.Info + package: string + options: Record + } + output: { + sdk?: any + } + } +} + +export type Hooks = { + [Name in keyof HookSpec]: Readonly & { + -readonly [Field in keyof HookSpec[Name]["output"]]: HookSpec[Name]["output"][Field] extends object + ? Draft + : HookSpec[Name]["output"][Field] + } +} + +export type HookFunctions = { + [key in keyof Hooks]?: (input: Hooks[key]) => Effect.Effect +} + +export type HookInput = HookSpec[Name]["input"] +export type HookOutput = HookSpec[Name]["output"] + +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 remove: (id: ID) => Effect.Effect + readonly trigger: ( + name: Name, + input: HookInput, + output: HookOutput, + ) => Effect.Effect & HookOutput> +} + +export class Service extends Context.Service()("@opencode/v2/Plugin") {} + +export const layer = Layer.effect( + Service, + Effect.gen(function* () { + let hooks: { + id: ID + hooks: HookFunctions + }[] = [] + + const svc = Service.of({ + add: Effect.fn("Plugin.add")(function* (input) { + const result = yield* input.effect + if (!result) return + hooks = [ + ...hooks.filter((item) => item.id !== input.id), + { + id: input.id, + hooks: result, + }, + ] + }), + trigger: Effect.fn("Plugin.trigger")(function* (name, input, output) { + const draftEntries = new Map>() + const event = { + ...input, + ...output, + } as Record + + for (const [field, value] of Object.entries(output)) { + if (value && typeof value === "object") { + draftEntries.set(field, createDraft(value)) + event[field] = draftEntries.get(field) + } + } + + for (const item of hooks) { + const match = item.hooks[name] + if (!match) continue + yield* match(event as any).pipe( + Effect.withSpan(`Plugin.hook.${name}`, { + attributes: { + plugin: item.id, + hook: name, + }, + }), + ) + } + + for (const [field, draft] of draftEntries) { + event[field] = finishDraft(draft) + } + + return event as any + }), + remove: Effect.fn("Plugin.remove")(function* (id) { + hooks = hooks.filter((item) => item.id !== id) + }), + }) + return svc + }), +) + +export const defaultLayer = layer + +// opencode +// sdcok diff --git a/packages/core/src/plugin/auth.ts b/packages/core/src/plugin/auth.ts new file mode 100644 index 0000000000..81cbfbe3f7 --- /dev/null +++ b/packages/core/src/plugin/auth.ts @@ -0,0 +1,27 @@ +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/env.ts b/packages/core/src/plugin/env.ts new file mode 100644 index 0000000000..d63936fa13 --- /dev/null +++ b/packages/core/src/plugin/env.ts @@ -0,0 +1,18 @@ +import { Effect } from "effect" +import { PluginV2 } from "../plugin" + +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, + } + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider.ts b/packages/core/src/plugin/provider.ts new file mode 100644 index 0000000000..1880787495 --- /dev/null +++ b/packages/core/src/plugin/provider.ts @@ -0,0 +1 @@ +export { ProviderPlugins } from "./provider/index" diff --git a/packages/core/src/plugin/provider/alibaba.ts b/packages/core/src/plugin/provider/alibaba.ts new file mode 100644 index 0000000000..fa5c0a91cf --- /dev/null +++ b/packages/core/src/plugin/provider/alibaba.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const AlibabaPlugin = PluginV2.define({ + id: PluginV2.ID.make("alibaba"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/alibaba") return + const mod = yield* Effect.promise(() => import("@ai-sdk/alibaba")) + evt.sdk = mod.createAlibaba(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/amazon-bedrock.ts b/packages/core/src/plugin/provider/amazon-bedrock.ts new file mode 100644 index 0000000000..366548a0a3 --- /dev/null +++ b/packages/core/src/plugin/provider/amazon-bedrock.ts @@ -0,0 +1,94 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +// Bedrock cross-region inference profiles require regional prefixes only for +// specific model/region combinations. Keep the mapping narrow and avoid +// double-prefixing model IDs that models.dev already marks as global/us/eu/etc. +function resolveModelID(modelID: string, region: string | undefined) { + const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."] + if (crossRegionPrefixes.some((prefix) => modelID.startsWith(prefix))) return modelID + + const resolvedRegion = region ?? "us-east-1" + const regionPrefix = resolvedRegion.split("-")[0] + if (regionPrefix === "us") { + const requiresPrefix = ["nova-micro", "nova-lite", "nova-pro", "nova-premier", "nova-2", "claude", "deepseek"].some( + (item) => modelID.includes(item), + ) + if (requiresPrefix && !resolvedRegion.startsWith("us-gov")) return `${regionPrefix}.${modelID}` + return modelID + } + if (regionPrefix === "eu") { + const regionRequiresPrefix = [ + "eu-west-1", + "eu-west-2", + "eu-west-3", + "eu-north-1", + "eu-central-1", + "eu-south-1", + "eu-south-2", + ].some((item) => resolvedRegion.includes(item)) + const modelRequiresPrefix = ["claude", "nova-lite", "nova-micro", "llama3", "pixtral"].some((item) => + modelID.includes(item), + ) + return regionRequiresPrefix && modelRequiresPrefix ? `${regionPrefix}.${modelID}` : modelID + } + if (regionPrefix !== "ap") return modelID + + const australia = ["ap-southeast-2", "ap-southeast-4"].includes(resolvedRegion) + if (australia && ["anthropic.claude-sonnet-4-5", "anthropic.claude-haiku"].some((item) => modelID.includes(item))) { + return `au.${modelID}` + } + + const prefix = resolvedRegion === "ap-northeast-1" ? "jp" : "apac" + return ["claude", "nova-lite", "nova-micro", "nova-pro"].some((item) => modelID.includes(item)) + ? `${prefix}.${modelID}` + : modelID +} + +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 + }), + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/amazon-bedrock") return + const options = { ...evt.options } + const profile = typeof options.profile === "string" ? options.profile : process.env.AWS_PROFILE + const region = typeof options.region === "string" ? options.region : (process.env.AWS_REGION ?? "us-east-1") + const bearerToken = + process.env.AWS_BEARER_TOKEN_BEDROCK ?? + (typeof options.bearerToken === "string" ? options.bearerToken : undefined) + if (bearerToken && !process.env.AWS_BEARER_TOKEN_BEDROCK) process.env.AWS_BEARER_TOKEN_BEDROCK = bearerToken + const containerCreds = Boolean( + process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI || process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI, + ) + + options.region = region + if (typeof options.endpoint === "string") options.baseURL = options.endpoint + if (!bearerToken && options.credentialProvider === undefined) { + // Do not gate SDK creation on explicit AWS env vars. The default chain + // also handles ~/.aws/credentials, SSO, process creds, and instance roles. + const { fromNodeProviderChain } = yield* Effect.promise(() => import("@aws-sdk/credential-providers")) + options.credentialProvider = fromNodeProviderChain(profile ? { profile } : {}) + } + + const mod = yield* Effect.promise(() => import("@ai-sdk/amazon-bedrock")) + evt.sdk = mod.createAmazonBedrock(options) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.amazonBedrock) return + const region = typeof evt.options.region === "string" ? evt.options.region : process.env.AWS_REGION + evt.language = evt.sdk.languageModel(resolveModelID(evt.model.apiID, region)) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/anthropic.ts b/packages/core/src/plugin/provider/anthropic.ts new file mode 100644 index 0000000000..14851c4a31 --- /dev/null +++ b/packages/core/src/plugin/provider/anthropic.ts @@ -0,0 +1,21 @@ +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" + }), + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/anthropic") return + const mod = yield* Effect.promise(() => import("@ai-sdk/anthropic")) + evt.sdk = mod.createAnthropic(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/azure.ts b/packages/core/src/plugin/provider/azure.ts new file mode 100644 index 0000000000..6c29a16103 --- /dev/null +++ b/packages/core/src/plugin/provider/azure.ts @@ -0,0 +1,64 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +function selectLanguage(sdk: any, modelID: string, useChat: boolean) { + if (useChat && sdk.chat) return sdk.chat(modelID) + if (sdk.responses) return sdk.responses(modelID) + if (sdk.messages) return sdk.messages(modelID) + if (sdk.chat) return sdk.chat(modelID) + return sdk.languageModel(modelID) +} + +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 + }), + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/azure") return + if (evt.model.providerID === ProviderV2.ID.azure) { + if ( + !evt.options.resourceName && + !evt.options.baseURL && + (evt.model.endpoint.type !== "aisdk" || !evt.model.endpoint.url) + ) { + throw new Error( + "AZURE_RESOURCE_NAME is missing, set it using env var or reconnecting the azure provider and setting it", + ) + } + } + const mod = yield* Effect.promise(() => import("@ai-sdk/azure")) + evt.sdk = mod.createAzure(evt.options) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.azure) return + evt.language = selectLanguage(evt.sdk, evt.model.apiID, Boolean(evt.options.useCompletionUrls)) + }), + } + }), +}) + +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 + const resourceName = process.env.AZURE_COGNITIVE_SERVICES_RESOURCE_NAME + if (resourceName) + evt.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 + evt.language = selectLanguage(evt.sdk, evt.model.apiID, Boolean(evt.options.useCompletionUrls)) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/cerebras.ts b/packages/core/src/plugin/provider/cerebras.ts new file mode 100644 index 0000000000..b2fadd8bf1 --- /dev/null +++ b/packages/core/src/plugin/provider/cerebras.ts @@ -0,0 +1,20 @@ +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" + }), + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/cerebras") return + const mod = yield* Effect.promise(() => import("@ai-sdk/cerebras")) + evt.sdk = mod.createCerebras(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/cloudflare-ai-gateway.ts b/packages/core/src/plugin/provider/cloudflare-ai-gateway.ts new file mode 100644 index 0000000000..ffcd4adcf4 --- /dev/null +++ b/packages/core/src/plugin/provider/cloudflare-ai-gateway.ts @@ -0,0 +1,81 @@ +import os from "os" +import { InstallationVersion } from "../../installation/version" +import { Effect, Option, Schema } from "effect" +import { PluginV2 } from "../../plugin" + +export const CloudflareAIGatewayPlugin = PluginV2.define({ + id: PluginV2.ID.make("cloudflare-ai-gateway"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "ai-gateway-provider") return + if (evt.options.baseURL) return + + const config = gatewayConfig(evt.options) + if (!config) return + const metadata = gatewayMetadata(evt.options) + const { createAiGateway } = yield* Effect.promise(() => import("ai-gateway-provider")).pipe(Effect.orDie) + const { createUnified } = yield* Effect.promise(() => import("ai-gateway-provider/providers/unified")).pipe( + Effect.orDie, + ) + const gateway = createAiGateway({ + accountId: config.accountId, + gateway: config.gatewayId, + apiKey: config.apiKey, + options: gatewayOptions(evt.options, metadata), + } as any) + const unified = createUnified() + evt.sdk = { + languageModel(modelID: string) { + return gateway(unified(modelID)) + }, + } + }), + } + }), +}) + +type GatewayConfig = { + accountId: string + gatewayId: string + apiKey: string +} + +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 + // gateway as gatewayId, while older config examples may use gateway. + const gatewayId = + process.env.CLOUDFLARE_GATEWAY_ID ?? stringOption(options, "gatewayId") ?? stringOption(options, "gateway") + const apiKey = process.env.CLOUDFLARE_API_TOKEN ?? process.env.CF_AIG_TOKEN ?? stringOption(options, "apiKey") + if (!accountId || !gatewayId || !apiKey) return undefined + + return { accountId, gatewayId, apiKey } +} + +function gatewayMetadata(options: Record) { + // Preserve the legacy cf-aig-metadata header escape hatch for gateway logging + // metadata, but prefer the typed metadata option when present. + if (options.metadata !== undefined) return options.metadata + const raw = (options.headers as Record | undefined)?.["cf-aig-metadata"] + return raw ? Option.getOrUndefined(decodeJson(raw)) : undefined +} + +function gatewayOptions(options: Record, metadata: unknown) { + return { + metadata, + cacheTtl: options.cacheTtl, + cacheKey: options.cacheKey, + skipCache: options.skipCache, + collectLog: options.collectLog, + headers: { + "User-Agent": `opencode/${InstallationVersion} cloudflare-ai-gateway (${os.platform()} ${os.release()}; ${os.arch()})`, + }, + } +} + +function stringOption(options: Record, key: string) { + return typeof options[key] === "string" ? options[key] : undefined +} diff --git a/packages/core/src/plugin/provider/cloudflare-workers-ai.ts b/packages/core/src/plugin/provider/cloudflare-workers-ai.ts new file mode 100644 index 0000000000..f39869b57d --- /dev/null +++ b/packages/core/src/plugin/provider/cloudflare-workers-ai.ts @@ -0,0 +1,69 @@ +import os from "os" +import { InstallationVersion } from "../../installation/version" +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +const providerID = ProviderV2.ID.make("cloudflare-workers-ai") + +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) + }), + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.model.providerID !== providerID) return + if (evt.package !== "@ai-sdk/openai-compatible") return + + if (!hasWorkersEndpoint(evt.model.endpoint)) return + const mod = yield* Effect.promise(() => import("@ai-sdk/openai-compatible")) + evt.sdk = mod.createOpenAICompatible(sdkOptions(evt.options) as any) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== providerID) return + evt.language = evt.sdk.languageModel(evt.model.apiID) + }), + } + }), +}) + +function resolveAccountId(options: Record) { + return process.env.CLOUDFLARE_ACCOUNT_ID ?? stringOption(options, "accountId") +} + +function workersEndpoint(accountId: string) { + return `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/v1` +} + +function hasWorkersEndpoint(endpoint: ProviderV2.Endpoint) { + return endpoint.type === "aisdk" && Boolean(endpoint.url) +} + +function sdkOptions(options: Record) { + return { + ...options, + baseURL: expandAccountId(options.baseURL), + apiKey: process.env.CLOUDFLARE_API_KEY ?? options.apiKey, + headers: { + "User-Agent": `opencode/${InstallationVersion} cloudflare-workers-ai (${os.platform()} ${os.release()}; ${os.arch()})`, + ...options.headers, + }, + name: providerID, + } +} + +function expandAccountId(baseURL: unknown) { + if (typeof baseURL !== "string") return baseURL + return baseURL.replaceAll("${CLOUDFLARE_ACCOUNT_ID}", process.env.CLOUDFLARE_ACCOUNT_ID ?? "${CLOUDFLARE_ACCOUNT_ID}") +} + +function stringOption(options: Record, key: string) { + return typeof options[key] === "string" ? options[key] : undefined +} diff --git a/packages/core/src/plugin/provider/cohere.ts b/packages/core/src/plugin/provider/cohere.ts new file mode 100644 index 0000000000..991c370d17 --- /dev/null +++ b/packages/core/src/plugin/provider/cohere.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const CoherePlugin = PluginV2.define({ + id: PluginV2.ID.make("cohere"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/cohere") return + const mod = yield* Effect.promise(() => import("@ai-sdk/cohere")) + evt.sdk = mod.createCohere(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/deepinfra.ts b/packages/core/src/plugin/provider/deepinfra.ts new file mode 100644 index 0000000000..bbd42f6e28 --- /dev/null +++ b/packages/core/src/plugin/provider/deepinfra.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const DeepInfraPlugin = PluginV2.define({ + id: PluginV2.ID.make("deepinfra"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/deepinfra") return + const mod = yield* Effect.promise(() => import("@ai-sdk/deepinfra")) + evt.sdk = mod.createDeepInfra(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/dynamic.ts b/packages/core/src/plugin/provider/dynamic.ts new file mode 100644 index 0000000000..e5abc7009e --- /dev/null +++ b/packages/core/src/plugin/provider/dynamic.ts @@ -0,0 +1,31 @@ +import { Npm } from "../../npm" +import { Effect, Option } from "effect" +import { pathToFileURL } from "url" +import { PluginV2 } from "../../plugin" + +export const DynamicProviderPlugin = PluginV2.define({ + id: PluginV2.ID.make("dynamic-provider"), + effect: Effect.gen(function* () { + const npm = yield* Npm.Service + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.sdk) return + + const installedPath = evt.package.startsWith("file://") + ? evt.package + : Option.getOrUndefined((yield* npm.add(evt.package).pipe(Effect.orDie)).entrypoint) + if (!installedPath) throw new Error(`Package ${evt.package} has no import entrypoint`) + + const mod = yield* Effect.promise(async () => { + return (await import( + installedPath.startsWith("file://") ? installedPath : pathToFileURL(installedPath).href + )) as Record any> + }).pipe(Effect.orDie) + const match = Object.keys(mod).find((name) => name.startsWith("create")) + if (!match) throw new Error(`Package ${evt.package} has no provider factory export`) + + evt.sdk = mod[match](evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/gateway.ts b/packages/core/src/plugin/provider/gateway.ts new file mode 100644 index 0000000000..5b08ad9ef5 --- /dev/null +++ b/packages/core/src/plugin/provider/gateway.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const GatewayPlugin = PluginV2.define({ + id: PluginV2.ID.make("gateway"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/gateway") return + const mod = yield* Effect.promise(() => import("@ai-sdk/gateway")) + evt.sdk = mod.createGateway(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/github-copilot.ts b/packages/core/src/plugin/provider/github-copilot.ts new file mode 100644 index 0000000000..31e57ba12a --- /dev/null +++ b/packages/core/src/plugin/provider/github-copilot.ts @@ -0,0 +1,44 @@ +import { Effect } from "effect" +import { ModelV2 } from "../../model" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +function shouldUseResponses(modelID: string) { + // Copilot supports Responses for GPT-5 class models, except mini variants + // which still need the chat-completions endpoint. + const match = /^gpt-(\d+)/.exec(modelID) + if (!match) return false + return Number(match[1]) >= 5 && !modelID.startsWith("gpt-5-mini") +} + +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")) + evt.sdk = mod.createOpenaiCompatible(evt.options) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.githubCopilot) return + if (evt.sdk.responses === undefined && evt.sdk.chat === undefined) { + evt.language = evt.sdk.languageModel(evt.model.apiID) + return + } + evt.language = shouldUseResponses(evt.model.apiID) + ? 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 + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/gitlab.ts b/packages/core/src/plugin/provider/gitlab.ts new file mode 100644 index 0000000000..226f5a45eb --- /dev/null +++ b/packages/core/src/plugin/provider/gitlab.ts @@ -0,0 +1,65 @@ +import os from "os" +import { InstallationVersion } from "../../installation/version" +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +export const GitLabPlugin = PluginV2.define({ + id: PluginV2.ID.make("gitlab"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "gitlab-ai-provider") return + const mod = yield* Effect.promise(() => import("gitlab-ai-provider")) + evt.sdk = mod.createGitLab({ + ...evt.options, + instanceUrl: + typeof evt.options.instanceUrl === "string" + ? evt.options.instanceUrl + : (process.env.GITLAB_INSTANCE_URL ?? "https://gitlab.com"), + apiKey: typeof evt.options.apiKey === "string" ? evt.options.apiKey : process.env.GITLAB_TOKEN, + aiGatewayHeaders: { + "User-Agent": `opencode/${InstallationVersion} gitlab-ai-provider/${mod.VERSION} (${os.platform()} ${os.release()}; ${os.arch()})`, + "anthropic-beta": "context-1m-2025-08-07", + ...evt.options.aiGatewayHeaders, + }, + featureFlags: { + duo_agent_platform_agentic_chat: true, + duo_agent_platform: true, + ...evt.options.featureFlags, + }, + }) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.gitlab) return + const featureFlags = + typeof evt.options.featureFlags === "object" && evt.options.featureFlags ? evt.options.featureFlags : {} + if (evt.model.apiID.startsWith("duo-workflow-")) { + const gitlab = yield* Effect.promise(() => import("gitlab-ai-provider")).pipe(Effect.orDie) + const workflowRef = + typeof evt.model.options.aisdk.request.workflowRef === "string" + ? evt.model.options.aisdk.request.workflowRef + : undefined + const workflowDefinition = + typeof evt.model.options.aisdk.request.workflowDefinition === "string" + ? evt.model.options.aisdk.request.workflowDefinition + : undefined + const language = evt.sdk.workflowChat( + gitlab.isWorkflowModel(evt.model.apiID) ? evt.model.apiID : "duo-workflow", + { + featureFlags, + workflowDefinition, + }, + ) + if (workflowRef) language.selectedModelRef = workflowRef + evt.language = language + return + } + evt.language = evt.sdk.agenticChat(evt.model.apiID, { + aiGatewayHeaders: evt.options.aiGatewayHeaders, + featureFlags, + }) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/google-vertex.ts b/packages/core/src/plugin/provider/google-vertex.ts new file mode 100644 index 0000000000..0c335df931 --- /dev/null +++ b/packages/core/src/plugin/provider/google-vertex.ts @@ -0,0 +1,141 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +function resolveProject(options: Record) { + // models.dev advertises GOOGLE_VERTEX_PROJECT for Vertex, while Google SDKs + // and ADC examples commonly use the broader Google Cloud project aliases. + return ( + options.project ?? + process.env.GOOGLE_VERTEX_PROJECT ?? + process.env.GOOGLE_CLOUD_PROJECT ?? + process.env.GCP_PROJECT ?? + process.env.GCLOUD_PROJECT + ) +} + +function resolveLocation(options: Record) { + return ( + options.location ?? + process.env.GOOGLE_VERTEX_LOCATION ?? + process.env.GOOGLE_CLOUD_LOCATION ?? + process.env.VERTEX_LOCATION ?? + "us-central1" + ) +} + +function vertexEndpoint(location: string) { + return location === "global" ? "aiplatform.googleapis.com" : `${location}-aiplatform.googleapis.com` +} + +function replaceVertexVars(value: string, project: string | undefined, location: string) { + // Vertex OpenAI-compatible endpoints are stored as templates in the catalog; + // expand them after provider config/env project and location have been resolved. + return value + .replaceAll("${GOOGLE_VERTEX_PROJECT}", project ?? "${GOOGLE_VERTEX_PROJECT}") + .replaceAll("${GOOGLE_VERTEX_LOCATION}", location) + .replaceAll("${GOOGLE_VERTEX_ENDPOINT}", vertexEndpoint(location)) +} + +function authFetch(fetchWithRuntimeOptions?: unknown) { + // Native Vertex SDKs handle ADC internally. OpenAI-compatible Vertex endpoints + // do not, so inject a Google access token into their fetch path. + return async (input: Parameters[0], init?: RequestInit) => { + const { GoogleAuth } = await import("google-auth-library") + const auth = new GoogleAuth() + const client = await auth.getApplicationDefault() + const token = await client.credential.getAccessToken() + const headers = new Headers(init?.headers) + headers.set("Authorization", `Bearer ${token.token}`) + return typeof fetchWithRuntimeOptions === "function" + ? fetchWithRuntimeOptions(input, { ...init, headers }) + : fetch(input, { ...init, headers }) + } +} + +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) + } + }), + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.model.providerID === ProviderV2.ID.googleVertex && evt.package.includes("@ai-sdk/openai-compatible")) { + evt.options.fetch = authFetch(evt.options.fetch) + return + } + if (evt.package !== "@ai-sdk/google-vertex") return + const mod = yield* Effect.promise(() => import("@ai-sdk/google-vertex")) + const project = resolveProject(evt.options) + const location = resolveLocation(evt.options) + const options = { ...evt.options } + delete options.fetch + evt.sdk = mod.createVertex({ + ...options, + project, + location, + }) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.googleVertex) return + evt.language = evt.sdk.languageModel(String(evt.model.apiID).trim()) + }), + } + }), +}) + +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 + }), + "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")) + 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"), + }) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.make("google-vertex-anthropic")) return + evt.language = evt.sdk.languageModel(String(evt.model.apiID).trim()) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/google.ts b/packages/core/src/plugin/provider/google.ts new file mode 100644 index 0000000000..47e29c6b5d --- /dev/null +++ b/packages/core/src/plugin/provider/google.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const GooglePlugin = PluginV2.define({ + id: PluginV2.ID.make("google"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/google") return + const mod = yield* Effect.promise(() => import("@ai-sdk/google")) + evt.sdk = mod.createGoogleGenerativeAI(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/groq.ts b/packages/core/src/plugin/provider/groq.ts new file mode 100644 index 0000000000..f2052afd1a --- /dev/null +++ b/packages/core/src/plugin/provider/groq.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const GroqPlugin = PluginV2.define({ + id: PluginV2.ID.make("groq"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/groq") return + const mod = yield* Effect.promise(() => import("@ai-sdk/groq")) + evt.sdk = mod.createGroq(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/index.ts b/packages/core/src/plugin/provider/index.ts new file mode 100644 index 0000000000..fd02d322a1 --- /dev/null +++ b/packages/core/src/plugin/provider/index.ts @@ -0,0 +1,67 @@ +import { AlibabaPlugin } from "./alibaba" +import { AmazonBedrockPlugin } from "./amazon-bedrock" +import { AnthropicPlugin } from "./anthropic" +import { AzureCognitiveServicesPlugin, AzurePlugin } from "./azure" +import { CerebrasPlugin } from "./cerebras" +import { CloudflareAIGatewayPlugin } from "./cloudflare-ai-gateway" +import { CloudflareWorkersAIPlugin } from "./cloudflare-workers-ai" +import { CoherePlugin } from "./cohere" +import { DeepInfraPlugin } from "./deepinfra" +import { DynamicProviderPlugin } from "./dynamic" +import { GatewayPlugin } from "./gateway" +import { GithubCopilotPlugin } from "./github-copilot" +import { GitLabPlugin } from "./gitlab" +import { GooglePlugin } from "./google" +import { GoogleVertexAnthropicPlugin, GoogleVertexPlugin } from "./google-vertex" +import { GroqPlugin } from "./groq" +import { KiloPlugin } from "./kilo" +import { LLMGatewayPlugin } from "./llmgateway" +import { MistralPlugin } from "./mistral" +import { NvidiaPlugin } from "./nvidia" +import { OpenAIPlugin } from "./openai" +import { OpenAICompatiblePlugin } from "./openai-compatible" +import { OpencodePlugin } from "./opencode" +import { OpenRouterPlugin } from "./openrouter" +import { PerplexityPlugin } from "./perplexity" +import { SapAICorePlugin } from "./sap-ai-core" +import { TogetherAIPlugin } from "./togetherai" +import { VercelPlugin } from "./vercel" +import { VenicePlugin } from "./venice" +import { XAIPlugin } from "./xai" +import { ZenmuxPlugin } from "./zenmux" + +export const ProviderPlugins = [ + AlibabaPlugin, + AmazonBedrockPlugin, + AnthropicPlugin, + AzureCognitiveServicesPlugin, + AzurePlugin, + CerebrasPlugin, + CloudflareAIGatewayPlugin, + CloudflareWorkersAIPlugin, + CoherePlugin, + DeepInfraPlugin, + GatewayPlugin, + GithubCopilotPlugin, + GitLabPlugin, + GooglePlugin, + GoogleVertexAnthropicPlugin, + GoogleVertexPlugin, + GroqPlugin, + KiloPlugin, + LLMGatewayPlugin, + MistralPlugin, + NvidiaPlugin, + OpencodePlugin, + OpenAICompatiblePlugin, + OpenAIPlugin, + OpenRouterPlugin, + PerplexityPlugin, + SapAICorePlugin, + TogetherAIPlugin, + VercelPlugin, + VenicePlugin, + XAIPlugin, + ZenmuxPlugin, + DynamicProviderPlugin, +] diff --git a/packages/core/src/plugin/provider/kilo.ts b/packages/core/src/plugin/provider/kilo.ts new file mode 100644 index 0000000000..47b8ec99cd --- /dev/null +++ b/packages/core/src/plugin/provider/kilo.ts @@ -0,0 +1,16 @@ +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" + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/llmgateway.ts b/packages/core/src/plugin/provider/llmgateway.ts new file mode 100644 index 0000000000..da1ab282bd --- /dev/null +++ b/packages/core/src/plugin/provider/llmgateway.ts @@ -0,0 +1,18 @@ +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" + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/mistral.ts b/packages/core/src/plugin/provider/mistral.ts new file mode 100644 index 0000000000..e7f0decb79 --- /dev/null +++ b/packages/core/src/plugin/provider/mistral.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const MistralPlugin = PluginV2.define({ + id: PluginV2.ID.make("mistral"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/mistral") return + const mod = yield* Effect.promise(() => import("@ai-sdk/mistral")) + evt.sdk = mod.createMistral(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/nvidia.ts b/packages/core/src/plugin/provider/nvidia.ts new file mode 100644 index 0000000000..b227e5cef3 --- /dev/null +++ b/packages/core/src/plugin/provider/nvidia.ts @@ -0,0 +1,16 @@ +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" + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/openai-compatible.ts b/packages/core/src/plugin/provider/openai-compatible.ts new file mode 100644 index 0000000000..76c3373706 --- /dev/null +++ b/packages/core/src/plugin/provider/openai-compatible.ts @@ -0,0 +1,17 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const OpenAICompatiblePlugin = PluginV2.define({ + id: PluginV2.ID.make("openai-compatible"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.sdk) return + if (!evt.package.includes("@ai-sdk/openai-compatible")) return + if (evt.options.includeUsage !== false) evt.options.includeUsage = true + const mod = yield* Effect.promise(() => import("@ai-sdk/openai-compatible")) + evt.sdk = mod.createOpenAICompatible(evt.options as any) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/openai.ts b/packages/core/src/plugin/provider/openai.ts new file mode 100644 index 0000000000..a81455f198 --- /dev/null +++ b/packages/core/src/plugin/provider/openai.ts @@ -0,0 +1,27 @@ +import { Effect } from "effect" +import { ModelV2 } from "../../model" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +export const OpenAIPlugin = PluginV2.define({ + id: PluginV2.ID.make("openai"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/openai") return + const mod = yield* Effect.promise(() => import("@ai-sdk/openai")) + evt.sdk = mod.createOpenAI(evt.options) + }), + "aisdk.language": Effect.fn(function* (evt) { + 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 + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/opencode.ts b/packages/core/src/plugin/provider/opencode.ts new file mode 100644 index 0000000000..10bbb62dad --- /dev/null +++ b/packages/core/src/plugin/provider/opencode.ts @@ -0,0 +1,27 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +export const OpencodePlugin = PluginV2.define({ + id: PluginV2.ID.make("opencode"), + effect: Effect.gen(function* () { + let hasKey = false + return { + "provider.update": Effect.fn(function* (evt) { + if (evt.provider.id !== ProviderV2.ID.opencode) 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"), + ) + if (!hasKey) evt.provider.options.aisdk.provider.apiKey = "public" + }), + "model.update": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.opencode) return + if (hasKey) return + if (evt.model.cost.some((item) => item.input > 0)) evt.cancel = true + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/openrouter.ts b/packages/core/src/plugin/provider/openrouter.ts new file mode 100644 index 0000000000..976eea8c05 --- /dev/null +++ b/packages/core/src/plugin/provider/openrouter.ts @@ -0,0 +1,29 @@ +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" + }), + "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/perplexity.ts b/packages/core/src/plugin/provider/perplexity.ts new file mode 100644 index 0000000000..2415ab7c1a --- /dev/null +++ b/packages/core/src/plugin/provider/perplexity.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const PerplexityPlugin = PluginV2.define({ + id: PluginV2.ID.make("perplexity"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/perplexity") return + const mod = yield* Effect.promise(() => import("@ai-sdk/perplexity")) + evt.sdk = mod.createPerplexity(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/sap-ai-core.ts b/packages/core/src/plugin/provider/sap-ai-core.ts new file mode 100644 index 0000000000..7c57b785bf --- /dev/null +++ b/packages/core/src/plugin/provider/sap-ai-core.ts @@ -0,0 +1,44 @@ +import { Npm } from "../../npm" +import { Effect, Option } from "effect" +import { pathToFileURL } from "url" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +export const SapAICorePlugin = PluginV2.define({ + id: PluginV2.ID.make("sap-ai-core"), + effect: Effect.gen(function* () { + const npm = yield* Npm.Service + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.make("sap-ai-core")) return + const serviceKey = + process.env.AICORE_SERVICE_KEY ?? + (typeof evt.options.serviceKey === "string" ? evt.options.serviceKey : undefined) + if (serviceKey && !process.env.AICORE_SERVICE_KEY) process.env.AICORE_SERVICE_KEY = serviceKey + + const installedPath = evt.package.startsWith("file://") + ? evt.package + : Option.getOrUndefined((yield* npm.add(evt.package).pipe(Effect.orDie)).entrypoint) + if (!installedPath) throw new Error(`Package ${evt.package} has no import entrypoint`) + + const mod = yield* Effect.promise(async () => { + return (await import( + installedPath.startsWith("file://") ? installedPath : pathToFileURL(installedPath).href + )) as Record any> + }).pipe(Effect.orDie) + const match = Object.keys(mod).find((name) => name.startsWith("create")) + if (!match) throw new Error(`Package ${evt.package} has no provider factory export`) + + evt.sdk = mod[match]( + serviceKey + ? { deploymentId: process.env.AICORE_DEPLOYMENT_ID, resourceGroup: process.env.AICORE_RESOURCE_GROUP } + : {}, + ) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.make("sap-ai-core")) return + evt.language = evt.sdk(evt.model.apiID) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/togetherai.ts b/packages/core/src/plugin/provider/togetherai.ts new file mode 100644 index 0000000000..b1870f2662 --- /dev/null +++ b/packages/core/src/plugin/provider/togetherai.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const TogetherAIPlugin = PluginV2.define({ + id: PluginV2.ID.make("togetherai"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/togetherai") return + const mod = yield* Effect.promise(() => import("@ai-sdk/togetherai")) + evt.sdk = mod.createTogetherAI(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/venice.ts b/packages/core/src/plugin/provider/venice.ts new file mode 100644 index 0000000000..8a3b950245 --- /dev/null +++ b/packages/core/src/plugin/provider/venice.ts @@ -0,0 +1,15 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" + +export const VenicePlugin = PluginV2.define({ + id: PluginV2.ID.make("venice"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "venice-ai-sdk-provider") return + const mod = yield* Effect.promise(() => import("venice-ai-sdk-provider")) + evt.sdk = mod.createVenice(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/vercel.ts b/packages/core/src/plugin/provider/vercel.ts new file mode 100644 index 0000000000..2108542b16 --- /dev/null +++ b/packages/core/src/plugin/provider/vercel.ts @@ -0,0 +1,21 @@ +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" + }), + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/vercel") return + const mod = yield* Effect.promise(() => import("@ai-sdk/vercel")) + evt.sdk = mod.createVercel(evt.options) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/xai.ts b/packages/core/src/plugin/provider/xai.ts new file mode 100644 index 0000000000..b54aa7374c --- /dev/null +++ b/packages/core/src/plugin/provider/xai.ts @@ -0,0 +1,20 @@ +import { Effect } from "effect" +import { PluginV2 } from "../../plugin" +import { ProviderV2 } from "../../provider" + +export const XAIPlugin = PluginV2.define({ + id: PluginV2.ID.make("xai"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (evt.package !== "@ai-sdk/xai") return + const mod = yield* Effect.promise(() => import("@ai-sdk/xai")) + evt.sdk = mod.createXai(evt.options) + }), + "aisdk.language": Effect.fn(function* (evt) { + if (evt.model.providerID !== ProviderV2.ID.make("xai")) return + evt.language = evt.sdk.responses(evt.model.apiID) + }), + } + }), +}) diff --git a/packages/core/src/plugin/provider/zenmux.ts b/packages/core/src/plugin/provider/zenmux.ts new file mode 100644 index 0000000000..6bdd426010 --- /dev/null +++ b/packages/core/src/plugin/provider/zenmux.ts @@ -0,0 +1,16 @@ +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" + }), + } + }), +}) diff --git a/packages/core/src/process.ts b/packages/core/src/process.ts new file mode 100644 index 0000000000..76ea9cf3f0 --- /dev/null +++ b/packages/core/src/process.ts @@ -0,0 +1,232 @@ +import { Context, Duration, Effect, Fiber, Layer, Schema, Stream } from "effect" +import type { PlatformError } from "effect/PlatformError" +import { ChildProcess } from "effect/unstable/process" +import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner" +import { CrossSpawnSpawner } from "./cross-spawn-spawner" + +export class AppProcessError extends Schema.TaggedErrorClass()("AppProcessError", { + command: Schema.String, + exitCode: Schema.optional(Schema.Number), + stderr: Schema.optional(Schema.String), + cause: Schema.optional(Schema.Defect), +}) {} + +export interface RunOptions { + readonly maxOutputBytes?: number + readonly maxErrorBytes?: number + readonly signal?: AbortSignal + readonly timeout?: Duration.Input + readonly stdin?: string | Uint8Array | Stream.Stream +} + +export interface RunStreamOptions { + readonly signal?: AbortSignal + readonly includeStderr?: boolean + readonly okExitCodes?: ReadonlyArray + readonly maxErrorBytes?: number +} + +export interface RunResult { + readonly command: string + readonly exitCode: number + readonly stdout: Buffer + readonly stderr: Buffer + readonly truncated: boolean +} + +export type Interface = ChildProcessSpawner["Service"] & { + readonly run: (command: ChildProcess.Command, options?: RunOptions) => Effect.Effect + readonly runStream: ( + command: ChildProcess.Command, + options?: RunStreamOptions, + ) => Stream.Stream +} + +export class Service extends Context.Service()("@opencode/AppProcess") {} + +export const requireSuccess = (result: RunResult): Effect.Effect => + result.exitCode === 0 + ? Effect.succeed(result) + : Effect.fail( + new AppProcessError({ + command: result.command, + exitCode: result.exitCode, + stderr: result.stderr.toString("utf8"), + }), + ) + +export const requireExitIn = + (codes: ReadonlyArray) => + (result: RunResult): Effect.Effect => + codes.includes(result.exitCode) + ? Effect.succeed(result) + : Effect.fail( + new AppProcessError({ + command: result.command, + exitCode: result.exitCode, + stderr: result.stderr.toString("utf8"), + }), + ) + +const describeCommand = (command: ChildProcess.Command): string => { + if (command._tag === "StandardCommand") { + return command.args.length ? `${command.command} ${command.args.join(" ")}` : command.command + } + return `${describeCommand(command.left)} | ${describeCommand(command.right)}` +} + +const wrapError = (description: string, cause: unknown): AppProcessError => + cause instanceof AppProcessError ? cause : new AppProcessError({ command: description, cause }) + +const abortError = (signal: AbortSignal): Error => { + const reason = signal.reason + if (reason instanceof Error) return reason + const err = new Error("Aborted") + err.name = "AbortError" + return err +} + +const waitForAbort = (signal: AbortSignal) => + Effect.callback((resume) => { + if (signal.aborted) { + resume(Effect.fail(abortError(signal))) + return + } + const onabort = () => resume(Effect.fail(abortError(signal))) + signal.addEventListener("abort", onabort, { once: true }) + return Effect.sync(() => signal.removeEventListener("abort", onabort)) + }) + +const normalizeStdin = ( + input: string | Uint8Array | Stream.Stream, +): Stream.Stream => + typeof input === "string" + ? Stream.make(new TextEncoder().encode(input)) + : input instanceof Uint8Array + ? Stream.make(input) + : input + +const collectStream = (stream: Stream.Stream, maxOutputBytes: number | undefined) => + Stream.runFold( + stream, + () => ({ chunks: [] as Uint8Array[], bytes: 0, truncated: false }), + (acc, chunk) => { + if (maxOutputBytes === undefined) { + acc.chunks.push(chunk) + acc.bytes += chunk.length + return acc + } + const remaining = maxOutputBytes - acc.bytes + if (remaining > 0) acc.chunks.push(remaining >= chunk.length ? chunk : chunk.slice(0, remaining)) + acc.bytes += chunk.length + acc.truncated = acc.truncated || acc.bytes > maxOutputBytes + return acc + }, + ).pipe(Effect.map((x) => ({ buffer: Buffer.concat(x.chunks), truncated: x.truncated }))) + +export const layer = Layer.effect( + Service, + Effect.gen(function* () { + const spawner = yield* ChildProcessSpawner + + const runCommand = (command: ChildProcess.Command, options?: RunOptions) => { + const description = describeCommand(command) + const collect = Effect.scoped( + Effect.gen(function* () { + const handle = yield* spawner.spawn(command) + const [stdout, stderr, exitCode] = yield* Effect.all( + [ + collectStream(handle.stdout, options?.maxOutputBytes), + collectStream(handle.stderr, options?.maxErrorBytes), + handle.exitCode, + ], + { concurrency: "unbounded" }, + ) + return { + command: description, + exitCode, + stdout: stdout.buffer, + stderr: stderr.buffer, + truncated: stdout.truncated, + } satisfies RunResult + }), + ) + const timed = options?.timeout + ? Effect.timeoutOrElse(collect, { + duration: options.timeout, + orElse: () => Effect.fail(new AppProcessError({ command: description, cause: new Error("Timed out") })), + }) + : collect + const aborted = options?.signal + ? timed.pipe( + Effect.raceFirst( + waitForAbort(options.signal).pipe(Effect.mapError((cause) => wrapError(description, cause))), + ), + ) + : timed + return aborted.pipe(Effect.catch((cause) => Effect.fail(wrapError(description, cause)))) + } + + const run = Effect.fn("AppProcess.run")(function* (command: ChildProcess.Command, options?: RunOptions) { + if (options?.stdin === undefined) return yield* runCommand(command, options) + if (command._tag !== "StandardCommand") { + return yield* new AppProcessError({ + command: describeCommand(command), + cause: new Error("stdin option only supports StandardCommand; received PipedCommand"), + }) + } + const next = ChildProcess.make(command.command, command.args, { + ...command.options, + stdin: normalizeStdin(options.stdin), + }) + return yield* runCommand(next, options) + }) + + const runStream = ( + command: ChildProcess.Command, + options?: RunStreamOptions, + ): Stream.Stream => { + const description = describeCommand(command) + const okExitCodes = options?.okExitCodes + const built: Stream.Stream = Stream.unwrap( + Effect.gen(function* () { + const handle = yield* spawner.spawn(command) + const stderrFiber = yield* Effect.forkScoped( + collectStream(handle.stderr, options?.maxErrorBytes).pipe(Effect.map((x) => x.buffer.toString("utf8"))), + ) + const source = options?.includeStderr === true ? handle.all : handle.stdout + const lines = source.pipe( + Stream.decodeText, + Stream.splitLines, + Stream.filter((line) => line.length > 0), + ) + const tail = Stream.unwrap( + Effect.gen(function* () { + const code = yield* handle.exitCode + if (okExitCodes && okExitCodes.length > 0 && !okExitCodes.includes(code)) { + const stderr = yield* Fiber.join(stderrFiber) + return Stream.fail(new AppProcessError({ command: description, exitCode: code, stderr })) + } + return Stream.empty + }), + ) + return Stream.concat(lines, tail) as Stream.Stream + }), + ) + const mapped = built.pipe( + Stream.catch((cause): Stream.Stream => Stream.fail(wrapError(description, cause))), + ) + if (!options?.signal) return mapped + const signal = options.signal + return mapped.pipe( + Stream.interruptWhen(waitForAbort(signal).pipe(Effect.mapError((cause) => wrapError(description, cause)))), + ) + } + + return Service.of({ ...spawner, run, runStream }) + }), +) + +export const defaultLayer = layer.pipe(Layer.provide(CrossSpawnSpawner.defaultLayer)) + +export * as AppProcess from "./process" diff --git a/packages/core/src/provider.ts b/packages/core/src/provider.ts new file mode 100644 index 0000000000..7c1c966654 --- /dev/null +++ b/packages/core/src/provider.ts @@ -0,0 +1,120 @@ +export * as ProviderV2 from "./provider" + +import { withStatics } from "./schema" +import { Schema } from "effect" + +export const ID = Schema.String.pipe( + Schema.brand("ProviderV2.ID"), + withStatics((schema) => ({ + // Well-known providers + opencode: schema.make("opencode"), + anthropic: schema.make("anthropic"), + openai: schema.make("openai"), + google: schema.make("google"), + googleVertex: schema.make("google-vertex"), + githubCopilot: schema.make("github-copilot"), + amazonBedrock: schema.make("amazon-bedrock"), + azure: schema.make("azure"), + openrouter: schema.make("openrouter"), + mistral: schema.make("mistral"), + gitlab: schema.make("gitlab"), + })), +) +export type ID = typeof ID.Type + +const OpenAIResponses = Schema.Struct({ + type: Schema.Literal("openai/responses"), + url: Schema.String, + websocket: Schema.optional(Schema.Boolean), +}) + +const OpenAICompletions = Schema.Struct({ + type: Schema.Literal("openai/completions"), + url: Schema.String, + reasoning: Schema.Union([ + Schema.Struct({ + type: Schema.Literal("reasoning_content"), + }), + Schema.Struct({ + type: Schema.Literal("reasoning_details"), + }), + ]).pipe(Schema.optional), +}) +export type OpenAICompletions = typeof OpenAICompletions.Type + +const AISDK = Schema.Struct({ + type: Schema.Literal("aisdk"), + package: Schema.String, + url: Schema.String.pipe(Schema.optional), +}) + +const AnthropicMessages = Schema.Struct({ + type: Schema.Literal("anthropic/messages"), + url: Schema.String, +}) + +const UnknownEndpoint = Schema.Struct({ + type: Schema.Literal("unknown"), +}) + +export const Endpoint = Schema.Union([ + UnknownEndpoint, + OpenAIResponses, + OpenAICompletions, + AnthropicMessages, + AISDK, +]).pipe(Schema.toTaggedUnion("type")) +export type Endpoint = typeof Endpoint.Type + +export const Options = Schema.Struct({ + headers: Schema.Record(Schema.String, Schema.String), + body: Schema.Record(Schema.String, Schema.Any), + aisdk: Schema.Struct({ + provider: Schema.Record(Schema.String, Schema.Any), + request: Schema.Record(Schema.String, Schema.Any), + }), +}) +export type Options = typeof Options.Type + +export class Info extends Schema.Class("ProviderV2.Info")({ + id: ID, + name: Schema.String, + enabled: Schema.Union([ + Schema.Literal(false), + Schema.Struct({ + via: Schema.Literal("env"), + name: Schema.String, + }), + Schema.Struct({ + via: Schema.Literal("auth"), + service: Schema.String, + }), + Schema.Struct({ + via: Schema.Literal("custom"), + data: Schema.Record(Schema.String, Schema.Any), + }), + ]), + env: Schema.String.pipe(Schema.Array), + endpoint: Endpoint, + options: Options, +}) { + static empty(providerID: ID) { + return new Info({ + id: providerID, + name: providerID, + enabled: false, + env: [], + endpoint: { + type: "unknown", + }, + options: { + headers: {}, + body: {}, + aisdk: { + provider: {}, + request: {}, + }, + }, + }) + } +} diff --git a/packages/opencode/src/v2/session-prompt.ts b/packages/core/src/session-prompt.ts similarity index 100% rename from packages/opencode/src/v2/session-prompt.ts rename to packages/core/src/session-prompt.ts diff --git a/packages/opencode/src/v2/tool-output.ts b/packages/core/src/tool-output.ts similarity index 100% rename from packages/opencode/src/v2/tool-output.ts rename to packages/core/src/tool-output.ts diff --git a/packages/core/src/util/error.ts b/packages/core/src/util/error.ts index 9d3b7c661a..7338571f29 100644 --- a/packages/core/src/util/error.ts +++ b/packages/core/src/util/error.ts @@ -1,8 +1,8 @@ -import z from "zod" +import { Schema } from "effect" export abstract class NamedError extends Error { - abstract schema(): z.core.$ZodType - abstract toObject(): { name: string; data: any } + abstract schema(): Schema.Top + abstract toObject(): { name: string; data: unknown } static hasName(error: unknown, name: string): boolean { return ( @@ -10,30 +10,42 @@ export abstract class NamedError extends Error { ) } - static create(name: Name, data: Data) { - const schema = z - .object({ - name: z.literal(name), - data, - }) - .meta({ - ref: name, - }) + static create( + name: Name, + fields: Fields, + ): ReturnType>> + static create( + name: Name, + data: DataSchema, + ): ReturnType> + static create(name: Name, data: Schema.Top | Schema.Struct.Fields) { + return NamedError.createSchemaClass(name, Schema.isSchema(data) ? data : Schema.Struct(data)) + } + + private static createSchemaClass(name: Name, data: DataSchema) { + const schema = Schema.Struct({ + name: Schema.Literal(name), + data, + }).annotate({ identifier: name }) + type Data = Schema.Schema.Type + const result = class extends NamedError { public static readonly Schema = schema + public static readonly EffectSchema = schema + public static readonly tag = name - public override readonly name = name as Name + public override readonly name = name constructor( - public readonly data: z.input, + public readonly data: Data, options?: ErrorOptions, ) { super(name, options) this.name = name } - static isInstance(input: any): input is InstanceType { - return typeof input === "object" && "name" in input && input.name === name + static isInstance(input: unknown): input is InstanceType { + return NamedError.hasName(input, name) } schema() { @@ -51,10 +63,7 @@ export abstract class NamedError extends Error { return result } - public static readonly Unknown = NamedError.create( - "UnknownError", - z.object({ - message: z.string(), - }), - ) + public static readonly Unknown = NamedError.create("UnknownError", { + message: Schema.String, + }) } diff --git a/packages/core/src/util/fn.ts b/packages/core/src/util/fn.ts deleted file mode 100644 index 9efe4622fc..0000000000 --- a/packages/core/src/util/fn.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { z } from "zod" - -export function fn(schema: T, cb: (input: z.infer) => Result) { - const result = (input: z.infer) => { - const parsed = schema.parse(input) - return cb(parsed) - } - result.force = (input: z.infer) => cb(input) - result.schema = schema - return result -} diff --git a/packages/core/src/util/log.ts b/packages/core/src/util/log.ts index e1962aed4c..83060b29c6 100644 --- a/packages/core/src/util/log.ts +++ b/packages/core/src/util/log.ts @@ -4,11 +4,14 @@ import path from "path" import fs from "fs/promises" import { createWriteStream } from "fs" import * as Global from "../global" -import z from "zod" +import { Schema } from "effect" import { Glob } from "./glob" -export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" }) -export type Level = z.infer +export const Level = Schema.Literals(["DEBUG", "INFO", "WARN", "ERROR"]).annotate({ + identifier: "LogLevel", + description: "Log level", +}) +export type Level = Schema.Schema.Type const levelPriority: Record = { DEBUG: 0, diff --git a/packages/opencode/src/v2/schema.ts b/packages/core/src/v2-schema.ts similarity index 88% rename from packages/opencode/src/v2/schema.ts rename to packages/core/src/v2-schema.ts index 44587b838a..a34b0b1516 100644 --- a/packages/opencode/src/v2/schema.ts +++ b/packages/core/src/v2-schema.ts @@ -7,4 +7,4 @@ export const DateTimeUtcFromMillis = Schema.Finite.pipe( }), ) -export * as V2Schema from "./schema" +export * as V2Schema from "./v2-schema" diff --git a/packages/opencode/test/provider/copilot/convert-to-copilot-messages.test.ts b/packages/core/test/github-copilot/convert-to-copilot-messages.test.ts similarity index 99% rename from packages/opencode/test/provider/copilot/convert-to-copilot-messages.test.ts rename to packages/core/test/github-copilot/convert-to-copilot-messages.test.ts index 6f874db6d2..65f4b6a536 100644 --- a/packages/opencode/test/provider/copilot/convert-to-copilot-messages.test.ts +++ b/packages/core/test/github-copilot/convert-to-copilot-messages.test.ts @@ -1,4 +1,4 @@ -import { convertToOpenAICompatibleChatMessages as convertToCopilotMessages } from "@/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages" +import { convertToOpenAICompatibleChatMessages as convertToCopilotMessages } from "@opencode-ai/core/github-copilot/chat/convert-to-openai-compatible-chat-messages" import { describe, test, expect } from "bun:test" describe("system messages", () => { diff --git a/packages/opencode/test/provider/copilot/copilot-chat-model.test.ts b/packages/core/test/github-copilot/copilot-chat-model.test.ts similarity index 99% rename from packages/opencode/test/provider/copilot/copilot-chat-model.test.ts rename to packages/core/test/github-copilot/copilot-chat-model.test.ts index 389a72bb37..bc1e2ecd95 100644 --- a/packages/opencode/test/provider/copilot/copilot-chat-model.test.ts +++ b/packages/core/test/github-copilot/copilot-chat-model.test.ts @@ -1,4 +1,4 @@ -import { OpenAICompatibleChatLanguageModel } from "@/provider/sdk/copilot/chat/openai-compatible-chat-language-model" +import { OpenAICompatibleChatLanguageModel } from "@opencode-ai/core/github-copilot/chat/openai-compatible-chat-language-model" import { describe, test, expect, mock } from "bun:test" import type { LanguageModelV3Prompt } from "@ai-sdk/provider" diff --git a/packages/core/test/plugin/provider-github-copilot.test.ts b/packages/core/test/plugin/provider-github-copilot.test.ts new file mode 100644 index 0000000000..c825f7b8ec --- /dev/null +++ b/packages/core/test/plugin/provider-github-copilot.test.ts @@ -0,0 +1,188 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +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 { fakeSelectorSdk, it, model } from "../v2/plugin/provider-helper" + +describe("GithubCopilotPlugin", () => { + it.effect("creates the bundled Copilot SDK for the GitHub Copilot package", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GithubCopilotPlugin) + const ignored = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("github-copilot", "gpt-5"), + package: "@ai-sdk/openai-compatible", + options: { name: "github-copilot" }, + }, + {}, + ) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("github-copilot", "gpt-5"), + package: "@ai-sdk/github-copilot", + options: { name: "github-copilot" }, + }, + {}, + ) + expect(ignored.sdk).toBeUndefined() + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("selects languageModel when responses and chat are absent", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(GithubCopilotPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("github-copilot", "claude-sonnet-4"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: {}, + }, + {}, + ) + expect(calls).toEqual(["languageModel:claude-sonnet-4"]) + }), + ) + + it.effect("selects languageModel with the API model ID when responses and chat are absent", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(GithubCopilotPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("github-copilot", "alias", { apiID: ModelV2.ID.make("claude-sonnet-4") }), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: {}, + }, + {}, + ) + expect(calls).toEqual(["languageModel:claude-sonnet-4"]) + }), + ) + + it.effect("uses responses for gpt-5 models except gpt-5-mini", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(GithubCopilotPlugin) + yield* plugin.trigger( + "aisdk.language", + { model: model("github-copilot", "gpt-5"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { model: model("github-copilot", "gpt-5.1-codex"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { model: model("github-copilot", "gpt-4o"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { model: model("github-copilot", "gpt-5-mini"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { model: model("github-copilot", "gpt-5-mini-2025-08-07"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + expect(calls).toEqual([ + "responses:gpt-5", + "responses:gpt-5.1-codex", + "chat:gpt-4o", + "chat:gpt-5-mini", + "chat:gpt-5-mini-2025-08-07", + ]) + }), + ) + + it.effect("uses the API model ID when selecting responses or chat", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(GithubCopilotPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("github-copilot", "default", { apiID: ModelV2.ID.make("gpt-5") }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { + model: model("github-copilot", "small", { apiID: ModelV2.ID.make("gpt-5-mini") }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { + model: model("github-copilot", "sonnet", { apiID: ModelV2.ID.make("claude-sonnet-4") }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + expect(calls).toEqual(["responses:gpt-5", "chat:gpt-5-mini", "chat:claude-sonnet-4"]) + }), + ) + + it.effect("filters gpt-5-chat-latest before Copilot language selection", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ) + + it.effect("does not filter gpt-5-chat-latest for non-Copilot providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ) + + it.effect("ignores non-Copilot providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(GithubCopilotPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { model: model("openai", "gpt-5"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + expect(calls).toEqual([]) + expect(result.language).toBeUndefined() + }), + ) +}) diff --git a/packages/core/test/process/process.test.ts b/packages/core/test/process/process.test.ts new file mode 100644 index 0000000000..5cc73e6169 --- /dev/null +++ b/packages/core/test/process/process.test.ts @@ -0,0 +1,277 @@ +import { describe, expect } from "bun:test" +import { realpathSync } from "node:fs" +import { tmpdir } from "node:os" +import { Effect, Exit, Stream } from "effect" +import { ChildProcess } from "effect/unstable/process" +import { AppProcess } from "@opencode-ai/core/process" +import { testEffect } from "../lib/effect" + +const it = testEffect(AppProcess.defaultLayer) + +const NODE = process.execPath +const cmd = (...args: string[]) => ChildProcess.make(NODE, args) + +describe("AppProcess", () => { + describe("run", () => { + it.effect( + "captures stdout and exit code zero", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc.run(cmd("-e", "process.stdout.write('hi\\n')")) + expect(result.exitCode).toBe(0) + expect(result.stdout.toString("utf8")).toBe("hi\n") + expect(result.truncated).toBe(false) + }), + ) + + it.effect( + "non-zero exit returns RunResult; caller can require success", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc.run(cmd("-e", "process.exit(1)")) + expect(result.exitCode).toBe(1) + }), + ) + + it.effect( + "requireSuccess fails on non-zero exit", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const exit = yield* Effect.exit( + svc.run(cmd("-e", "process.exit(1)")).pipe(Effect.flatMap(AppProcess.requireSuccess)), + ) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const reason = exit.cause.reasons[0] + if (reason && reason._tag === "Fail") { + expect(reason.error).toBeInstanceOf(AppProcess.AppProcessError) + expect((reason.error as AppProcess.AppProcessError).exitCode).toBe(1) + } else { + throw new Error("expected fail reason") + } + } + }), + ) + + it.effect( + "requireSuccess succeeds on exit 0", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc.run(cmd("-e", "process.exit(0)")).pipe(Effect.flatMap(AppProcess.requireSuccess)) + expect(result.exitCode).toBe(0) + }), + ) + + it.effect( + "requireExitIn allowlists multiple exit codes", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const requireZeroOrOne = AppProcess.requireExitIn([0, 1]) + const okZero = yield* svc.run(cmd("-e", "process.exit(0)")).pipe(Effect.flatMap(requireZeroOrOne)) + expect(okZero.exitCode).toBe(0) + const okOne = yield* svc.run(cmd("-e", "process.exit(1)")).pipe(Effect.flatMap(requireZeroOrOne)) + expect(okOne.exitCode).toBe(1) + const exit = yield* Effect.exit(svc.run(cmd("-e", "process.exit(2)")).pipe(Effect.flatMap(requireZeroOrOne))) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const reason = exit.cause.reasons[0] + if (reason && reason._tag === "Fail") { + expect(reason.error).toBeInstanceOf(AppProcess.AppProcessError) + expect((reason.error as AppProcess.AppProcessError).exitCode).toBe(2) + } + } + }), + ) + + it.effect( + "truncates output when maxOutputBytes is set", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc.run(cmd("-e", "process.stdout.write('0123456789')"), { maxOutputBytes: 5 }) + expect(result.exitCode).toBe(0) + expect(result.truncated).toBe(true) + expect(result.stdout.length).toBe(5) + expect(result.stdout.toString("utf8")).toBe("01234") + }), + ) + + it.effect( + "result includes command description", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc.run(cmd("-e", "process.stdout.write('hi')")) + expect(result.command).toBe(`${NODE} -e process.stdout.write('hi')`) + }), + ) + }) + + describe("inherited platform methods", () => { + it.effect( + "string returns stdout as string", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const out = yield* svc.string(cmd("-e", "process.stdout.write('hi\\n')")) + expect(out).toBe("hi\n") + }), + ) + + it.effect( + "lines returns the platform's array of lines", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const out = yield* svc.lines(cmd("-e", "process.stdout.write('a\\nb\\n')")) + expect(Array.from(out)).toEqual(["a", "b"]) + }), + ) + }) + + describe("run with stdin option", () => { + const echoStdin = "process.stdin.on('data', c => process.stdout.write(c))" + + it.effect( + "feeds a string to stdin and returns it on stdout", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc.run(cmd("-e", echoStdin), { stdin: "hello" }) + expect(result.exitCode).toBe(0) + expect(result.stdout.toString("utf8")).toBe("hello") + }), + ) + + it.effect( + "feeds a Uint8Array to stdin", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const bytes = new TextEncoder().encode("bytes") + const result = yield* svc.run(cmd("-e", echoStdin), { stdin: bytes }) + expect(result.exitCode).toBe(0) + expect(result.stdout.toString("utf8")).toBe("bytes") + }), + ) + + it.effect( + "feeds a Stream of Uint8Array chunks to stdin", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const enc = new TextEncoder() + const stream = Stream.fromIterable([enc.encode("one"), enc.encode("-two"), enc.encode("-three")]) + const result = yield* svc.run(cmd("-e", echoStdin), { stdin: stream }) + expect(result.exitCode).toBe(0) + expect(result.stdout.toString("utf8")).toBe("one-two-three") + }), + ) + + it.effect( + "completes correctly with empty input", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc.run(cmd("-e", echoStdin), { stdin: "" }) + expect(result.exitCode).toBe(0) + expect(result.stdout.toString("utf8")).toBe("") + }), + ) + + it.effect( + "carries existing Command options like env", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const script = + "process.stdout.write(process.env.FEED + ':'); process.stdin.on('data', c => process.stdout.write(c))" + const command = ChildProcess.make(NODE, ["-e", script], { env: { FEED: "envset" }, extendEnv: true }) + const result = yield* svc.run(command, { stdin: "payload" }) + expect(result.exitCode).toBe(0) + expect(result.stdout.toString("utf8")).toBe("envset:payload") + }), + ) + + it.effect( + "carries existing Command options like cwd", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const dir = realpathSync(tmpdir()) + const script = + "process.stdout.write(process.cwd() + '|'); process.stdin.on('data', c => process.stdout.write(c))" + const command = ChildProcess.make(NODE, ["-e", script], { cwd: dir }) + const result = yield* svc.run(command, { stdin: "ok" }) + expect(result.exitCode).toBe(0) + const [cwd, stdin] = result.stdout.toString("utf8").split("|") + expect(realpathSync(cwd)).toBe(dir) + expect(stdin).toBe("ok") + }), + ) + }) + + describe("runStream", () => { + it.live( + "emits lines incrementally and ends cleanly on exit 0", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc + .runStream(cmd("-e", "console.log('one'); console.log('two'); console.log('three')")) + .pipe(Stream.runCollect) + expect(Array.from(result)).toEqual(["one", "two", "three"]) + }), + ) + + it.live( + "okExitCodes determines whether a non-zero exit fails the stream", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const allowed = yield* svc + .runStream(cmd("-e", "console.log('only'); process.exit(1)"), { okExitCodes: [0, 1] }) + .pipe(Stream.runCollect) + expect(Array.from(allowed)).toEqual(["only"]) + const exit = yield* Effect.exit( + svc + .runStream(cmd("-e", "console.log('a'); process.exit(2)"), { okExitCodes: [0, 1] }) + .pipe(Stream.runCollect), + ) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const reason = exit.cause.reasons[0] + if (reason && reason._tag === "Fail") { + expect(reason.error).toBeInstanceOf(AppProcess.AppProcessError) + } + } + }), + ) + + it.live( + "without okExitCodes, never fails on exit code", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const result = yield* svc.runStream(cmd("-e", "console.log('only'); process.exit(7)")).pipe(Stream.runCollect) + expect(Array.from(result)).toEqual(["only"]) + }), + ) + + it.live( + "AbortSignal interrupts the stream", + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const controller = new AbortController() + controller.abort() + const exit = yield* Effect.exit( + svc + .runStream(cmd("-e", "setInterval(() => {}, 60_000)"), { signal: controller.signal }) + .pipe(Stream.runCollect), + ) + expect(Exit.isFailure(exit)).toBe(true) + }), + ) + }) + + describe("spawn (inherited)", () => { + it.live( + "returns the platform ChildProcessHandle for advanced use", + Effect.scoped( + Effect.gen(function* () { + const svc = yield* AppProcess.Service + const handle = yield* svc.spawn(cmd("-e", "setInterval(() => {}, 1_000)")) + expect(yield* handle.isRunning).toBe(true) + yield* handle.kill() + }), + ), + ) + }) +}) diff --git a/packages/core/test/v2/catalog.test.ts b/packages/core/test/v2/catalog.test.ts new file mode 100644 index 0000000000..cba3405bce --- /dev/null +++ b/packages/core/test/v2/catalog.test.ts @@ -0,0 +1,199 @@ +import { describe, expect } from "bun:test" +import { DateTime, Effect, Layer, Option } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" +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" + +const it = testEffect(Catalog.layer.pipe(Layer.provideMerge(PluginV2.defaultLayer))) + +describe("CatalogV2", () => { + it.effect("normalizes provider baseURL into endpoint url", () => + Effect.gen(function* () { + const catalog = yield* Catalog.Service + const providerID = ProviderV2.ID.make("test") + + 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" + }) + + const provider = yield* catalog.provider.get(providerID) + + expect(provider.endpoint).toEqual({ + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://override.example.com", + }) + expect(provider.options.aisdk.provider.baseURL).toBeUndefined() + }), + ) + + it.effect("normalizes model baseURL into endpoint url", () => + Effect.gen(function* () { + const catalog = yield* Catalog.Service + const providerID = ProviderV2.ID.make("test") + const modelID = ModelV2.ID.make("model") + + 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" + }) + + const model = yield* catalog.model.get(providerID, modelID) + + expect(model.endpoint).toEqual({ + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://override.example.com", + }) + expect(model.options.aisdk.provider.baseURL).toBeUndefined() + }), + ) + + it.effect("resolves unknown model endpoint from provider endpoint", () => + Effect.gen(function* () { + const catalog = yield* Catalog.Service + const providerID = ProviderV2.ID.make("test") + const modelID = ModelV2.ID.make("model") + + 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, () => {}) + + const model = yield* catalog.model.get(providerID, modelID) + + expect(model.endpoint).toEqual({ + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://provider.example.com", + }) + }), + ) + + it.effect("runs provider 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[] = [] + + yield* plugin.add({ + id: PluginV2.ID.make("test"), + effect: Effect.succeed({ + "provider.update": (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) + }), + }), + }) + yield* 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("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") + + 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 + }) + + 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 }) + expect(model.options.aisdk.request).toEqual({ request: true }) + }), + ) + + it.effect("falls back to newest available model when no default is configured", () => + Effect.gen(function* () { + const catalog = yield* Catalog.Service + const providerID = ProviderV2.ID.make("test") + + 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) + }) + + const model = yield* catalog.model.default() + + expect(Option.getOrUndefined(model)?.id).toMatch("new") + }), + ) + + it.effect("small model prefers small keyword candidates before cost scoring", () => + Effect.gen(function* () { + const catalog = yield* Catalog.Service + const providerID = ProviderV2.ID.make("test") + + 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()) + }) + + const model = yield* catalog.model.small(providerID) + + expect(Option.getOrUndefined(model)?.id).toMatch("expensive-mini") + }), + ) +}) diff --git a/packages/core/test/v2/plugin/fixtures/provider-factory.ts b/packages/core/test/v2/plugin/fixtures/provider-factory.ts new file mode 100644 index 0000000000..7278c231dd --- /dev/null +++ b/packages/core/test/v2/plugin/fixtures/provider-factory.ts @@ -0,0 +1,9 @@ +export function createFixtureProvider(options: Record) { + const captured = Object.fromEntries(Object.entries(options)) + return Object.assign((modelID: string) => ({ modelID, options: captured }), { + options: captured, + languageModel(modelID: string) { + return { modelID, options: captured } + }, + }) +} diff --git a/packages/core/test/v2/plugin/provider-alibaba.test.ts b/packages/core/test/v2/plugin/provider-alibaba.test.ts new file mode 100644 index 0000000000..06e6f969fd --- /dev/null +++ b/packages/core/test/v2/plugin/provider-alibaba.test.ts @@ -0,0 +1,67 @@ +import { describe, expect } from "bun:test" +import { createAlibaba } from "@ai-sdk/alibaba" +import { Effect } from "effect" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AlibabaPlugin } from "@opencode-ai/core/plugin/provider/alibaba" +import { it, model } from "./provider-helper" + +describe("AlibabaPlugin", () => { + it.effect("creates an Alibaba SDK for @ai-sdk/alibaba", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AlibabaPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("alibaba", "qwen"), package: "@ai-sdk/alibaba", options: { name: "alibaba" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("ignores non-Alibaba SDK packages", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AlibabaPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("alibaba", "qwen"), package: "@ai-sdk/openai-compatible", options: { name: "alibaba" } }, + {}, + ) + expect(result.sdk).toBeUndefined() + }), + ) + + it.effect("matches the old bundled Alibaba SDK provider naming", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AlibabaPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-alibaba", "qwen"), + package: "@ai-sdk/alibaba", + options: { name: "custom-alibaba", apiKey: "test" }, + }, + {}, + ) + const expected = createAlibaba({ apiKey: "test", ...{ name: "custom-alibaba" } }).languageModel("qwen") + const actual = result.sdk?.languageModel("qwen") + expect(actual?.provider).toBe(expected.provider) + expect(actual?.modelId).toBe(expected.modelId) + }), + ) + + it.effect("uses the old default languageModel(apiID) behavior", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AlibabaPlugin) + const item = model("alibaba", "alias", { apiID: ModelV2.ID.make("qwen-plus") }) + const result = yield* plugin.trigger("aisdk.sdk", { model: item, package: "@ai-sdk/alibaba", options: {} }, {}) + const language = result.sdk?.languageModel(item.apiID) + expect(language?.modelId).toBe("qwen-plus") + expect(language?.provider).toBe("alibaba.chat") + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-amazon-bedrock.test.ts b/packages/core/test/v2/plugin/provider-amazon-bedrock.test.ts new file mode 100644 index 0000000000..c70ada08d9 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-amazon-bedrock.test.ts @@ -0,0 +1,465 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AmazonBedrockPlugin } from "@opencode-ai/core/plugin/provider/amazon-bedrock" +import { fakeSelectorSdk, it, model, provider, withEnv } from "./provider-helper" + +function bedrockBaseURL(sdk: unknown, modelID = "anthropic.claude-sonnet-4-5") { + const language = (sdk as { languageModel: (id: string) => unknown }).languageModel(modelID) + return (language as { config: { baseUrl: () => string } }).config.baseUrl() +} + +function bedrockFetch(sdk: unknown, modelID = "anthropic.claude-sonnet-4-5") { + const language = (sdk as { languageModel: (id: string) => unknown }).languageModel(modelID) + return ( + language as { config: { fetch: (input: Parameters[0], init?: RequestInit) => Promise } } + ).config.fetch +} + +describe("AmazonBedrockPlugin", () => { + it.effect("moves endpoint option to endpoint URL", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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({ + type: "aisdk", + package: "test-provider", + url: "https://bedrock.example", + }) + expect(result.provider.options.aisdk.provider.endpoint).toBeUndefined() + }), + ) + + it.effect("prefers endpoint over baseURL for SDK base URL", () => + withEnv({ AWS_BEARER_TOKEN_BEDROCK: undefined, AWS_PROFILE: undefined, AWS_ACCESS_KEY_ID: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { + name: "amazon-bedrock", + bearerToken: "token", + baseURL: "https://base.example", + endpoint: "https://endpoint.example", + region: "us-east-1", + }, + }, + {}, + ) + expect(bedrockBaseURL(result.sdk)).toBe("https://endpoint.example") + }), + ), + ) + + it.effect("uses baseURL as SDK base URL", () => + withEnv({ AWS_BEARER_TOKEN_BEDROCK: undefined, AWS_PROFILE: undefined, AWS_ACCESS_KEY_ID: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { + name: "amazon-bedrock", + bearerToken: "token", + baseURL: "https://base.example", + region: "us-east-1", + }, + }, + {}, + ) + expect(bedrockBaseURL(result.sdk)).toBe("https://base.example") + }), + ), + ) + + it.effect("creates SDK without explicit credential env so the default AWS chain can resolve credentials", () => + withEnv( + { + AWS_ACCESS_KEY_ID: undefined, + AWS_BEARER_TOKEN_BEDROCK: undefined, + AWS_CONTAINER_CREDENTIALS_FULL_URI: undefined, + AWS_CONTAINER_CREDENTIALS_RELATIVE_URI: undefined, + AWS_PROFILE: undefined, + AWS_REGION: undefined, + AWS_WEB_IDENTITY_TOKEN_FILE: undefined, + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { name: "amazon-bedrock" }, + }, + {}, + ) + expect(result.sdk).toBeDefined() + expect(bedrockBaseURL(result.sdk)).toBe("https://bedrock-runtime.us-east-1.amazonaws.com") + }), + ), + ) + + it.effect("uses config region over AWS_REGION for SDK base URL", () => + withEnv({ AWS_BEARER_TOKEN_BEDROCK: "token", AWS_REGION: "us-east-1" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { name: "amazon-bedrock", region: "eu-west-1" }, + }, + {}, + ) + expect(bedrockBaseURL(result.sdk)).toBe("https://bedrock-runtime.eu-west-1.amazonaws.com") + }), + ), + ) + + it.effect("uses AWS_REGION for SDK base URL when config region is absent", () => + withEnv({ AWS_BEARER_TOKEN_BEDROCK: "token", AWS_REGION: "eu-west-1" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { name: "amazon-bedrock" }, + }, + {}, + ) + expect(bedrockBaseURL(result.sdk)).toBe("https://bedrock-runtime.eu-west-1.amazonaws.com") + }), + ), + ) + + it.effect("defaults SDK region to us-east-1", () => + withEnv({ AWS_BEARER_TOKEN_BEDROCK: "token", AWS_REGION: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { name: "amazon-bedrock" }, + }, + {}, + ) + expect(bedrockBaseURL(result.sdk)).toBe("https://bedrock-runtime.us-east-1.amazonaws.com") + }), + ), + ) + + it.effect("loads bearer token option into env and uses bearer auth", () => + withEnv({ AWS_ACCESS_KEY_ID: undefined, AWS_BEARER_TOKEN_BEDROCK: undefined, AWS_PROFILE: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const headers: Array = [] + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { + name: "amazon-bedrock", + bearerToken: "option-token", + fetch: async (_input: Parameters[0], init?: RequestInit) => { + headers.push(new Headers(init?.headers).get("Authorization")) + return new Response("{}") + }, + }, + }, + {}, + ) + yield* Effect.promise(() => bedrockFetch(result.sdk)("https://bedrock.example", { method: "POST" })) + expect(process.env.AWS_BEARER_TOKEN_BEDROCK).toBe("option-token") + expect(headers).toEqual(["Bearer option-token"]) + }), + ), + ) + + it.effect("prefers bearer token env over bearer token option", () => + withEnv({ AWS_BEARER_TOKEN_BEDROCK: "env-token" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const headers: Array = [] + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { + name: "amazon-bedrock", + bearerToken: "option-token", + fetch: async (_input: Parameters[0], init?: RequestInit) => { + headers.push(new Headers(init?.headers).get("Authorization")) + return new Response("{}") + }, + }, + }, + {}, + ) + yield* Effect.promise(() => bedrockFetch(result.sdk)("https://bedrock.example", { method: "POST" })) + expect(process.env.AWS_BEARER_TOKEN_BEDROCK).toBe("env-token") + expect(headers).toEqual(["Bearer env-token"]) + }), + ), + ) + + it.effect("uses SigV4 credential env when bearer token is absent", () => + withEnv( + { + AWS_ACCESS_KEY_ID: "test-access-key", + AWS_BEARER_TOKEN_BEDROCK: undefined, + AWS_REGION: "us-east-1", + AWS_SECRET_ACCESS_KEY: "test-secret-key", + AWS_SESSION_TOKEN: "test-session-token", + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const headers: Array = [] + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + package: "@ai-sdk/amazon-bedrock", + options: { + name: "amazon-bedrock", + fetch: async (_input: Parameters[0], init?: RequestInit) => { + headers.push(new Headers(init?.headers).get("Authorization")) + return new Response("{}") + }, + }, + }, + {}, + ) + yield* Effect.promise(() => + bedrockFetch(result.sdk)("https://bedrock-runtime.us-east-1.amazonaws.com/model/test/invoke", { + body: "{}", + method: "POST", + }), + ) + expect(headers[0]?.startsWith("AWS4-HMAC-SHA256 ")).toBe(true) + }), + ), + ) + + it.effect("applies legacy cross-region inference prefixes", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AmazonBedrockPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: {}, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: { region: "eu-west-1" }, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { + model: model("amazon-bedrock", "global.anthropic.claude-sonnet-4-5"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: { region: "eu-west-1" }, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: { region: "ap-northeast-1" }, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: { region: "ap-southeast-2" }, + }, + {}, + ) + expect(calls).toEqual([ + "languageModel:us.anthropic.claude-sonnet-4-5", + "languageModel:eu.anthropic.claude-sonnet-4-5", + "languageModel:global.anthropic.claude-sonnet-4-5", + "languageModel:jp.anthropic.claude-sonnet-4-5", + "languageModel:au.anthropic.claude-sonnet-4-5", + ]) + }), + ) + + it.effect("uses AWS_REGION for language prefixes when region option is absent", () => + withEnv({ AWS_REGION: "eu-west-1" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AmazonBedrockPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("amazon-bedrock", "anthropic.claude-sonnet-4-5"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: {}, + }, + {}, + ) + expect(calls).toEqual(["languageModel:eu.anthropic.claude-sonnet-4-5"]) + }), + ), + ) + + it.effect("applies the full legacy cross-region prefix matrix", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + const cases = [ + { region: "us-east-1", modelID: "amazon.nova-micro-v1:0", expected: "us.amazon.nova-micro-v1:0" }, + { region: "us-east-1", modelID: "amazon.nova-lite-v1:0", expected: "us.amazon.nova-lite-v1:0" }, + { region: "us-east-1", modelID: "amazon.nova-pro-v1:0", expected: "us.amazon.nova-pro-v1:0" }, + { region: "us-east-1", modelID: "amazon.nova-premier-v1:0", expected: "us.amazon.nova-premier-v1:0" }, + { region: "us-east-1", modelID: "amazon.nova-2-lite-v1:0", expected: "us.amazon.nova-2-lite-v1:0" }, + { region: "us-east-1", modelID: "anthropic.claude-sonnet-4-5", expected: "us.anthropic.claude-sonnet-4-5" }, + { region: "us-east-1", modelID: "deepseek.r1-v1:0", expected: "us.deepseek.r1-v1:0" }, + { region: "us-gov-west-1", modelID: "anthropic.claude-sonnet-4-5", expected: "anthropic.claude-sonnet-4-5" }, + { region: "us-east-1", modelID: "cohere.command-r-plus-v1:0", expected: "cohere.command-r-plus-v1:0" }, + { region: "eu-west-1", modelID: "anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, + { region: "eu-west-2", modelID: "amazon.nova-lite-v1:0", expected: "eu.amazon.nova-lite-v1:0" }, + { region: "eu-west-3", modelID: "amazon.nova-micro-v1:0", expected: "eu.amazon.nova-micro-v1:0" }, + { + region: "eu-north-1", + modelID: "meta.llama3-70b-instruct-v1:0", + expected: "eu.meta.llama3-70b-instruct-v1:0", + }, + { region: "eu-central-1", modelID: "mistral.pixtral-large-v1:0", expected: "eu.mistral.pixtral-large-v1:0" }, + { region: "eu-south-1", modelID: "anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, + { region: "eu-south-2", modelID: "anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, + { region: "eu-central-2", modelID: "anthropic.claude-sonnet-4-5", expected: "anthropic.claude-sonnet-4-5" }, + { region: "eu-west-1", modelID: "cohere.command-r-plus-v1:0", expected: "cohere.command-r-plus-v1:0" }, + { + region: "ap-southeast-2", + modelID: "anthropic.claude-sonnet-4-5", + expected: "au.anthropic.claude-sonnet-4-5", + }, + { + region: "ap-southeast-4", + modelID: "anthropic.claude-haiku-v1:0", + expected: "au.anthropic.claude-haiku-v1:0", + }, + { region: "ap-southeast-2", modelID: "anthropic.claude-opus-4", expected: "apac.anthropic.claude-opus-4" }, + { + region: "ap-northeast-1", + modelID: "anthropic.claude-sonnet-4-5", + expected: "jp.anthropic.claude-sonnet-4-5", + }, + { region: "ap-northeast-1", modelID: "amazon.nova-pro-v1:0", expected: "jp.amazon.nova-pro-v1:0" }, + { region: "ap-south-1", modelID: "anthropic.claude-sonnet-4-5", expected: "apac.anthropic.claude-sonnet-4-5" }, + { region: "ap-south-1", modelID: "amazon.nova-lite-v1:0", expected: "apac.amazon.nova-lite-v1:0" }, + { region: "ca-central-1", modelID: "anthropic.claude-sonnet-4-5", expected: "anthropic.claude-sonnet-4-5" }, + { + region: "us-east-1", + modelID: "global.anthropic.claude-sonnet-4-5", + expected: "global.anthropic.claude-sonnet-4-5", + }, + { region: "us-east-1", modelID: "us.anthropic.claude-sonnet-4-5", expected: "us.anthropic.claude-sonnet-4-5" }, + { region: "eu-west-1", modelID: "eu.anthropic.claude-sonnet-4-5", expected: "eu.anthropic.claude-sonnet-4-5" }, + { + region: "ap-northeast-1", + modelID: "jp.anthropic.claude-sonnet-4-5", + expected: "jp.anthropic.claude-sonnet-4-5", + }, + { + region: "ap-south-1", + modelID: "apac.anthropic.claude-sonnet-4-5", + expected: "apac.anthropic.claude-sonnet-4-5", + }, + { + region: "ap-southeast-2", + modelID: "au.anthropic.claude-sonnet-4-5", + expected: "au.anthropic.claude-sonnet-4-5", + }, + ] + yield* plugin.add(AmazonBedrockPlugin) + for (const item of cases) { + yield* plugin.trigger( + "aisdk.language", + { + model: model("amazon-bedrock", item.modelID), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: { region: item.region }, + }, + {}, + ) + } + expect(calls).toEqual(cases.map((item) => `languageModel:${item.expected}`)) + }), + ) + + it.effect("ignores non-Bedrock providers for language selection", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AmazonBedrockPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: model("openai", "anthropic.claude-sonnet-4-5"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: { region: "eu-west-1" }, + }, + {}, + ) + expect(calls).toEqual([]) + expect(result.language).toBeUndefined() + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-anthropic.test.ts b/packages/core/test/v2/plugin/provider-anthropic.test.ts new file mode 100644 index 0000000000..bbea4a3721 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-anthropic.test.ts @@ -0,0 +1,91 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AnthropicPlugin } from "@opencode-ai/core/plugin/provider/anthropic" +import { it, model, provider } from "./provider-helper" + +describe("AnthropicPlugin", () => { + it.effect("applies legacy beta headers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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( + "interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14", + ) + expect(result.provider.options.headers.Existing).toBe("1") + }), + ) + + it.effect("ignores non-Anthropic providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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() + }), + ) + + it.effect("creates Anthropic SDKs with the model provider ID as the SDK name", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const providers: string[] = [] + yield* plugin.add(AnthropicPlugin) + yield* plugin.add({ + id: PluginV2.ID.make("anthropic-sdk-inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + providers.push(evt.sdk.languageModel("claude-sonnet-4-5").provider) + }), + }), + }) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-anthropic", "claude-sonnet-4-5"), + package: "@ai-sdk/anthropic", + options: { name: "custom-anthropic", apiKey: "test" }, + }, + {}, + ) + expect(providers).toEqual(["custom-anthropic"]) + }), + ) + + it.effect("uses the Anthropic provider ID as the SDK name for the bundled Anthropic provider", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const providers: string[] = [] + yield* plugin.add(AnthropicPlugin) + yield* plugin.add({ + id: PluginV2.ID.make("anthropic-sdk-inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + providers.push(evt.sdk.languageModel("claude-sonnet-4-5").provider) + }), + }), + }) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("anthropic", "claude-sonnet-4-5"), + package: "@ai-sdk/anthropic", + options: { name: "anthropic", apiKey: "test" }, + }, + {}, + ) + expect(providers).toEqual(["anthropic"]) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-azure-cognitive-services.test.ts b/packages/core/test/v2/plugin/provider-azure-cognitive-services.test.ts new file mode 100644 index 0000000000..b835cbeeff --- /dev/null +++ b/packages/core/test/v2/plugin/provider-azure-cognitive-services.test.ts @@ -0,0 +1,127 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AzureCognitiveServicesPlugin } from "@opencode-ai/core/plugin/provider/azure" +import { fakeSelectorSdk, it, model, provider, withEnv } from "./provider-helper" + +describe("AzureCognitiveServicesPlugin", () => { + it.effect("maps the resource env var to the Azure SDK baseURL", () => + withEnv({ AZURE_COGNITIVE_SERVICES_RESOURCE_NAME: "cognitive" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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", + }) + expect(result.provider.options.aisdk.provider.baseURL).toBe( + "https://cognitive.cognitiveservices.azure.com/openai", + ) + expect(result.provider.options.aisdk.provider.resourceName).toBeUndefined() + }), + ), + ) + + it.effect("leaves baseURL unset without resource env and ignores other providers", () => + withEnv({ AZURE_COGNITIVE_SERVICES_RESOURCE_NAME: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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" }) + }), + ), + ) + + it.effect("selects chat only for completion URLs", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AzureCognitiveServicesPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("azure-cognitive-services", "deployment"), + sdk: fakeSelectorSdk(calls), + options: { useCompletionUrls: true }, + }, + {}, + ) + expect(calls).toEqual(["chat:deployment"]) + }), + ) + + it.effect("uses the legacy Azure selector order and provider guard", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AzureCognitiveServicesPlugin) + yield* plugin.trigger( + "aisdk.language", + { model: model("azure-cognitive-services", "deployment"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + const ignored = yield* plugin.trigger( + "aisdk.language", + { model: model("openai", "deployment"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + expect(calls).toEqual(["responses:deployment"]) + expect(ignored.language).toBeUndefined() + }), + ) + + it.effect("falls back from responses to messages, chat, then languageModel", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + const sdk = fakeSelectorSdk(calls) + yield* plugin.add(AzureCognitiveServicesPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("azure-cognitive-services", "messages-deployment"), + sdk: { messages: sdk.messages, chat: sdk.chat, languageModel: sdk.languageModel }, + options: {}, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { + model: model("azure-cognitive-services", "chat-deployment"), + sdk: { chat: sdk.chat, languageModel: sdk.languageModel }, + options: {}, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { + model: model("azure-cognitive-services", "language-deployment"), + sdk: { languageModel: sdk.languageModel }, + options: {}, + }, + {}, + ) + expect(calls).toEqual([ + "messages:messages-deployment", + "chat:chat-deployment", + "languageModel:language-deployment", + ]) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-azure.test.ts b/packages/core/test/v2/plugin/provider-azure.test.ts new file mode 100644 index 0000000000..12d8363e73 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-azure.test.ts @@ -0,0 +1,245 @@ +import { describe, expect } from "bun:test" +import { Effect, Layer } from "effect" +import { AuthV2 } from "@opencode-ai/core/auth" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AuthPlugin } from "@opencode-ai/core/plugin/auth" +import { AzurePlugin } from "@opencode-ai/core/plugin/provider/azure" +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)) + +describe("AzurePlugin", () => { + it.effect("resolves resourceName from env", () => + withEnv({ AZURE_RESOURCE_NAME: "from-env" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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") + }), + ), + ) + + it.effect("keeps explicit resourceName over env and ignores other providers", () => + withEnv({ AZURE_RESOURCE_NAME: "from-env" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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 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() + }), + ), + ) + + itWithAuth.effect("prefers auth resourceName over env", () => + withEnv( + { + AZURE_RESOURCE_NAME: "from-env", + }, + () => + 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({ + type: "api", + key: "key", + metadata: { resourceName: "from-auth" }, + }), + active: true, + }) + yield* plugin.add({ + ...AuthPlugin, + effect: AuthPlugin.effect.pipe(Effect.provideService(AuthV2.Service, auth)), + }) + 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") + }), + ), + ) + + it.effect("falls back to env when configured resourceName is blank", () => + withEnv({ AZURE_RESOURCE_NAME: "from-env" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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") + }), + ), + ) + + it.effect("falls back to env when configured resourceName is whitespace", () => + withEnv({ AZURE_RESOURCE_NAME: "from-env" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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") + }), + ), + ) + + it.effect("allows configured baseURL without resourceName", () => + withEnv({ AZURE_RESOURCE_NAME: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AzurePlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("azure", "deployment"), + package: "@ai-sdk/azure", + options: { name: "azure", baseURL: "https://proxy.example.com/openai" }, + }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ), + ) + + it.effect("rejects missing resourceName when baseURL is not configured", () => + withEnv({ AZURE_RESOURCE_NAME: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(AzurePlugin) + const exit = yield* plugin + .trigger( + "aisdk.sdk", + { model: model("azure", "deployment"), package: "@ai-sdk/azure", options: { name: "azure" } }, + {}, + ) + .pipe(Effect.exit) + expect(exit._tag).toBe("Failure") + }), + ), + ) + + it.effect("selects chat only for completion URLs", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AzurePlugin) + yield* plugin.trigger( + "aisdk.language", + { model: model("azure", "deployment"), sdk: fakeSelectorSdk(calls), options: { useCompletionUrls: true } }, + {}, + ) + expect(calls).toEqual(["chat:deployment"]) + }), + ) + + it.effect("selects chat from per-call useCompletionUrls", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AzurePlugin) + yield* plugin.trigger( + "aisdk.language", + { model: model("azure", "deployment"), sdk: fakeSelectorSdk(calls), options: { useCompletionUrls: true } }, + {}, + ) + expect(calls).toEqual(["chat:deployment"]) + }), + ) + + it.effect("ignores model useCompletionUrls when per-call option is unset", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AzurePlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("azure", "deployment", { + options: { headers: {}, body: {}, aisdk: { provider: {}, request: { useCompletionUrls: true } } }, + }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + expect(calls).toEqual(["responses:deployment"]) + }), + ) + + it.effect("uses the legacy Azure selector order and provider guard", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(AzurePlugin) + yield* plugin.trigger( + "aisdk.language", + { model: model("azure", "deployment"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + const ignored = yield* plugin.trigger( + "aisdk.language", + { model: model("openai", "deployment"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + expect(calls).toEqual(["responses:deployment"]) + expect(ignored.language).toBeUndefined() + }), + ) + + it.effect("falls back through the legacy Azure selector order", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + const make = (method: string) => (id: string) => { + calls.push(`${method}:${id}`) + return { modelId: id, provider: method, specificationVersion: "v3" } + } + yield* plugin.add(AzurePlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("azure", "messages-deployment"), + sdk: { messages: make("messages"), chat: make("chat"), languageModel: make("languageModel") }, + options: {}, + }, + {}, + ) + yield* plugin.trigger( + "aisdk.language", + { model: model("azure", "language-deployment"), sdk: { languageModel: make("languageModel") }, options: {} }, + {}, + ) + expect(calls).toEqual(["messages:messages-deployment", "languageModel:language-deployment"]) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-cerebras.test.ts b/packages/core/test/v2/plugin/provider-cerebras.test.ts new file mode 100644 index 0000000000..7270d5367a --- /dev/null +++ b/packages/core/test/v2/plugin/provider-cerebras.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, mock } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { CerebrasPlugin } from "@opencode-ai/core/plugin/provider/cerebras" +import { it, model, provider } from "./provider-helper" + +const cerebrasOptions: Record[] = [] + +void mock.module("@ai-sdk/cerebras", () => ({ + createCerebras: (options: Record) => { + const snapshot = { ...options } + cerebrasOptions.push(snapshot) + return { + languageModel: (modelID: string) => ({ modelID, provider: snapshot.name, specificationVersion: "v3" }), + } + }, +})) + +describe("CerebrasPlugin", () => { + it.effect("applies the legacy integration header", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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" }) + }), + ) + + it.effect("ignores non-Cerebras providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CerebrasPlugin) + const result = yield* plugin.trigger("provider.update", {}, { provider: provider("groq"), cancel: false }) + expect(result.provider.options.headers).toEqual({}) + }), + ) + + it.effect("creates a bundled Cerebras SDK with the model provider ID as the SDK name", () => + Effect.gen(function* () { + cerebrasOptions.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(CerebrasPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-cerebras", "llama-4-scout-17b-16e-instruct"), + package: "@ai-sdk/cerebras", + options: { name: "custom-cerebras", apiKey: "test" }, + }, + {}, + ) + expect(cerebrasOptions).toEqual([{ name: "custom-cerebras", apiKey: "test" }]) + expect(result.sdk.languageModel("llama-4-scout-17b-16e-instruct").provider).toBe("custom-cerebras") + }), + ) + + it.effect("preserves an explicit bundled Cerebras SDK name option", () => + Effect.gen(function* () { + cerebrasOptions.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(CerebrasPlugin) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-cerebras", "llama-4-scout-17b-16e-instruct"), + package: "@ai-sdk/cerebras", + options: { name: "configured-cerebras", apiKey: "test" }, + }, + {}, + ) + expect(cerebrasOptions).toEqual([{ name: "configured-cerebras", apiKey: "test" }]) + }), + ) + + it.effect("ignores non-Cerebras SDK packages", () => + Effect.gen(function* () { + cerebrasOptions.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(CerebrasPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-cerebras", "llama-4-scout-17b-16e-instruct"), + package: "@ai-sdk/groq", + options: { name: "custom-cerebras", apiKey: "test" }, + }, + {}, + ) + expect(cerebrasOptions).toEqual([]) + expect(result.sdk).toBeUndefined() + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-cloudflare-ai-gateway.test.ts b/packages/core/test/v2/plugin/provider-cloudflare-ai-gateway.test.ts new file mode 100644 index 0000000000..72ad5da33f --- /dev/null +++ b/packages/core/test/v2/plugin/provider-cloudflare-ai-gateway.test.ts @@ -0,0 +1,384 @@ +import { describe, expect, mock } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { CloudflareAIGatewayPlugin } from "@opencode-ai/core/plugin/provider/cloudflare-ai-gateway" +import { it, model, withEnv } from "./provider-helper" + +const aiGatewayCalls: Record[] = [] +const unifiedCalls: string[] = [] +const gatewayModelCalls: unknown[] = [] + +function captureAiGatewayOptions(options: Record) { + const nested = + options.options && typeof options.options === "object" ? (options.options as Record) : undefined + return { + ...options, + ...(nested + ? { + options: { + ...nested, + headers: + nested.headers && typeof nested.headers === "object" + ? { ...(nested.headers as Record) } + : nested.headers, + }, + } + : {}), + } +} + +function resetCalls() { + aiGatewayCalls.length = 0 + unifiedCalls.length = 0 + gatewayModelCalls.length = 0 +} + +function cloudflareEnv(overrides: Record = {}) { + return { + CLOUDFLARE_ACCOUNT_ID: "env-account", + CLOUDFLARE_GATEWAY_ID: "env-gateway", + CLOUDFLARE_API_TOKEN: "env-token", + CF_AIG_TOKEN: undefined, + ...overrides, + } +} + +mock.module("ai-gateway-provider", () => ({ + createAiGateway(options: Record) { + aiGatewayCalls.push(captureAiGatewayOptions(options)) + return (input: unknown) => { + gatewayModelCalls.push(input) + return { + modelId: input, + provider: "cloudflare-ai-gateway", + specificationVersion: "v3", + } + } + }, +})) + +mock.module("ai-gateway-provider/providers/unified", () => ({ + createUnified() { + return (modelID: string) => { + unifiedCalls.push(modelID) + return { unifiedModelID: modelID } + } + }, +})) + +describe("CloudflareAIGatewayPlugin", () => { + it.effect("requires account, gateway, and token before creating the unified SDK", () => + withEnv( + { + CLOUDFLARE_ACCOUNT_ID: "acct", + CLOUDFLARE_GATEWAY_ID: "gateway", + CLOUDFLARE_API_TOKEN: "token", + CF_AIG_TOKEN: undefined, + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { name: "cloudflare-ai-gateway" }, + }, + {}, + ) + expect(result.sdk.languageModel("openai/gpt-5")).toBeDefined() + }), + ), + ) + + it.effect("passes legacy metadata, cache, log, and User-Agent values under the AI Gateway options key", () => + withEnv(cloudflareEnv(), () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { + name: "cloudflare-ai-gateway", + metadata: { invoked_by: "test", project: "opencode" }, + cacheTtl: 300, + cacheKey: "cache-key", + skipCache: true, + collectLog: false, + }, + }, + {}, + ) + + expect(aiGatewayCalls).toHaveLength(1) + expect(aiGatewayCalls[0]).toEqual({ + accountId: "env-account", + gateway: "env-gateway", + apiKey: "env-token", + options: { + metadata: { invoked_by: "test", project: "opencode" }, + cacheTtl: 300, + cacheKey: "cache-key", + skipCache: true, + collectLog: false, + headers: { + "User-Agent": expect.stringContaining("opencode/"), + }, + }, + }) + }), + ), + ) + + it.effect("parses legacy cf-aig-metadata header when metadata option is absent", () => + withEnv(cloudflareEnv(), () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { + name: "cloudflare-ai-gateway", + headers: { + "cf-aig-metadata": JSON.stringify({ invoked_by: "header", project: "opencode" }), + }, + }, + }, + {}, + ) + + expect(aiGatewayCalls[0]?.options).toMatchObject({ + metadata: { invoked_by: "header", project: "opencode" }, + }) + }), + ), + ) + + it.effect("prefers Cloudflare env values over auth/config-derived options", () => + withEnv(cloudflareEnv(), () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { + name: "cloudflare-ai-gateway", + accountId: "auth-account", + gateway: "auth-gateway", + apiKey: "auth-token", + }, + }, + {}, + ) + + expect(aiGatewayCalls[0]).toMatchObject({ + accountId: "env-account", + gateway: "env-gateway", + apiKey: "env-token", + }) + }), + ), + ) + + it.effect("accepts gatewayId metadata copied from auth into provider options", () => + withEnv( + cloudflareEnv({ + CLOUDFLARE_ACCOUNT_ID: undefined, + CLOUDFLARE_GATEWAY_ID: undefined, + CLOUDFLARE_API_TOKEN: undefined, + }), + () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { + name: "cloudflare-ai-gateway", + accountId: "auth-account", + gatewayId: "auth-gateway", + apiKey: "auth-token", + }, + }, + {}, + ) + + expect(aiGatewayCalls[0]).toMatchObject({ + accountId: "auth-account", + gateway: "auth-gateway", + apiKey: "auth-token", + }) + }), + ), + ) + + it.effect("falls back to CF_AIG_TOKEN when CLOUDFLARE_API_TOKEN is unset", () => + withEnv(cloudflareEnv({ CLOUDFLARE_API_TOKEN: undefined, CF_AIG_TOKEN: "cf-aig-token" }), () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { name: "cloudflare-ai-gateway" }, + }, + {}, + ) + + expect(aiGatewayCalls[0]).toMatchObject({ apiKey: "cf-aig-token" }) + }), + ), + ) + + it.effect("does not create an SDK when account and gateway IDs are missing", () => + withEnv(cloudflareEnv({ CLOUDFLARE_ACCOUNT_ID: undefined, CLOUDFLARE_GATEWAY_ID: undefined }), () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { name: "cloudflare-ai-gateway" }, + }, + {}, + ) + + expect(result.sdk).toBeUndefined() + expect(aiGatewayCalls).toHaveLength(0) + }), + ), + ) + + it.effect("does not create an SDK when the token is missing", () => + withEnv(cloudflareEnv({ CLOUDFLARE_API_TOKEN: undefined, CF_AIG_TOKEN: undefined }), () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { name: "cloudflare-ai-gateway" }, + }, + {}, + ) + + expect(result.sdk).toBeUndefined() + expect(aiGatewayCalls).toHaveLength(0) + }), + ), + ) + + it.effect("does not replace a configured baseURL with the Cloudflare AI Gateway SDK", () => + withEnv( + cloudflareEnv({ + CLOUDFLARE_ACCOUNT_ID: undefined, + CLOUDFLARE_GATEWAY_ID: undefined, + CLOUDFLARE_API_TOKEN: undefined, + }), + () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "ai-gateway-provider", + options: { name: "cloudflare-ai-gateway", baseURL: "https://proxy.example/v1" }, + }, + {}, + ) + + expect(result.sdk).toBeUndefined() + expect(aiGatewayCalls).toHaveLength(0) + }), + ), + ) + + it.effect("maps provider/model IDs through the unified Cloudflare provider unchanged", () => + withEnv(cloudflareEnv(), () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "anthropic/claude-sonnet-4-5"), + package: "ai-gateway-provider", + options: { name: "cloudflare-ai-gateway" }, + }, + {}, + ) + + expect(result.sdk.languageModel("anthropic/claude-sonnet-4-5")).toEqual({ + modelId: { unifiedModelID: "anthropic/claude-sonnet-4-5" }, + provider: "cloudflare-ai-gateway", + specificationVersion: "v3", + }) + expect(unifiedCalls).toEqual(["anthropic/claude-sonnet-4-5"]) + expect(gatewayModelCalls).toEqual([{ unifiedModelID: "anthropic/claude-sonnet-4-5" }]) + }), + ), + ) + + it.effect("ignores non Cloudflare AI Gateway packages", () => + withEnv(cloudflareEnv(), () => + Effect.gen(function* () { + resetCalls() + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareAIGatewayPlugin) + + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-ai-gateway", "openai/gpt-5"), + package: "@ai-sdk/openai-compatible", + options: { name: "cloudflare-ai-gateway" }, + }, + {}, + ) + + expect(result.sdk).toBeUndefined() + expect(aiGatewayCalls).toHaveLength(0) + }), + ), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-cloudflare-workers-ai.test.ts b/packages/core/test/v2/plugin/provider-cloudflare-workers-ai.test.ts new file mode 100644 index 0000000000..3aed2a17b8 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-cloudflare-workers-ai.test.ts @@ -0,0 +1,267 @@ +import { describe, expect } from "bun:test" +import { Effect, Layer } from "effect" +import { AuthV2 } from "@opencode-ai/core/auth" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AuthPlugin } from "@opencode-ai/core/plugin/auth" +import { CloudflareWorkersAIPlugin } from "@opencode-ai/core/plugin/provider/cloudflare-workers-ai" +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)) + +function cloudflareLanguage(sdk: unknown, modelID = "@cf/model") { + return (sdk as { languageModel: (id: string) => { config: CloudflareConfig; provider: string } }).languageModel( + modelID, + ) +} + +type CloudflareConfig = { + url: (input: { path: string; modelId: string }) => string + headers: () => Record | Promise> +} + +function cloudflareURL(sdk: unknown, modelID = "@cf/model") { + return cloudflareLanguage(sdk, modelID).config.url({ path: "/chat/completions", modelId: modelID }) +} + +function cloudflareHeaders(sdk: unknown, modelID = "@cf/model") { + return cloudflareLanguage(sdk, modelID).config.headers() +} + +describe("CloudflareWorkersAIPlugin", () => { + it.effect("maps account ID to endpoint URL and creates an OpenAI-compatible SDK", () => + withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "key" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareWorkersAIPlugin) + const updated = yield* plugin.trigger( + "provider.update", + {}, + { provider: provider("cloudflare-workers-ai"), cancel: false }, + ) + const sdk = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-workers-ai", "@cf/model", { endpoint: updated.provider.endpoint }), + package: "@ai-sdk/openai-compatible", + options: { name: "cloudflare-workers-ai", headers: { custom: "header" } }, + }, + {}, + ) + expect(updated.provider.endpoint).toEqual({ + type: "aisdk", + package: "test-provider", + url: "https://api.cloudflare.com/client/v4/accounts/acct/ai/v1", + }) + expect(sdk.sdk).toBeDefined() + }), + ), + ) + + it.effect("preserves a configured endpoint URL instead of deriving one from account ID", () => + withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + expect(result.provider.endpoint).toEqual({ + type: "aisdk", + package: "test-provider", + url: "https://proxy.example/v1", + }) + }), + ), + ) + + it.effect("allows a configured baseURL without account ID", () => + withEnv({ CLOUDFLARE_ACCOUNT_ID: undefined, CLOUDFLARE_API_KEY: "key" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareWorkersAIPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-workers-ai", "@cf/model", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://proxy.example/v1" }, + }), + package: "@ai-sdk/openai-compatible", + options: { name: "cloudflare-workers-ai", baseURL: "https://proxy.example/v1" }, + }, + {}, + ) + expect(cloudflareURL(result.sdk)).toBe("https://proxy.example/v1/chat/completions") + }), + ), + ) + + itWithAuth.effect("falls back to auth account metadata when account env is absent", () => + withEnv( + { + CLOUDFLARE_ACCOUNT_ID: undefined, + CLOUDFLARE_API_KEY: undefined, + }, + () => + 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({ + type: "api", + key: "auth-key", + metadata: { accountId: "auth-acct" }, + }), + active: true, + }) + yield* plugin.add({ + ...AuthPlugin, + effect: AuthPlugin.effect.pipe(Effect.provideService(AuthV2.Service, auth)), + }) + yield* plugin.add(CloudflareWorkersAIPlugin) + const updated = yield* plugin.trigger( + "provider.update", + {}, + { provider: provider("cloudflare-workers-ai"), cancel: false }, + ) + expect(updated.provider.endpoint).toEqual({ + type: "aisdk", + package: "test-provider", + url: "https://api.cloudflare.com/client/v4/accounts/auth-acct/ai/v1", + }) + }), + ), + ) + + it.effect("uses env account ID over configured account ID", () => + withEnv({ CLOUDFLARE_ACCOUNT_ID: "env-acct" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + expect(result.provider.endpoint).toEqual({ + type: "aisdk", + package: "test-provider", + url: "https://api.cloudflare.com/client/v4/accounts/env-acct/ai/v1", + }) + }), + ), + ) + + it.effect("uses env API key over auth or configured API key and keeps the Cloudflare User-Agent", () => + withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "env-key" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareWorkersAIPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-workers-ai", "@cf/model", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://proxy.example/v1" }, + }), + package: "@ai-sdk/openai-compatible", + options: { + name: "cloudflare-workers-ai", + apiKey: "auth-key", + baseURL: "https://proxy.example/v1", + headers: { custom: "header" }, + }, + }, + {}, + ) + const headers = yield* Effect.promise(() => Promise.resolve(cloudflareHeaders(result.sdk))) + expect(headers.authorization).toBe("Bearer env-key") + expect(headers.custom).toBe("header") + expect(headers["user-agent"]).toMatch(/^opencode\/.* cloudflare-workers-ai \(.+\) ai-sdk\/openai-compatible\//) + }), + ), + ) + + it.effect("expands account ID vars in endpoint URLs", () => + withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "key" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareWorkersAIPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-workers-ai", "@cf/model", { + endpoint: { + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1", + }, + }), + package: "@ai-sdk/openai-compatible", + options: { + name: "cloudflare-workers-ai", + baseURL: "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1", + }, + }, + {}, + ) + expect(cloudflareURL(result.sdk)).toBe( + "https://api.cloudflare.com/client/v4/accounts/acct/ai/v1/chat/completions", + ) + }), + ), + ) + + it.effect("selects languageModel with the API model ID", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(CloudflareWorkersAIPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: model("cloudflare-workers-ai", "alias", { apiID: ModelV2.ID.make("@cf/api-model") }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + expect(result.language).toBeDefined() + expect(calls).toEqual(["languageModel:@cf/api-model"]) + }), + ) + + it.effect("does not create an SDK for non OpenAI-compatible packages", () => + withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "key" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CloudflareWorkersAIPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-workers-ai", "@cf/model", { + endpoint: { type: "aisdk", package: "@ai-sdk/anthropic", url: "https://proxy.example/v1" }, + }), + package: "@ai-sdk/anthropic", + options: { name: "cloudflare-workers-ai" }, + }, + {}, + ) + expect(result.sdk).toBeUndefined() + }), + ), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-cohere.test.ts b/packages/core/test/v2/plugin/provider-cohere.test.ts new file mode 100644 index 0000000000..54bec2cec4 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-cohere.test.ts @@ -0,0 +1,86 @@ +import { describe, expect, mock } from "bun:test" +import { Effect } from "effect" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { CoherePlugin } from "@opencode-ai/core/plugin/provider/cohere" +import { fakeSelectorSdk, it, model } from "./provider-helper" + +const cohereOptions: Record[] = [] + +void mock.module("@ai-sdk/cohere", () => ({ + createCohere: (options: Record) => { + cohereOptions.push({ ...options }) + return { + languageModel: (modelID: string) => ({ + modelID, + provider: `${options.name ?? "cohere"}.chat`, + specificationVersion: "v3", + }), + } + }, +})) + +describe("CoherePlugin", () => { + it.effect("creates a Cohere SDK only for @ai-sdk/cohere", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CoherePlugin) + + const ignored = yield* plugin.trigger( + "aisdk.sdk", + { model: model("cohere", "command"), package: "@ai-sdk/openai-compatible", options: { name: "cohere" } }, + {}, + ) + expect(ignored.sdk).toBeUndefined() + + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("cohere", "command"), package: "@ai-sdk/cohere", options: { name: "cohere" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("uses the model provider ID as the bundled SDK name", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(CoherePlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-cohere", "command-r-plus"), + package: "@ai-sdk/cohere", + options: { name: "custom-cohere", apiKey: "test", baseURL: "https://cohere.example" }, + }, + {}, + ) + + expect(cohereOptions.at(-1)).toEqual({ + name: "custom-cohere", + apiKey: "test", + baseURL: "https://cohere.example", + }) + expect(result.sdk?.languageModel("command-r-plus").provider).toBe("custom-cohere.chat") + }), + ) + + it.effect("leaves language selection to the default languageModel fallback", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + const sdk = fakeSelectorSdk(calls) + yield* plugin.add(CoherePlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { model: model("cohere", "alias", { apiID: ModelV2.ID.make("command-r-plus") }), sdk, options: {} }, + {}, + ) + + expect(result.language).toBeUndefined() + expect(calls).toEqual([]) + expect(result.language ?? sdk.languageModel("command-r-plus")).toBeDefined() + expect(calls).toEqual(["languageModel:command-r-plus"]) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-deepinfra.test.ts b/packages/core/test/v2/plugin/provider-deepinfra.test.ts new file mode 100644 index 0000000000..1195b8c184 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-deepinfra.test.ts @@ -0,0 +1,129 @@ +import { describe, expect, mock } from "bun:test" +import { Effect, Layer } from "effect" +import { AISDK } from "@opencode-ai/core/aisdk" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { DeepInfraPlugin } from "@opencode-ai/core/plugin/provider/deepinfra" +import { testEffect } from "../../lib/effect" +import { it, model } from "./provider-helper" + +const itAISDK = testEffect(Layer.provideMerge(AISDK.layer, PluginV2.defaultLayer)) +const deepinfraOptions: Record[] = [] +const deepinfraLanguageModels: string[] = [] + +void mock.module("@ai-sdk/deepinfra", () => ({ + createDeepInfra: (options: Record) => { + const captured = { ...options } + deepinfraOptions.push(captured) + return { + languageModel: (modelID: string) => { + deepinfraLanguageModels.push(modelID) + return { modelID, provider: `${captured.name ?? "deepinfra"}.chat`, specificationVersion: "v3" } + }, + } + }, +})) + +function resetDeepInfraMock() { + deepinfraOptions.length = 0 + deepinfraLanguageModels.length = 0 +} + +describe("DeepInfraPlugin", () => { + it.effect("creates a DeepInfra SDK for @ai-sdk/deepinfra", () => + Effect.gen(function* () { + resetDeepInfraMock() + const plugin = yield* PluginV2.Service + yield* plugin.add(DeepInfraPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("deepinfra", "model"), package: "@ai-sdk/deepinfra", options: { name: "deepinfra" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("passes the model provider ID as the bundled DeepInfra SDK name", () => + Effect.gen(function* () { + resetDeepInfraMock() + const plugin = yield* PluginV2.Service + yield* plugin.add(DeepInfraPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-deepinfra", "model"), + package: "@ai-sdk/deepinfra", + options: { name: "custom-deepinfra", apiKey: "test" }, + }, + {}, + ) + expect(result.sdk.languageModel("model").provider).toBe("custom-deepinfra.chat") + expect(deepinfraOptions).toEqual([{ name: "custom-deepinfra", apiKey: "test" }]) + }), + ) + + it.effect("uses the canonical provider ID as the bundled DeepInfra SDK name", () => + Effect.gen(function* () { + resetDeepInfraMock() + const plugin = yield* PluginV2.Service + yield* plugin.add(DeepInfraPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("deepinfra", "model"), + package: "@ai-sdk/deepinfra", + options: { name: "deepinfra", apiKey: "test" }, + }, + {}, + ) + expect(result.sdk.languageModel("model").provider).toBe("deepinfra.chat") + expect(deepinfraOptions).toEqual([{ name: "deepinfra", apiKey: "test" }]) + }), + ) + + it.effect("matches only the exact bundled DeepInfra package", () => + Effect.gen(function* () { + resetDeepInfraMock() + const plugin = yield* PluginV2.Service + yield* plugin.add(DeepInfraPlugin) + const packages = [ + "unmatched-package", + "@ai-sdk/deepinfra-compatible", + "file:///tmp/@ai-sdk/deepinfra-provider.js", + ] + yield* Effect.forEach(packages, (item) => + Effect.gen(function* () { + const ignored = yield* plugin.trigger( + "aisdk.sdk", + { model: model("deepinfra", "model"), package: item, options: { name: "deepinfra" } }, + {}, + ) + expect(ignored.sdk).toBeUndefined() + }), + ) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("deepinfra", "model"), package: "@ai-sdk/deepinfra", options: { name: "deepinfra" } }, + {}, + ) + expect(result.sdk).toBeDefined() + expect(deepinfraOptions).toEqual([{ name: "deepinfra" }]) + }), + ) + + itAISDK.effect("uses the default languageModel selection for DeepInfra models", () => + Effect.gen(function* () { + resetDeepInfraMock() + const plugin = yield* PluginV2.Service + const aisdk = yield* AISDK.Service + yield* plugin.add(DeepInfraPlugin) + const language = yield* aisdk.language( + model("deepinfra", "meta-llama/Llama-3.3-70B-Instruct", { + endpoint: { type: "aisdk", package: "@ai-sdk/deepinfra" }, + }), + ) + expect(language.provider).toBe("deepinfra.chat") + expect(deepinfraLanguageModels).toEqual(["meta-llama/Llama-3.3-70B-Instruct"]) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-dynamic.test.ts b/packages/core/test/v2/plugin/provider-dynamic.test.ts new file mode 100644 index 0000000000..cca331b110 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-dynamic.test.ts @@ -0,0 +1,172 @@ +import { Npm } from "@opencode-ai/core/npm" +import { describe, expect } from "bun:test" +import { Cause, Effect, Layer, Option } from "effect" +import fs from "fs/promises" +import os from "os" +import path from "path" +import { fileURLToPath } from "url" +import { AISDK } from "@opencode-ai/core/aisdk" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { DynamicProviderPlugin } from "@opencode-ai/core/plugin/provider/dynamic" +import { testEffect } from "../../lib/effect" +import { fixtureProvider, it, model, npmLayer } from "./provider-helper" + +const fixtureProviderPath = fileURLToPath(fixtureProvider) +const itWithAISDK = testEffect(AISDK.layer.pipe(Layer.provideMerge(PluginV2.defaultLayer))) + +function npmEntrypointLayer(entrypoint: Option.Option) { + return Layer.succeed( + Npm.Service, + Npm.Service.of({ + add: () => Effect.succeed({ directory: "", entrypoint }), + install: () => Effect.void, + which: () => Effect.succeed(Option.none()), + }), + ) +} + +function dynamicPlugin(layer = npmLayer) { + return { id: DynamicProviderPlugin.id, effect: DynamicProviderPlugin.effect.pipe(Effect.provide(layer)) } +} + +function tempEntrypoint(source: string) { + return Effect.acquireRelease( + Effect.promise(async () => { + const directory = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-provider-dynamic-")) + const entrypoint = path.join(directory, "provider.mjs") + await Bun.write(entrypoint, source) + return { directory, entrypoint } + }), + (tmp) => Effect.promise(() => fs.rm(tmp.directory, { recursive: true, force: true })), + ) +} + +describe("DynamicProviderPlugin", () => { + it.effect("creates an SDK from a provider factory export", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(dynamicPlugin()) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom", "test-model"), + package: fixtureProvider, + options: { name: "custom", marker: "dynamic" }, + }, + {}, + ) + expect(result.sdk.options).toEqual({ marker: "dynamic", name: "custom" }) + expect(result.sdk.languageModel("x")).toEqual({ modelID: "x", options: { marker: "dynamic", name: "custom" } }) + }), + ) + + it.effect("does not override an SDK already supplied by an earlier plugin", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const sdk = { marker: "existing" } + yield* plugin.add(dynamicPlugin()) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom", "test-model"), + package: fixtureProvider, + options: { name: "custom", marker: "dynamic" }, + }, + { sdk }, + ) + expect(result.sdk).toBe(sdk) + }), + ) + + it.effect("injects the provider ID as the SDK factory name", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(dynamicPlugin()) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-provider", "test-model"), + package: fixtureProvider, + options: { name: "custom-provider", marker: "dynamic" }, + }, + {}, + ) + expect(result.sdk.options).toEqual({ marker: "dynamic", name: "custom-provider" }) + }), + ) + + it.effect("loads npm packages through their resolved import entrypoint", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(dynamicPlugin(npmEntrypointLayer(Option.some(fixtureProviderPath)))) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("npm-provider", "test-model"), + package: "fixture-provider", + options: { name: "npm-provider", marker: "npm" }, + }, + {}, + ) + expect(result.sdk.languageModel("x")).toEqual({ modelID: "x", options: { marker: "npm", name: "npm-provider" } }) + }), + ) + + itWithAISDK.effect("wraps missing npm entrypoint failures as AISDK init errors", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const aisdk = yield* AISDK.Service + yield* plugin.add(dynamicPlugin(npmEntrypointLayer(Option.none()))) + const exit = yield* aisdk + .language(model("missing-entrypoint", "alias", { endpoint: { type: "aisdk", package: "fixture-provider" } })) + .pipe(Effect.exit) + expect(exit._tag).toBe("Failure") + if (exit._tag === "Failure") expect(Cause.prettyErrors(exit.cause).join("\n")).toContain("AISDK.InitError") + }), + ) + + itWithAISDK.effect("wraps dynamic import failures as AISDK init errors", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const aisdk = yield* AISDK.Service + yield* plugin.add(dynamicPlugin()) + const exit = yield* aisdk + .language( + model("bad-import", "alias", { endpoint: { type: "aisdk", package: "file:///missing/provider-factory.js" } }), + ) + .pipe(Effect.exit) + expect(exit._tag).toBe("Failure") + if (exit._tag === "Failure") expect(Cause.prettyErrors(exit.cause).join("\n")).toContain("AISDK.InitError") + }), + ) + + itWithAISDK.live("wraps missing provider factory exports as AISDK init errors", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const aisdk = yield* AISDK.Service + const tmp = yield* tempEntrypoint("export const notAProviderFactory = true\n") + yield* plugin.add(dynamicPlugin(npmEntrypointLayer(Option.some(tmp.entrypoint)))) + const exit = yield* aisdk + .language(model("missing-factory", "alias", { endpoint: { type: "aisdk", package: "fixture-provider" } })) + .pipe(Effect.exit) + expect(exit._tag).toBe("Failure") + if (exit._tag === "Failure") expect(Cause.prettyErrors(exit.cause).join("\n")).toContain("AISDK.InitError") + }), + ) + + itWithAISDK.effect("uses the model apiID for the default language model", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const aisdk = yield* AISDK.Service + yield* plugin.add(dynamicPlugin()) + const language = yield* aisdk.language( + model("custom", "alias", { + apiID: ModelV2.ID.make("test-model-api"), + endpoint: { type: "aisdk", package: fixtureProvider }, + }), + ) + expect(language).toMatchObject({ modelID: "test-model-api", options: { name: "custom" } }) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-gateway.test.ts b/packages/core/test/v2/plugin/provider-gateway.test.ts new file mode 100644 index 0000000000..8ee69b7dd4 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-gateway.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, mock } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { GatewayPlugin } from "@opencode-ai/core/plugin/provider/gateway" +import { it, model } from "./provider-helper" + +const gatewayCalls: Record[] = [] +const vercelGatewayModels = ["anthropic/claude-sonnet-4", "openai/gpt-5", "google/gemini-2.5-pro"] + +mock.module("@ai-sdk/gateway", () => ({ + createGateway(options: Record) { + gatewayCalls.push({ ...options }) + return { + languageModel(modelID: string) { + return { + modelId: modelID, + provider: options.name, + specificationVersion: "v3", + } + }, + } + }, +})) + +describe("GatewayPlugin", () => { + it.effect("creates a Gateway SDK for @ai-sdk/gateway", () => + Effect.gen(function* () { + gatewayCalls.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(GatewayPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("gateway", "model"), package: "@ai-sdk/gateway", options: { name: "gateway" } }, + {}, + ) + expect(result.sdk).toBeDefined() + expect(gatewayCalls).toHaveLength(1) + }), + ) + + it.effect("passes the model providerID as the Gateway SDK name", () => + Effect.gen(function* () { + gatewayCalls.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(GatewayPlugin) + + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("vercel", "anthropic/claude-sonnet-4"), + package: "@ai-sdk/gateway", + options: { name: "vercel", apiKey: "test-key" }, + }, + {}, + ) + + expect(gatewayCalls).toEqual([{ name: "vercel", apiKey: "test-key" }]) + expect(result.sdk.languageModel("anthropic/claude-sonnet-4").provider).toBe("vercel") + }), + ) + + it.effect("matches Vercel AI Gateway models by their @ai-sdk/gateway package", () => + Effect.gen(function* () { + gatewayCalls.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(GatewayPlugin) + + for (const modelID of vercelGatewayModels) { + const ignored = yield* plugin.trigger( + "aisdk.sdk", + { model: model("vercel", modelID), package: "@ai-sdk/vercel", options: { name: "vercel" } }, + {}, + ) + expect(ignored.sdk).toBeUndefined() + + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("vercel", modelID), package: "@ai-sdk/gateway", options: { name: "vercel" } }, + {}, + ) + expect(result.sdk).toBeDefined() + } + + expect(gatewayCalls).toHaveLength(3) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-gitlab.test.ts b/packages/core/test/v2/plugin/provider-gitlab.test.ts new file mode 100644 index 0000000000..0b71310e0f --- /dev/null +++ b/packages/core/test/v2/plugin/provider-gitlab.test.ts @@ -0,0 +1,346 @@ +import { describe, expect, mock } from "bun:test" +import { Effect, Layer } from "effect" +import { AuthV2 } from "@opencode-ai/core/auth" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AuthPlugin } from "@opencode-ai/core/plugin/auth" +import { GitLabPlugin } from "@opencode-ai/core/plugin/provider/gitlab" +import { testEffect } from "../../lib/effect" +import { it, model, npmLayer, provider, withEnv } from "./provider-helper" + +const gitlabSDKOptions: Record[] = [] + +void mock.module("gitlab-ai-provider", () => ({ + VERSION: "test-version", + createGitLab: (options: Record) => { + gitlabSDKOptions.push(options) + return { + agenticChat: (id: string, options: unknown) => ({ id, options, type: "agentic" }), + workflowChat: (id: string, options: unknown) => ({ id, options, type: "workflow" }), + } + }, + discoverWorkflowModels: async () => ({ models: [], project: undefined }), + isWorkflowModel: (id: string) => id === "duo-workflow" || id === "duo-workflow-exact", +})) + +const itWithAuth = testEffect(Layer.mergeAll(PluginV2.defaultLayer, AuthV2.defaultLayer, npmLayer)) + +describe("GitLabPlugin", () => { + it.effect("creates SDKs with legacy default instance URL, token env, headers, and feature flags", () => + withEnv( + { + GITLAB_INSTANCE_URL: undefined, + GITLAB_TOKEN: "env-token", + }, + () => + Effect.gen(function* () { + gitlabSDKOptions.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(GitLabPlugin) + yield* plugin.trigger( + "aisdk.sdk", + { model: model("gitlab", "claude"), package: "gitlab-ai-provider", options: { name: "gitlab" } }, + {}, + ) + expect(gitlabSDKOptions).toHaveLength(1) + expect(gitlabSDKOptions[0].instanceUrl).toBe("https://gitlab.com") + expect(gitlabSDKOptions[0].apiKey).toBe("env-token") + expect(gitlabSDKOptions[0].aiGatewayHeaders).toMatchObject({ + "anthropic-beta": "context-1m-2025-08-07", + }) + expect(String((gitlabSDKOptions[0].aiGatewayHeaders as Record)["User-Agent"])).toContain( + "gitlab-ai-provider/test-version", + ) + expect(gitlabSDKOptions[0].featureFlags).toEqual({ + duo_agent_platform_agentic_chat: true, + duo_agent_platform: true, + }) + }), + ), + ) + + it.effect("uses GITLAB_INSTANCE_URL when instanceUrl is not configured", () => + withEnv( + { + GITLAB_INSTANCE_URL: "https://env.gitlab.example", + GITLAB_TOKEN: undefined, + }, + () => + Effect.gen(function* () { + gitlabSDKOptions.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(GitLabPlugin) + yield* plugin.trigger( + "aisdk.sdk", + { model: model("gitlab", "claude"), package: "gitlab-ai-provider", options: { name: "gitlab" } }, + {}, + ) + expect(gitlabSDKOptions[0].instanceUrl).toBe("https://env.gitlab.example") + }), + ), + ) + + it.effect("keeps configured instance URL, apiKey, aiGatewayHeaders, and featureFlags over env/defaults", () => + withEnv( + { + GITLAB_INSTANCE_URL: "https://env.gitlab.example", + GITLAB_TOKEN: "env-token", + }, + () => + Effect.gen(function* () { + gitlabSDKOptions.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(GitLabPlugin) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("gitlab", "claude"), + package: "gitlab-ai-provider", + options: { + name: "gitlab", + instanceUrl: "https://configured.gitlab.example", + apiKey: "configured-token", + aiGatewayHeaders: { + "anthropic-beta": "configured-beta", + "x-gitlab-test": "1", + }, + featureFlags: { + duo_agent_platform: false, + custom_flag: true, + }, + }, + }, + {}, + ) + expect(gitlabSDKOptions[0].instanceUrl).toBe("https://configured.gitlab.example") + expect(gitlabSDKOptions[0].apiKey).toBe("configured-token") + expect(gitlabSDKOptions[0].aiGatewayHeaders).toMatchObject({ + "anthropic-beta": "configured-beta", + "x-gitlab-test": "1", + }) + expect(gitlabSDKOptions[0].featureFlags).toEqual({ + duo_agent_platform_agentic_chat: true, + duo_agent_platform: false, + custom_flag: true, + }) + }), + ), + ) + + it.effect("ignores non-GitLab SDK packages", () => + Effect.gen(function* () { + gitlabSDKOptions.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(GitLabPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("gitlab", "claude"), package: "@ai-sdk/openai", options: { name: "gitlab" } }, + {}, + ) + expect(result.sdk).toBeUndefined() + expect(gitlabSDKOptions).toHaveLength(0) + }), + ) + + itWithAuth.effect("uses active API auth token over GITLAB_TOKEN", () => + withEnv( + { + GITLAB_TOKEN: "env-token", + }, + () => + 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, + }) + yield* plugin.add({ + ...AuthPlugin, + effect: AuthPlugin.effect.pipe(Effect.provideService(AuthV2.Service, auth)), + }) + yield* plugin.add(GitLabPlugin) + const updated = yield* plugin.trigger("provider.update", {}, { provider: provider("gitlab"), cancel: false }) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("gitlab", "claude"), + package: "gitlab-ai-provider", + options: updated.provider.options.aisdk.provider, + }, + {}, + ) + expect(gitlabSDKOptions[0].apiKey).toBe("auth-token") + }), + ), + ) + + itWithAuth.effect("uses active OAuth access token when no API auth exists", () => + withEnv( + { + GITLAB_TOKEN: undefined, + }, + () => + 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({ + type: "oauth", + refresh: "refresh-token", + access: "oauth-token", + expires: 9999999999999, + }), + active: true, + }) + yield* plugin.add({ + ...AuthPlugin, + effect: AuthPlugin.effect.pipe(Effect.provideService(AuthV2.Service, auth)), + }) + yield* plugin.add(GitLabPlugin) + const updated = yield* plugin.trigger("provider.update", {}, { provider: provider("gitlab"), cancel: false }) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("gitlab", "claude"), + package: "gitlab-ai-provider", + options: updated.provider.options.aisdk.provider, + }, + {}, + ) + expect(gitlabSDKOptions[0].apiKey).toBe("oauth-token") + }), + ), + ) + + it.effect("uses workflowChat for duo workflow models and preserves selectedModelRef", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: [string, unknown][] = [] + yield* plugin.add(GitLabPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: model("gitlab", "duo-workflow-custom", { + options: { + headers: {}, + body: {}, + aisdk: { provider: {}, request: { workflowRef: "ref", workflowDefinition: "definition" } }, + }, + }), + sdk: { + workflowChat: (id: string, options: unknown) => { + calls.push([id, options]) + return { id, options } + }, + agenticChat: () => undefined, + }, + options: { featureFlags: { configured: true } }, + }, + {}, + ) + expect(calls).toEqual([ + ["duo-workflow", { featureFlags: { configured: true }, workflowDefinition: "definition" }], + ]) + expect(result.language as unknown).toEqual({ + id: "duo-workflow", + options: calls[0]?.[1], + selectedModelRef: "ref", + }) + }), + ) + + it.effect("uses exact static workflow model ids when the provider recognizes them", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: [string, unknown][] = [] + yield* plugin.add(GitLabPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: model("gitlab", "duo-workflow-exact"), + sdk: { + workflowChat: (id: string, options: unknown) => { + calls.push([id, options]) + return { id, options } + }, + agenticChat: () => undefined, + }, + options: { featureFlags: { configured: true } }, + }, + {}, + ) + expect(calls).toEqual([ + ["duo-workflow-exact", { featureFlags: { configured: true }, workflowDefinition: undefined }], + ]) + expect(result.language as unknown).toEqual({ id: "duo-workflow-exact", options: calls[0]?.[1] }) + }), + ) + + it.effect("uses provider feature flags instead of request feature flags", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: [string, unknown][] = [] + yield* plugin.add(GitLabPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("gitlab", "duo-workflow-custom", { + options: { + headers: {}, + body: {}, + aisdk: { provider: {}, request: { featureFlags: { request_flag: true } } }, + }, + }), + sdk: { + workflowChat: (id: string, options: unknown) => { + calls.push([id, options]) + return { id, options } + }, + agenticChat: () => undefined, + }, + options: { featureFlags: { configured: true } }, + }, + {}, + ) + expect(calls).toEqual([["duo-workflow", { featureFlags: { configured: true }, workflowDefinition: undefined }]]) + }), + ) + + it.effect("uses agenticChat with provider aiGatewayHeaders and feature flags for normal models", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: [string, unknown][] = [] + yield* plugin.add(GitLabPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("gitlab", "claude", { + options: { headers: { h: "v" }, body: {}, aisdk: { provider: {}, request: {} } }, + }), + sdk: { + workflowChat: () => undefined, + agenticChat: (id: string, options: unknown) => { + const selected = options as { + aiGatewayHeaders?: Record + featureFlags?: Record + } + calls.push([ + id, + { aiGatewayHeaders: { ...selected.aiGatewayHeaders }, featureFlags: { ...selected.featureFlags } }, + ]) + }, + }, + options: { aiGatewayHeaders: { fallback: "header" }, featureFlags: { duo_agent_platform: true } }, + }, + {}, + ) + expect(calls).toEqual([ + ["claude", { aiGatewayHeaders: { fallback: "header" }, featureFlags: { duo_agent_platform: true } }], + ]) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-google-vertex-anthropic.test.ts b/packages/core/test/v2/plugin/provider-google-vertex-anthropic.test.ts new file mode 100644 index 0000000000..6bcece53c9 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-google-vertex-anthropic.test.ts @@ -0,0 +1,147 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +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" + +describe("GoogleVertexAnthropicPlugin", () => { + it.effect("resolves legacy project and location env on provider update", () => + withEnv( + { + GOOGLE_CLOUD_PROJECT: "cloud-project", + GCP_PROJECT: "gcp-project", + GCLOUD_PROJECT: "gcloud-project", + GOOGLE_CLOUD_LOCATION: "cloud-location", + VERTEX_LOCATION: "vertex-location", + GOOGLE_VERTEX_LOCATION: "google-vertex-location", + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GoogleVertexAnthropicPlugin) + const result = yield* plugin.trigger( + "provider.update", + {}, + { provider: provider("google-vertex-anthropic"), cancel: false }, + ) + expect(result.provider.options.aisdk.provider.project).toBe("cloud-project") + expect(result.provider.options.aisdk.provider.location).toBe("cloud-location") + }), + ), + ) + + it.effect("keeps configured project and location over env fallback", () => + withEnv({ GOOGLE_CLOUD_PROJECT: "env-project", GOOGLE_CLOUD_LOCATION: "env-location" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + expect(result.provider.options.aisdk.provider.project).toBe("configured-project") + expect(result.provider.options.aisdk.provider.location).toBe("configured-location") + }), + ), + ) + + it.effect("creates SDKs from legacy env fallback and default location", () => + withEnv( + { + GOOGLE_CLOUD_PROJECT: undefined, + GCP_PROJECT: "gcp-project", + GCLOUD_PROJECT: "gcloud-project", + GOOGLE_CLOUD_LOCATION: undefined, + VERTEX_LOCATION: undefined, + GOOGLE_VERTEX_LOCATION: "ignored-location", + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GoogleVertexAnthropicPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("google-vertex-anthropic", "claude-sonnet-4-5"), + package: "@ai-sdk/google-vertex/anthropic", + options: { name: "google-vertex-anthropic" }, + }, + {}, + ) + expect(result.sdk.languageModel("claude-sonnet-4-5").config.baseURL).toBe( + "https://aiplatform.googleapis.com/v1/projects/gcp-project/locations/global/publishers/anthropic/models", + ) + }), + ), + ) + + it.effect("uses GOOGLE_CLOUD_LOCATION before VERTEX_LOCATION when creating SDKs", () => + withEnv( + { GOOGLE_CLOUD_PROJECT: "project", GOOGLE_CLOUD_LOCATION: "cloud-location", VERTEX_LOCATION: "vertex-location" }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GoogleVertexAnthropicPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("google-vertex-anthropic", "claude-sonnet-4-5"), + package: "@ai-sdk/google-vertex/anthropic", + options: { name: "google-vertex-anthropic" }, + }, + {}, + ) + expect(result.sdk.languageModel("claude-sonnet-4-5").config.baseURL).toBe( + "https://cloud-location-aiplatform.googleapis.com/v1/projects/project/locations/cloud-location/publishers/anthropic/models", + ) + }), + ), + ) + + it.effect("trims model IDs before selecting language models", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(GoogleVertexAnthropicPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("google-vertex-anthropic", " claude-sonnet-4-5 "), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: {}, + }, + {}, + ) + expect(calls).toEqual(["languageModel:claude-sonnet-4-5"]) + }), + ) + + it.effect("ignores non Vertex Anthropic providers for language selection", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(GoogleVertexAnthropicPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: model("google-vertex", "claude-sonnet-4-5"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: {}, + }, + {}, + ) + expect(calls).toEqual([]) + expect(result.language).toBeUndefined() + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-google-vertex.test.ts b/packages/core/test/v2/plugin/provider-google-vertex.test.ts new file mode 100644 index 0000000000..3bd60fd721 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-google-vertex.test.ts @@ -0,0 +1,300 @@ +import { describe, expect, mock } from "bun:test" +import { Effect } from "effect" +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" + +const vertexOptions: Record[] = [] + +void mock.module("@ai-sdk/google-vertex", () => ({ + createVertex: (options: Record) => { + vertexOptions.push(options) + return { + languageModel: (modelID: string) => ({ modelID, provider: "google-vertex", specificationVersion: "v3" }), + } + }, +})) + +void mock.module("google-auth-library", () => ({ + GoogleAuth: class { + async getApplicationDefault() { + return { + credential: { + async getAccessToken() { + return { token: "vertex-token" } + }, + }, + } + } + }, +})) + +describe("GoogleVertexPlugin", () => { + it.effect("resolves project and location from env using legacy precedence", () => + withEnv( + { + GOOGLE_CLOUD_PROJECT: "google-cloud-project", + GCP_PROJECT: "gcp-project", + GCLOUD_PROJECT: "gcloud-project", + GOOGLE_VERTEX_LOCATION: "google-vertex-location", + GOOGLE_CLOUD_LOCATION: "google-cloud-location", + VERTEX_LOCATION: "vertex-location", + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + 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({ + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://google-vertex-location-aiplatform.googleapis.com/v1/projects/google-cloud-project/locations/google-vertex-location", + }) + }), + ), + ) + + it.effect("resolves the advertised GOOGLE_VERTEX_PROJECT env for provider updates and SDKs", () => + withEnv( + { + GOOGLE_VERTEX_PROJECT: "vertex-project", + GOOGLE_CLOUD_PROJECT: undefined, + GCP_PROJECT: undefined, + GCLOUD_PROJECT: undefined, + GOOGLE_VERTEX_LOCATION: "europe-west4", + GOOGLE_CLOUD_LOCATION: undefined, + VERTEX_LOCATION: undefined, + }, + () => + Effect.gen(function* () { + vertexOptions.length = 0 + const plugin = yield* PluginV2.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, + }, + ) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("google-vertex", "gemini", { + endpoint: { type: "aisdk", package: "@ai-sdk/google-vertex" }, + }), + package: "@ai-sdk/google-vertex", + options: { name: "google-vertex" }, + }, + {}, + ) + + expect(updated.provider.options.aisdk.provider.project).toBe("vertex-project") + expect(updated.provider.endpoint).toEqual({ + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://europe-west4-aiplatform.googleapis.com/v1/projects/vertex-project/locations/europe-west4", + }) + expect(vertexOptions[0].project).toBe("vertex-project") + expect(vertexOptions[0].location).toBe("europe-west4") + }), + ), + ) + + it.effect("keeps configured project and location over env and uses global endpoint", () => + withEnv( + { + GOOGLE_CLOUD_PROJECT: "env-project", + GCP_PROJECT: "env-gcp-project", + GCLOUD_PROJECT: "env-gcloud-project", + GOOGLE_VERTEX_LOCATION: "env-location", + GOOGLE_CLOUD_LOCATION: "env-google-cloud-location", + VERTEX_LOCATION: "env-vertex-location", + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + expect(result.provider.options.aisdk.provider.project).toBe("config-project") + expect(result.provider.options.aisdk.provider.location).toBe("global") + expect(result.provider.endpoint).toEqual({ + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://aiplatform.googleapis.com/v1/projects/config-project/locations/global", + }) + }), + ), + ) + + it.effect("defaults location to us-central1 when only project is configured", () => + withEnv( + { + GOOGLE_CLOUD_PROJECT: undefined, + GCP_PROJECT: undefined, + GCLOUD_PROJECT: undefined, + GOOGLE_VERTEX_LOCATION: undefined, + GOOGLE_CLOUD_LOCATION: undefined, + VERTEX_LOCATION: undefined, + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + expect(result.provider.options.aisdk.provider.project).toBe("config-project") + expect(result.provider.options.aisdk.provider.location).toBe("us-central1") + }), + ), + ) + + it.effect("does not pass Google auth fetch to the native Vertex SDK", () => + withEnv( + { + GOOGLE_CLOUD_PROJECT: "env-project", + GOOGLE_VERTEX_LOCATION: "env-location", + }, + () => + Effect.gen(function* () { + vertexOptions.length = 0 + const plugin = yield* PluginV2.Service + yield* plugin.add(GoogleVertexPlugin) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("google-vertex", "gemini", { + endpoint: { type: "aisdk", package: "@ai-sdk/google-vertex" }, + }), + package: "@ai-sdk/google-vertex", + options: { name: "google-vertex" }, + }, + {}, + ) + expect(vertexOptions).toHaveLength(1) + expect(vertexOptions[0].project).toBe("env-project") + expect(vertexOptions[0].location).toBe("env-location") + expect(vertexOptions[0].fetch).toBeUndefined() + }), + ), + ) + + it.effect("keeps Google auth fetch for OpenAI-compatible Vertex endpoints", () => + Effect.gen(function* () { + const fetchCalls: { input: Parameters[0]; init?: RequestInit }[] = [] + const plugin = yield* PluginV2.Service + yield* plugin.add(GoogleVertexPlugin) + yield* plugin.add({ + id: PluginV2.ID.make("capture-openai-compatible"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.promise(async () => { + if (evt.model.providerID !== "google-vertex") return + if (evt.package !== "@ai-sdk/openai-compatible") return + expect(typeof evt.options.fetch).toBe("function") + await evt.options.fetch("https://vertex.example", { + headers: { "x-test": "1" }, + }) + }), + }), + }) + const originalFetch = fetch + ;(globalThis as typeof globalThis & { fetch: typeof fetch }).fetch = (async ( + input: Parameters[0], + init?: RequestInit, + ) => { + fetchCalls.push({ input, init }) + return new Response("ok") + }) as typeof fetch + yield* Effect.acquireUseRelease( + Effect.void, + () => + plugin.trigger( + "aisdk.sdk", + { + model: model("google-vertex", "gemini", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible" }, + }), + package: "@ai-sdk/openai-compatible", + options: { name: "google-vertex" }, + }, + {}, + ), + () => + Effect.sync(() => { + ;(globalThis as typeof globalThis & { fetch: typeof fetch }).fetch = originalFetch + }), + ) + expect(fetchCalls).toHaveLength(1) + expect(fetchCalls[0].input).toBe("https://vertex.example") + expect(new Headers(fetchCalls[0].init?.headers).get("authorization")).toBe("Bearer vertex-token") + expect(new Headers(fetchCalls[0].init?.headers).get("x-test")).toBe("1") + }), + ) + + it.effect("trims model IDs before selecting language models", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(GoogleVertexPlugin) + yield* plugin.trigger( + "aisdk.language", + { + model: model("google-vertex", " gemini-2.5-pro "), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: {}, + }, + {}, + ) + expect(calls).toEqual(["languageModel:gemini-2.5-pro"]) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-google.test.ts b/packages/core/test/v2/plugin/provider-google.test.ts new file mode 100644 index 0000000000..ee33b980b8 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-google.test.ts @@ -0,0 +1,70 @@ +import { describe, expect } from "bun:test" +import { Effect, Layer } from "effect" +import { AISDK } from "@opencode-ai/core/aisdk" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { GooglePlugin } from "@opencode-ai/core/plugin/provider/google" +import { testEffect } from "../../lib/effect" +import { it, model } from "./provider-helper" + +const itWithAISDK = testEffect(AISDK.layer.pipe(Layer.provideMerge(PluginV2.defaultLayer))) + +describe("GooglePlugin", () => { + it.effect("creates a Google Generative AI SDK for @ai-sdk/google using the provider ID as SDK name", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GooglePlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-google", "gemini"), + package: "@ai-sdk/google", + options: { name: "custom-google", apiKey: "test" }, + }, + {}, + ) + expect(result.sdk).toBeDefined() + expect(result.sdk?.languageModel("gemini").provider).toBe("custom-google") + }), + ) + + it.effect("ignores non-Google SDK packages", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GooglePlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("google", "gemini"), package: "@ai-sdk/google-vertex", options: { name: "google" } }, + {}, + ) + expect(result.sdk).toBeUndefined() + }), + ) + + itWithAISDK.effect("uses default languageModel loading with provider ID parity", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const aisdk = yield* AISDK.Service + yield* plugin.add(GooglePlugin) + const language = yield* aisdk.language( + model("custom-google", "alias", { + apiID: ModelV2.ID.make("gemini-api"), + endpoint: { + type: "aisdk", + package: "@ai-sdk/google", + }, + options: { + headers: {}, + body: {}, + aisdk: { + provider: { apiKey: "test" }, + request: {}, + }, + }, + }), + ) + expect(language.modelId).toBe("gemini-api") + expect(language.provider).toBe("custom-google") + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-groq.test.ts b/packages/core/test/v2/plugin/provider-groq.test.ts new file mode 100644 index 0000000000..14c10b6513 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-groq.test.ts @@ -0,0 +1,101 @@ +import { describe, expect } from "bun:test" +import { createGroq } from "@ai-sdk/groq" +import { Effect, Layer } from "effect" +import { AISDK } from "@opencode-ai/core/aisdk" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { GroqPlugin } from "@opencode-ai/core/plugin/provider/groq" +import { it, model } from "./provider-helper" +import { testEffect } from "../../lib/effect" + +const aisdkIt = testEffect(AISDK.layer.pipe(Layer.provideMerge(PluginV2.defaultLayer))) + +describe("GroqPlugin", () => { + it.effect("creates a Groq SDK for @ai-sdk/groq", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GroqPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("groq", "llama"), package: "@ai-sdk/groq", options: { name: "groq" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("ignores non-Groq SDK packages", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GroqPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("groq", "llama"), package: "@ai-sdk/openai-compatible", options: { name: "groq" } }, + {}, + ) + expect(result.sdk).toBeUndefined() + }), + ) + + it.effect("only matches the bundled @ai-sdk/groq package exactly", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GroqPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("groq", "llama"), package: "@ai-sdk/groq/compat", options: { name: "groq" } }, + {}, + ) + expect(result.sdk).toBeUndefined() + }), + ) + + it.effect("matches the old bundled Groq SDK provider naming", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GroqPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-groq", "llama"), + package: "@ai-sdk/groq", + options: { name: "custom-groq", apiKey: "test" }, + }, + {}, + ) + const expected = createGroq({ name: "custom-groq", apiKey: "test" } as Parameters[0] & { + name: string + }).languageModel("llama") + const actual = result.sdk?.languageModel("llama") + expect(actual?.provider).toBe(expected.provider) + expect(actual?.modelId).toBe(expected.modelId) + }), + ) + + aisdkIt.effect("uses the default languageModel(apiID) behavior", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const aisdk = yield* AISDK.Service + yield* plugin.add(GroqPlugin) + const result = yield* aisdk.language( + model("groq", "alias", { + apiID: ModelV2.ID.make("llama-api"), + endpoint: { + type: "aisdk", + package: "@ai-sdk/groq", + }, + options: { + headers: {}, + body: {}, + aisdk: { + provider: { apiKey: "test" }, + request: {}, + }, + }, + }), + ) + expect(result.modelId).toBe("llama-api") + expect(result.provider).toBe("groq.chat") + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-helper.ts b/packages/core/test/v2/plugin/provider-helper.ts new file mode 100644 index 0000000000..84a3044bfb --- /dev/null +++ b/packages/core/test/v2/plugin/provider-helper.ts @@ -0,0 +1,100 @@ +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 { 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 + +export const npmLayer = Layer.succeed( + Npm.Service, + Npm.Service.of({ + add: () => Effect.succeed({ directory: "", entrypoint: Option.none() }), + install: () => Effect.void, + which: () => Effect.succeed(Option.none()), + }), +) + +export const it = testEffect(Layer.mergeAll(PluginV2.defaultLayer, npmLayer)) + +export function provider(providerID: string, options?: Partial) { + return new ProviderV2.Info({ + ...ProviderV2.Info.empty(ProviderV2.ID.make(providerID)), + endpoint: { + type: "aisdk", + package: "test-provider", + }, + ...options, + options: { + headers: {}, + body: {}, + aisdk: { + provider: {}, + request: {}, + }, + ...options?.options, + }, + }) +} + +export function model(providerID: string, modelID: string, options?: Partial) { + return new ModelV2.Info({ + ...ModelV2.Info.empty(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID)), + apiID: ModelV2.ID.make(modelID), + endpoint: { + type: "aisdk", + package: "test-provider", + }, + ...options, + options: { + headers: {}, + body: {}, + aisdk: { + provider: {}, + request: {}, + }, + ...options?.options, + }, + }) +} + +export function withEnv(vars: Record, fx: () => Effect.Effect) { + return Effect.acquireUseRelease( + Effect.sync(() => { + const previous = Object.fromEntries(Object.keys(vars).map((key) => [key, process.env[key]])) + for (const [key, value] of Object.entries(vars)) { + if (value === undefined) delete process.env[key] + else process.env[key] = value + } + return previous + }), + () => fx(), + (previous) => + Effect.sync(() => { + for (const [key, value] of Object.entries(previous)) { + if (value === undefined) delete process.env[key] + else process.env[key] = value + } + }), + ) +} + +export function fakeSelectorSdk(calls: string[]) { + const make = (method: string) => (id: string) => { + calls.push(`${method}:${id}`) + return { modelId: id, provider: method, specificationVersion: "v3" } as unknown as LanguageModelV3 + } + return { + responses: make("responses"), + messages: make("messages"), + chat: make("chat"), + languageModel: make("languageModel"), + } +} + +export function expectPluginRegistered(ids: string[], id: string) { + expect(ids).toContain(PluginV2.ID.make(id)) +} diff --git a/packages/core/test/v2/plugin/provider-kilo.test.ts b/packages/core/test/v2/plugin/provider-kilo.test.ts new file mode 100644 index 0000000000..4261ae1328 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-kilo.test.ts @@ -0,0 +1,90 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +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 { expectPluginRegistered, it, provider } from "./provider-helper" + +describe("KiloPlugin", () => { + it.effect("is registered so legacy referer headers can be applied", () => + Effect.sync(() => + expectPluginRegistered( + ProviderPlugins.map((item) => item.id), + "kilo", + ), + ), + ) + + it.effect("applies legacy referer headers only to kilo", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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({ + Existing: "value", + "HTTP-Referer": "https://opencode.ai/", + "X-Title": "opencode", + }) + expect(ignored.provider.options.headers).toEqual({}) + }), + ) + + it.effect("uses the exact legacy Kilo header casing and set", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(KiloPlugin) + const result = yield* plugin.trigger("provider.update", {}, { provider: provider("kilo"), cancel: false }) + + expect(result.provider.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") + }), + ) + + it.effect("uses the legacy provider-id guard instead of endpoint package matching", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + + expect(matchingID.provider.options.headers).toEqual({ + "HTTP-Referer": "https://opencode.ai/", + "X-Title": "opencode", + }) + expect(matchingPackage.provider.options.headers).toEqual({}) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-llmgateway.test.ts b/packages/core/test/v2/plugin/provider-llmgateway.test.ts new file mode 100644 index 0000000000..1ffea96bcb --- /dev/null +++ b/packages/core/test/v2/plugin/provider-llmgateway.test.ts @@ -0,0 +1,63 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +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 { expectPluginRegistered, it, provider } from "./provider-helper" + +describe("LLMGatewayPlugin", () => { + it.effect("is registered so legacy referer headers can be applied", () => + Effect.sync(() => + expectPluginRegistered( + ProviderPlugins.map((item) => item.id), + "llmgateway", + ), + ), + ) + + it.effect("applies legacy referer headers only to enabled llmgateway", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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({ + Existing: "value", + "HTTP-Referer": "https://opencode.ai/", + "X-Title": "opencode", + "X-Source": "opencode", + }) + expect(ignored.provider.options.headers).toEqual({}) + }), + ) + + it.effect("does not apply legacy headers to a disabled llmgateway provider", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(LLMGatewayPlugin) + const result = yield* plugin.trigger("provider.update", {}, { provider: provider("llmgateway"), cancel: false }) + + expect(result.provider.enabled).toBe(false) + expect(result.provider.options.headers).toEqual({}) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-mistral.test.ts b/packages/core/test/v2/plugin/provider-mistral.test.ts new file mode 100644 index 0000000000..f24ff53e5b --- /dev/null +++ b/packages/core/test/v2/plugin/provider-mistral.test.ts @@ -0,0 +1,106 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { MistralPlugin } from "@opencode-ai/core/plugin/provider/mistral" +import { fakeSelectorSdk, it, model } from "./provider-helper" + +describe("MistralPlugin", () => { + it.effect("creates a Mistral SDK for @ai-sdk/mistral", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(MistralPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("mistral", "mistral-large"), package: "@ai-sdk/mistral", options: { name: "mistral" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("ignores non-Mistral SDK packages", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(MistralPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("mistral", "mistral-large"), + package: "@ai-sdk/openai-compatible", + options: { name: "mistral" }, + }, + {}, + ) + expect(result.sdk).toBeUndefined() + }), + ) + + it.effect("matches the old bundled Mistral SDK provider name for the bundled provider ID", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const providers: string[] = [] + yield* plugin.add(MistralPlugin) + yield* plugin.add({ + id: PluginV2.ID.make("mistral-sdk-inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + providers.push(evt.sdk.languageModel("mistral-large").provider) + }), + }), + }) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("mistral", "mistral-large"), package: "@ai-sdk/mistral", options: { name: "mistral" } }, + {}, + ) + expect(result.sdk).toBeDefined() + expect(providers).toEqual(["mistral.chat"]) + }), + ) + + it.effect("matches the old bundled Mistral SDK provider name for custom provider IDs", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const providers: string[] = [] + yield* plugin.add(MistralPlugin) + yield* plugin.add({ + id: PluginV2.ID.make("mistral-sdk-inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + providers.push(evt.sdk.languageModel("mistral-large").provider) + }), + }), + }) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-mistral", "mistral-large"), + package: "@ai-sdk/mistral", + options: { name: "custom-mistral" }, + }, + {}, + ) + expect(providers).toEqual(["mistral.chat"]) + }), + ) + + it.effect("leaves Mistral language selection on the default sdk.languageModel(apiID) path", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + const sdk = fakeSelectorSdk(calls) + yield* plugin.add(MistralPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { model: model("mistral", "alias", { apiID: ModelV2.ID.make("mistral-large") }), sdk, options: {} }, + {}, + ) + const language = result.language ?? sdk.languageModel(result.model.apiID) + expect(calls).toEqual(["languageModel:mistral-large"]) + expect(language).toBeDefined() + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-nvidia.test.ts b/packages/core/test/v2/plugin/provider-nvidia.test.ts new file mode 100644 index 0000000000..0e06356cd5 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-nvidia.test.ts @@ -0,0 +1,41 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +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 { expectPluginRegistered, it, provider } from "./provider-helper" + +describe("NvidiaPlugin", () => { + it.effect("is registered so legacy referer headers can be applied", () => + Effect.sync(() => + expectPluginRegistered( + ProviderPlugins.map((item) => item.id), + "nvidia", + ), + ), + ) + + it.effect("applies legacy referer headers only to nvidia", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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({ + Existing: "value", + "HTTP-Referer": "https://opencode.ai/", + "X-Title": "opencode", + }) + expect(ignored.provider.options.headers).toEqual({}) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-openai-compatible.test.ts b/packages/core/test/v2/plugin/provider-openai-compatible.test.ts new file mode 100644 index 0000000000..e8bf1f7575 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-openai-compatible.test.ts @@ -0,0 +1,101 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { OpenAICompatiblePlugin } from "@opencode-ai/core/plugin/provider/openai-compatible" +import { it, model } from "./provider-helper" + +describe("OpenAICompatiblePlugin", () => { + it.effect("preserves explicit includeUsage false and defaults it to true", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(OpenAICompatiblePlugin) + const defaulted = yield* plugin.trigger( + "aisdk.sdk", + { model: model("custom", "model"), package: "@ai-sdk/openai-compatible", options: { name: "custom" } }, + {}, + ) + const disabled = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom", "model"), + package: "@ai-sdk/openai-compatible", + options: { name: "custom", includeUsage: false }, + }, + {}, + ) + expect(defaulted.options.includeUsage).toBe(true) + expect(disabled.options.includeUsage).toBe(false) + }), + ) + + it.effect("defaults includeUsage for OpenAI-compatible package matches", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(OpenAICompatiblePlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom", "model"), + package: "file:///tmp/@ai-sdk/openai-compatible-provider.js", + options: { name: "custom" }, + }, + {}, + ) + expect(result.options.includeUsage).toBe(true) + }), + ) + + it.effect("uses the provider ID as the OpenAI-compatible provider name", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const observed: string[] = [] + yield* plugin.add(OpenAICompatiblePlugin) + yield* plugin.add({ + id: PluginV2.ID.make("inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + observed.push(evt.sdk.languageModel("model").provider) + }), + }), + }) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-provider", "model"), + package: "@ai-sdk/openai-compatible", + options: { name: "custom-provider", baseURL: "https://example.com/v1" }, + }, + {}, + ) + expect(observed).toEqual(["custom-provider.chat"]) + }), + ) + + it.effect("does not overwrite an SDK created by an earlier provider-specific plugin", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const sentinel = { languageModel: (modelID: string) => ({ modelID }) } + yield* plugin.add({ + id: PluginV2.ID.make("sentinel"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + evt.sdk = sentinel + }), + }), + }) + yield* plugin.add(OpenAICompatiblePlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("cloudflare-workers-ai", "model"), + package: "@ai-sdk/openai-compatible", + options: { name: "cloudflare-workers-ai" }, + }, + {}, + ) + expect(result.sdk).toBe(sentinel) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-openai.test.ts b/packages/core/test/v2/plugin/provider-openai.test.ts new file mode 100644 index 0000000000..31d6dd0b6d --- /dev/null +++ b/packages/core/test/v2/plugin/provider-openai.test.ts @@ -0,0 +1,100 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +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" + +describe("OpenAIPlugin", () => { + it.effect("creates an OpenAI SDK for @ai-sdk/openai using the provider ID as SDK name", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(OpenAIPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-openai", "gpt-5"), + package: "@ai-sdk/openai", + options: { name: "custom-openai", apiKey: "test" }, + }, + {}, + ) + expect(result.sdk?.responses("gpt-5").provider).toBe("custom-openai.responses") + }), + ) + + it.effect("ignores non-OpenAI SDK packages", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(OpenAIPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("openai", "gpt-5"), package: "@ai-sdk/openai-compatible", options: { name: "openai" } }, + {}, + ) + expect(result.sdk).toBeUndefined() + }), + ) + + it.effect("uses the Responses API for language models", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(OpenAIPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: model("openai", "alias", { apiID: ModelV2.ID.make("gpt-5") }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + expect(calls).toEqual(["responses:gpt-5"]) + expect(result.language).toBeDefined() + }), + ) + + it.effect("ignores non-OpenAI providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(OpenAIPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { model: model("anthropic", "gpt-5"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + expect(calls).toEqual([]) + expect(result.language).toBeUndefined() + }), + ) + + it.effect("cancels gpt-5-chat-latest during model updates", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ) + + it.effect("does not cancel gpt-5-chat-latest for non-OpenAI providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-opencode.test.ts b/packages/core/test/v2/plugin/provider-opencode.test.ts new file mode 100644 index 0000000000..f080776d40 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-opencode.test.ts @@ -0,0 +1,195 @@ +import { describe, expect } from "bun:test" +import { DateTime, Effect, Option } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { OpencodePlugin } from "@opencode-ai/core/plugin/provider/opencode" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { it, model, provider, withEnv } from "./provider-helper" + +const cost = (input: number, output = 0) => [{ input, output, cache: { read: 0, write: 0 } }] + +describe("OpencodePlugin", () => { + it.effect("uses a public key and cancels paid models without credentials", () => + withEnv({ OPENCODE_API_KEY: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ), + ) + + it.effect("keeps free models without credentials", () => + withEnv({ OPENCODE_API_KEY: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ), + ) + + it.effect("treats output-only cost as free without credentials", () => + withEnv({ OPENCODE_API_KEY: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ), + ) + + it.effect("uses OPENCODE_API_KEY as credentials", () => + withEnv({ OPENCODE_API_KEY: "secret" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ), + ) + + it.effect("uses configured provider env vars as credentials", () => + withEnv({ OPENCODE_API_KEY: undefined, CUSTOM_OPENCODE_API_KEY: "secret" }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ), + ) + + it.effect("uses configured apiKey as credentials", () => + withEnv({ OPENCODE_API_KEY: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(OpencodePlugin) + const updated = yield* plugin.trigger( + "provider.update", + {}, + { + provider: 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) + }), + ), + ) + + it.effect("uses auth-enabled providers as credentials", () => + withEnv({ OPENCODE_API_KEY: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ), + ) + + it.effect("ignores non-opencode providers and models", () => + withEnv({ OPENCODE_API_KEY: undefined }, () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ), + ) + + it.effect("prefers gpt-5-nano as the opencode small model", () => + Effect.gen(function* () { + 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 selected = yield* catalog.model.small(providerID) + + expect(Option.getOrUndefined(selected)?.id).toBe(ModelV2.ID.make("gpt-5-nano")) + }).pipe(Effect.provide(Catalog.defaultLayer)), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-openrouter.test.ts b/packages/core/test/v2/plugin/provider-openrouter.test.ts new file mode 100644 index 0000000000..3d143ac7f2 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-openrouter.test.ts @@ -0,0 +1,105 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +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 { expectPluginRegistered, it, model, provider } from "./provider-helper" + +describe("OpenRouterPlugin", () => { + it.effect("is registered so legacy OpenRouter behavior can be applied", () => + Effect.sync(() => + expectPluginRegistered( + ProviderPlugins.map((item) => item.id), + "openrouter", + ), + ), + ) + + it.effect("applies legacy referer headers only to openrouter", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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({ + Existing: "value", + "HTTP-Referer": "https://opencode.ai/", + "X-Title": "opencode", + }) + expect(ignored.provider.options.headers).toEqual({}) + }), + ) + + it.effect("creates an SDK only for the OpenRouter package", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(OpenRouterPlugin) + + const ignored = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("openrouter", "openai/gpt-5"), + package: "@ai-sdk/openai-compatible", + options: { name: "openrouter" }, + }, + {}, + ) + expect(ignored.sdk).toBeUndefined() + + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("custom", "openai/gpt-5"), package: "@openrouter/ai-sdk-provider", options: { name: "custom" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("filters OpenRouter's gpt-5 chat alias", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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 }, + ) + + expect(result.cancel).toBe(true) + expect(regular.cancel).toBe(false) + expect(ignored.cancel).toBe(false) + }), + ) + + it.effect("does not filter gpt-5-chat-latest for non-OpenRouter providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-perplexity.test.ts b/packages/core/test/v2/plugin/provider-perplexity.test.ts new file mode 100644 index 0000000000..d03f583375 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-perplexity.test.ts @@ -0,0 +1,107 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { PerplexityPlugin } from "@opencode-ai/core/plugin/provider/perplexity" +import { fakeSelectorSdk, it, model } from "./provider-helper" + +describe("PerplexityPlugin", () => { + it.effect("creates a Perplexity SDK for the exact @ai-sdk/perplexity package", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(PerplexityPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("perplexity", "sonar"), package: "@ai-sdk/perplexity", options: { name: "perplexity" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("ignores packages that are not the bundled Perplexity package", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(PerplexityPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("perplexity", "sonar"), + package: "@ai-sdk/perplexity-compatible", + options: { name: "perplexity" }, + }, + {}, + ) + expect(result.sdk).toBeUndefined() + }), + ) + + it.effect("uses the Perplexity provider ID as the SDK name for the bundled provider", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const providers: string[] = [] + yield* plugin.add(PerplexityPlugin) + yield* plugin.add({ + id: PluginV2.ID.make("perplexity-sdk-inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + providers.push(evt.sdk.languageModel("sonar").provider) + }), + }), + }) + yield* plugin.trigger( + "aisdk.sdk", + { model: model("perplexity", "sonar"), package: "@ai-sdk/perplexity", options: { name: "perplexity" } }, + {}, + ) + expect(providers).toEqual(["perplexity"]) + }), + ) + + it.effect("creates bundled Perplexity SDKs for custom provider IDs", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const providers: string[] = [] + yield* plugin.add(PerplexityPlugin) + yield* plugin.add({ + id: PluginV2.ID.make("custom-perplexity-sdk-inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + providers.push(evt.sdk.languageModel("sonar").provider) + }), + }), + }) + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-perplexity", "sonar"), + package: "@ai-sdk/perplexity", + options: { name: "custom-perplexity" }, + }, + {}, + ) + expect(providers).toEqual(["perplexity"]) + }), + ) + + it.effect("leaves Perplexity language selection to the default languageModel fallback", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(PerplexityPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: model("perplexity", "alias", { apiID: ModelV2.ID.make("sonar") }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + expect(calls).toEqual([]) + expect(result.language).toBeUndefined() + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-sap-ai-core.test.ts b/packages/core/test/v2/plugin/provider-sap-ai-core.test.ts new file mode 100644 index 0000000000..565b9280ab --- /dev/null +++ b/packages/core/test/v2/plugin/provider-sap-ai-core.test.ts @@ -0,0 +1,127 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { SapAICorePlugin } from "@opencode-ai/core/plugin/provider/sap-ai-core" +import { fixtureProvider, it, model, npmLayer, withEnv } from "./provider-helper" + +const pluginWithNpm = { id: SapAICorePlugin.id, effect: SapAICorePlugin.effect.pipe(Effect.provide(npmLayer)) } + +describe("SapAICorePlugin", () => { + it.effect("copies serviceKey option into AICORE_SERVICE_KEY but keeps SDK options to deployment metadata", () => + withEnv( + { AICORE_SERVICE_KEY: undefined, AICORE_DEPLOYMENT_ID: "deployment", AICORE_RESOURCE_GROUP: "resource-group" }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(pluginWithNpm) + const sdk = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("sap-ai-core", "sap-model"), + package: fixtureProvider, + options: { name: "sap-ai-core", serviceKey: "service-key" }, + }, + {}, + ) + expect(process.env.AICORE_SERVICE_KEY).toBe("service-key") + expect(sdk.sdk.options).toEqual({ deploymentId: "deployment", resourceGroup: "resource-group" }) + }), + ), + ) + + it.effect("preserves existing AICORE_SERVICE_KEY over serviceKey option", () => + withEnv( + { + AICORE_SERVICE_KEY: "env-service-key", + AICORE_DEPLOYMENT_ID: "deployment", + AICORE_RESOURCE_GROUP: "resource-group", + }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(pluginWithNpm) + const sdk = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("sap-ai-core", "sap-model"), + package: fixtureProvider, + options: { name: "sap-ai-core", serviceKey: "option-service-key" }, + }, + {}, + ) + expect(process.env.AICORE_SERVICE_KEY).toBe("env-service-key") + expect(sdk.sdk.options).toEqual({ deploymentId: "deployment", resourceGroup: "resource-group" }) + }), + ), + ) + + it.effect("omits deployment and resourceGroup SDK options when no service key is available", () => + withEnv( + { AICORE_SERVICE_KEY: undefined, AICORE_DEPLOYMENT_ID: "deployment", AICORE_RESOURCE_GROUP: "resource-group" }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(pluginWithNpm) + const sdk = yield* plugin.trigger( + "aisdk.sdk", + { model: model("sap-ai-core", "sap-model"), package: fixtureProvider, options: { name: "sap-ai-core" } }, + {}, + ) + expect(process.env.AICORE_SERVICE_KEY).toBeUndefined() + expect(sdk.sdk.options).toEqual({}) + }), + ), + ) + + it.effect("uses the callable SDK for language selection", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(pluginWithNpm) + const sdk = Object.assign((modelID: string) => ({ modelID, provider: "callable" }), { + languageModel() { + throw new Error("SAP AI Core should call the SDK directly") + }, + }) + const language = yield* plugin.trigger( + "aisdk.language", + { model: model("sap-ai-core", "sap-model"), sdk, options: {} }, + {}, + ) + expect(language.language as unknown).toEqual({ modelID: "sap-model", provider: "callable" }) + }), + ) + + it.effect("ignores non-SAP AI Core providers", () => + withEnv( + { AICORE_SERVICE_KEY: undefined, AICORE_DEPLOYMENT_ID: "deployment", AICORE_RESOURCE_GROUP: "resource-group" }, + () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(pluginWithNpm) + const sdk = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("openai", "sap-model"), + package: fixtureProvider, + options: { name: "openai", serviceKey: "service-key" }, + }, + {}, + ) + const language = yield* plugin.trigger( + "aisdk.language", + { + model: model("openai", "sap-model"), + sdk: () => { + throw new Error("SAP AI Core should ignore other providers") + }, + options: {}, + }, + {}, + ) + expect(process.env.AICORE_SERVICE_KEY).toBeUndefined() + expect(sdk.sdk).toBeUndefined() + expect(language.language).toBeUndefined() + }), + ), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-togetherai.test.ts b/packages/core/test/v2/plugin/provider-togetherai.test.ts new file mode 100644 index 0000000000..65090037be --- /dev/null +++ b/packages/core/test/v2/plugin/provider-togetherai.test.ts @@ -0,0 +1,97 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { TogetherAIPlugin } from "@opencode-ai/core/plugin/provider/togetherai" +import { fakeSelectorSdk, it, model } from "./provider-helper" + +describe("TogetherAIPlugin", () => { + it.effect("creates a TogetherAI SDK for @ai-sdk/togetherai", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(TogetherAIPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("togetherai", "model"), package: "@ai-sdk/togetherai", options: { name: "togetherai" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("matches the old bundled provider package exactly", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(TogetherAIPlugin) + + const ignored = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("togetherai", "model"), + package: "file:///tmp/@ai-sdk/togetherai-provider.js", + options: { name: "togetherai" }, + }, + {}, + ) + expect(ignored.sdk).toBeUndefined() + + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("togetherai", "model"), package: "@ai-sdk/togetherai", options: { name: "togetherai" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("creates bundled TogetherAI SDKs for custom provider IDs", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const observed: string[] = [] + yield* plugin.add(TogetherAIPlugin) + yield* plugin.add({ + id: PluginV2.ID.make("inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + observed.push(evt.sdk.languageModel("model").provider) + }), + }), + }) + + yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-togetherai", "model"), + package: "@ai-sdk/togetherai", + options: { name: "custom-togetherai" }, + }, + {}, + ) + + expect(observed).toEqual(["togetherai.chat"]) + }), + ) + + it.effect("defaults language selection to sdk.languageModel with the model API ID", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(TogetherAIPlugin) + + const result = yield* plugin.trigger( + "aisdk.language", + { + model: model("togetherai", "meta-llama/Llama-3.3-70B-Instruct-Turbo"), + sdk: { languageModel: fakeSelectorSdk(calls).languageModel }, + options: {}, + }, + {}, + ) + + expect(result.language).toBeUndefined() + expect(calls).toEqual([]) + expect(result.language ?? fakeSelectorSdk(calls).languageModel(result.model.apiID)).toBeDefined() + expect(calls).toEqual(["languageModel:meta-llama/Llama-3.3-70B-Instruct-Turbo"]) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-venice.test.ts b/packages/core/test/v2/plugin/provider-venice.test.ts new file mode 100644 index 0000000000..ff4a922ab1 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-venice.test.ts @@ -0,0 +1,86 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { VenicePlugin } from "@opencode-ai/core/plugin/provider/venice" +import { fakeSelectorSdk, it, model } from "./provider-helper" + +describe("VenicePlugin", () => { + it.effect("creates a Venice SDK for venice-ai-sdk-provider", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(VenicePlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { model: model("venice", "model"), package: "venice-ai-sdk-provider", options: { name: "venice" } }, + {}, + ) + expect(result.sdk).toBeDefined() + }), + ) + + it.effect("uses the model provider ID as the bundled Venice SDK name", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const observed: string[] = [] + yield* plugin.add(VenicePlugin) + yield* plugin.add({ + id: PluginV2.ID.make("inspector"), + effect: Effect.succeed({ + "aisdk.sdk": (evt) => + Effect.sync(() => { + observed.push(evt.sdk.languageModel("model").provider) + }), + }), + }) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("custom-venice", "model"), + package: "venice-ai-sdk-provider", + options: { name: "custom-venice", apiKey: "test" }, + }, + {}, + ) + expect(result.sdk).toBeDefined() + expect(observed).toEqual(["custom-venice.chat"]) + }), + ) + + it.effect("only handles the bundled venice-ai-sdk-provider package", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(VenicePlugin) + const similar = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("venice", "model"), + package: "file:///tmp/venice-ai-sdk-provider.js", + options: { name: "venice" }, + }, + {}, + ) + const other = yield* plugin.trigger( + "aisdk.sdk", + { model: model("venice", "model"), package: "@ai-sdk/openai-compatible", options: { name: "venice" } }, + {}, + ) + expect(similar.sdk).toBeUndefined() + expect(other.sdk).toBeUndefined() + }), + ) + + it.effect("leaves Venice language selection to the default languageModel fallback", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + yield* plugin.add(VenicePlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { model: model("venice", "alias"), sdk: fakeSelectorSdk(calls), options: {} }, + {}, + ) + expect(calls).toEqual([]) + expect(result.language).toBeUndefined() + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-vercel.test.ts b/packages/core/test/v2/plugin/provider-vercel.test.ts new file mode 100644 index 0000000000..3134a7b83c --- /dev/null +++ b/packages/core/test/v2/plugin/provider-vercel.test.ts @@ -0,0 +1,62 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { VercelPlugin } from "@opencode-ai/core/plugin/provider/vercel" +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 + 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({ + Existing: "1", + "http-referer": "https://opencode.ai/", + "x-title": "opencode", + }) + }), + ) + + it.effect("does not add legacy upper-case referer headers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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") + }), + ) + + it.effect("creates @ai-sdk/vercel SDKs for custom provider IDs", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(VercelPlugin) + const event = yield* plugin.trigger( + "aisdk.sdk", + { model: model("custom-vercel", "v0-1.0-md"), package: "@ai-sdk/vercel", options: { name: "custom-vercel" } }, + {}, + ) + expect(event.sdk).toBeDefined() + expect(event.sdk.languageModel("v0-1.0-md").provider).toBe("vercel.chat") + }), + ) + + it.effect("ignores non-Vercel providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(VercelPlugin) + const result = yield* plugin.trigger("provider.update", {}, { provider: provider("gateway"), cancel: false }) + expect(result.provider.options.headers).toEqual({}) + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-xai.test.ts b/packages/core/test/v2/plugin/provider-xai.test.ts new file mode 100644 index 0000000000..bb2828ff4d --- /dev/null +++ b/packages/core/test/v2/plugin/provider-xai.test.ts @@ -0,0 +1,115 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import { ModelV2 } from "@opencode-ai/core/model" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { XAIPlugin } from "@opencode-ai/core/plugin/provider/xai" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { testEffect } from "../../lib/effect" +import { fakeSelectorSdk } from "./provider-helper" + +const it = testEffect(PluginV2.defaultLayer) + +const model = new ModelV2.Info({ + ...ModelV2.Info.empty(ProviderV2.ID.make("xai"), ModelV2.ID.make("grok-4")), + apiID: ModelV2.ID.make("grok-4"), + endpoint: { + type: "aisdk", + package: "@ai-sdk/xai", + }, +}) + +describe("XAIPlugin", () => { + it.effect("creates an xAI SDK only for @ai-sdk/xai", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(XAIPlugin) + + const ignored = yield* plugin.trigger( + "aisdk.sdk", + { model, package: "@ai-sdk/openai-compatible", options: {} }, + {}, + ) + + const result = yield* plugin.trigger("aisdk.sdk", { model, package: "@ai-sdk/xai", options: {} }, {}) + + expect(ignored.sdk).toBeUndefined() + expect(typeof result.sdk?.responses).toBe("function") + }), + ) + + it.effect("creates xAI SDKs for custom provider IDs", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const providers: string[] = [] + + yield* plugin.add(XAIPlugin) + yield* plugin.add( + PluginV2.define({ + id: PluginV2.ID.make("xai-sdk-name-observer"), + effect: Effect.gen(function* () { + return { + "aisdk.sdk": Effect.fn(function* (evt) { + if (!evt.sdk) return + providers.push(evt.sdk.responses("grok-4").provider) + }), + } + }), + }), + ) + + yield* plugin.trigger( + "aisdk.sdk", + { + model: new ModelV2.Info({ ...model, providerID: ProviderV2.ID.make("custom-xai") }), + package: "@ai-sdk/xai", + options: {}, + }, + {}, + ) + + expect(providers).toEqual(["xai.responses"]) + }), + ) + + it.effect("uses responses with the model apiID for xAI language models", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + + yield* plugin.add(XAIPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: new ModelV2.Info({ ...model, id: ModelV2.ID.make("alias"), apiID: ModelV2.ID.make("grok-4") }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + + expect(calls).toEqual(["responses:grok-4"]) + expect(result.language).toBeDefined() + }), + ) + + it.effect("ignores non-xAI providers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const calls: string[] = [] + + yield* plugin.add(XAIPlugin) + const result = yield* plugin.trigger( + "aisdk.language", + { + model: new ModelV2.Info({ ...model, providerID: ProviderV2.ID.openai }), + sdk: fakeSelectorSdk(calls), + options: {}, + }, + {}, + ) + + expect(calls).toEqual([]) + expect(result.language).toBeUndefined() + }), + ) +}) diff --git a/packages/core/test/v2/plugin/provider-zenmux.test.ts b/packages/core/test/v2/plugin/provider-zenmux.test.ts new file mode 100644 index 0000000000..2b7730e6c7 --- /dev/null +++ b/packages/core/test/v2/plugin/provider-zenmux.test.ts @@ -0,0 +1,103 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +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 { expectPluginRegistered, it, provider } from "./provider-helper" + +describe("ZenmuxPlugin", () => { + it.effect("is registered so legacy referer headers can be applied", () => + Effect.sync(() => + expectPluginRegistered( + ProviderPlugins.map((item) => item.id), + "zenmux", + ), + ), + ) + + it.effect("applies the exact legacy Zenmux headers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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) + }), + ) + + it.effect("merges legacy Zenmux headers with existing headers", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + + expect(result.provider.options.headers).toEqual({ + Existing: "value", + "HTTP-Referer": "https://opencode.ai/", + "X-Title": "opencode", + }) + }), + ) + + it.effect("lets configured Zenmux legacy headers override defaults", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + + expect(result.provider.options.headers).toEqual({ + "HTTP-Referer": "https://example.com/", + "X-Title": "custom-title", + }) + }), + ) + + it.effect("guards legacy Zenmux headers to the exact zenmux provider id", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.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, + }, + ) + + expect(ignored.provider.options.headers).toEqual({ + "HTTP-Referer": "https://example.com/", + "X-Title": "custom-title", + }) + }), + ) +}) diff --git a/packages/desktop/.gitignore b/packages/desktop/.gitignore index ac9d8db969..6923045cd9 100644 --- a/packages/desktop/.gitignore +++ b/packages/desktop/.gitignore @@ -26,3 +26,4 @@ out/ resources/opencode-cli* resources/icons +resources/*.metainfo.xml diff --git a/packages/desktop/scripts/copy-metainfo.ts b/packages/desktop/scripts/copy-metainfo.ts new file mode 100644 index 0000000000..e7585ccafd --- /dev/null +++ b/packages/desktop/scripts/copy-metainfo.ts @@ -0,0 +1,47 @@ +import { resolveChannel } from "./utils" + +const arg = process.argv[2] +const channel = arg === "dev" || arg === "beta" || arg === "prod" ? arg : resolveChannel() + +const appId = channel === "prod" ? "ai.opencode.desktop" : `ai.opencode.desktop.${channel}` +const productName = channel === "prod" ? "OpenCode" : `OpenCode ${channel.charAt(0).toUpperCase() + channel.slice(1)}` +const summary = `Open source AI coding agent${channel !== "prod" ? ` (${channel})` : ""}` + +const xml = ` + + ${appId} + + CC0-1.0 + MIT + + ${productName} + ${summary} + + + Anomaly Innovations Inc. + + + +

+ OpenCode is an open source agent that helps you write and run code with any AI model. +

+
+ + ${appId}.desktop + + + + https://github.com/anomalyco/opencode/issues + https://opencode.ai + https://github.com/anomalyco/opencode + + + + https://raw.githubusercontent.com/anomalyco/opencode/b75d4d1c5ec449585d515c756fc81f080a157a9a/packages/web/src/assets/lander/screenshot.png + + +
+` + +await Bun.write(`resources/${appId}.metainfo.xml`, xml) +console.log(`Generated metainfo for ${channel} at resources/${appId}.metainfo.xml`) diff --git a/packages/desktop/scripts/prebuild.ts b/packages/desktop/scripts/prebuild.ts index 46a2475ea5..79b0e30afc 100644 --- a/packages/desktop/scripts/prebuild.ts +++ b/packages/desktop/scripts/prebuild.ts @@ -5,5 +5,6 @@ import { resolveChannel } from "./utils" const channel = resolveChannel() await $`bun ./scripts/copy-icons.ts ${channel}` +await $`bun ./scripts/copy-metainfo.ts ${channel}` await $`cd ../opencode && bun script/build-node.ts` diff --git a/packages/desktop/src/main/shell-env.test.ts b/packages/desktop/src/main/shell-env.test.ts index cfe88277ea..e71708ad04 100644 --- a/packages/desktop/src/main/shell-env.test.ts +++ b/packages/desktop/src/main/shell-env.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" -import { isNushell, mergeShellEnv, parseShellEnv } from "./shell-env" +import { isNushell, mergeShellEnv, parseShellEnv, resolveUserShell } from "./shell-env" describe("shell env", () => { test("parseShellEnv supports null-delimited pairs", () => { @@ -34,6 +34,13 @@ describe("shell env", () => { expect(env.OPENCODE_CLIENT).toBe("desktop") }) + test("resolveUserShell falls back to the login shell before /bin/sh", () => { + expect(resolveUserShell("/custom/env-shell", "/bin/zsh")).toBe("/custom/env-shell") + expect(resolveUserShell(undefined, "/bin/zsh")).toBe("/bin/zsh") + expect(resolveUserShell(undefined, "unknown")).toBe("/bin/sh") + expect(resolveUserShell(undefined, undefined)).toBe("/bin/sh") + }) + test("isNushell handles path and binary name", () => { expect(isNushell("nu")).toBe(true) expect(isNushell("/opt/homebrew/bin/nu")).toBe(true) diff --git a/packages/desktop/src/main/shell-env.ts b/packages/desktop/src/main/shell-env.ts index 4a65fbf0f7..deb43033ae 100644 --- a/packages/desktop/src/main/shell-env.ts +++ b/packages/desktop/src/main/shell-env.ts @@ -1,4 +1,5 @@ import { spawnSync } from "node:child_process" +import { userInfo } from "node:os" import { basename } from "node:path" import { getLogger } from "./logging" @@ -6,8 +7,17 @@ const TIMEOUT = 5_000 type Probe = { type: "Loaded"; value: Record } | { type: "Timeout" } | { type: "Unavailable" } +export function resolveUserShell(envShell: string | undefined, loginShell: string | null | undefined) { + const resolvedLoginShell = loginShell && loginShell !== "unknown" ? loginShell : undefined + return envShell || resolvedLoginShell || "/bin/sh" +} + export function getUserShell() { - return process.env.SHELL || "/bin/sh" + try { + return resolveUserShell(process.env.SHELL, userInfo().shell) + } catch { + return resolveUserShell(process.env.SHELL, undefined) + } } export function parseShellEnv(out: Buffer) { diff --git a/packages/enterprise/src/core/share.ts b/packages/enterprise/src/core/share.ts index fb8cd30295..a39171462d 100644 --- a/packages/enterprise/src/core/share.ts +++ b/packages/enterprise/src/core/share.ts @@ -1,9 +1,12 @@ import { Message, Model, Part, Session, SnapshotFileDiff } from "@opencode-ai/sdk/v2" -import { fn } from "@opencode-ai/core/util/fn" import { iife } from "@opencode-ai/core/util/iife" import z from "zod" import { Storage } from "./storage" +function fn(schema: T, cb: (input: z.infer) => Result) { + return (input: z.infer) => cb(schema.parse(input)) +} + export namespace Share { export const Info = z.object({ id: z.string(), diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx index b12afce27a..7cfb2bb4a7 100644 --- a/packages/enterprise/src/routes/share/[shareID].tsx +++ b/packages/enterprise/src/routes/share/[shareID].tsx @@ -15,7 +15,6 @@ import { Binary } from "@opencode-ai/core/util/binary" import { NamedError } from "@opencode-ai/core/util/error" import { DateTime } from "luxon" import { createStore } from "solid-js/store" -import z from "zod" import NotFound from "../[...404]" import { Tabs } from "@opencode-ai/ui/tabs" import { MessageNav } from "@opencode-ai/ui/message-nav" @@ -33,13 +32,28 @@ const ClientOnlyWorkerPoolProvider = clientOnly(() => })), ) -const SessionDataMissingError = NamedError.create( - "SessionDataMissingError", - z.object({ - sessionID: z.string(), - message: z.string().optional(), - }), -) +class SessionDataMissingError extends NamedError { + public override readonly name = "SessionDataMissingError" + + constructor( + public readonly data: { sessionID: string; message?: string }, + options?: ErrorOptions, + ) { + super("SessionDataMissingError", options) + } + + static isInstance(input: unknown): input is SessionDataMissingError { + return NamedError.hasName(input, "SessionDataMissingError") + } + + schema(): never { + throw new Error("SessionDataMissingError does not expose a schema") + } + + toObject() { + return { name: this.name, data: this.data } + } +} const getData = query(async (shareID) => { "use server" diff --git a/packages/enterprise/sst-env.d.ts b/packages/enterprise/sst-env.d.ts index 9680a53aab..088db5be2c 100644 --- a/packages/enterprise/sst-env.d.ts +++ b/packages/enterprise/sst-env.d.ts @@ -298,6 +298,7 @@ declare module "sst" { "EnterpriseStorage": cloudflare.R2Bucket "GatewayKv": cloudflare.KVNamespace "LogProcessor": cloudflare.Service + "Stat": cloudflare.Service "ZenData": cloudflare.R2Bucket "ZenDataNew": cloudflare.R2Bucket } diff --git a/packages/function/sst-env.d.ts b/packages/function/sst-env.d.ts index 9680a53aab..088db5be2c 100644 --- a/packages/function/sst-env.d.ts +++ b/packages/function/sst-env.d.ts @@ -298,6 +298,7 @@ declare module "sst" { "EnterpriseStorage": cloudflare.R2Bucket "GatewayKv": cloudflare.KVNamespace "LogProcessor": cloudflare.Service + "Stat": cloudflare.Service "ZenData": cloudflare.R2Bucket "ZenDataNew": cloudflare.R2Bucket } diff --git a/packages/llm/example/tutorial.ts b/packages/llm/example/tutorial.ts index a9adecf369..429ac4824b 100644 --- a/packages/llm/example/tutorial.ts +++ b/packages/llm/example/tutorial.ts @@ -78,7 +78,7 @@ const streamText = LLM.stream(request).pipe( Stream.tap((event) => Effect.sync(() => { if (event.type === "text-delta") process.stdout.write(`\ntext: ${event.text}`) - if (event.type === "request-finish") process.stdout.write(`\nfinish: ${event.reason}\n`) + if (event.type === "finish") process.stdout.write(`\nfinish: ${event.reason}\n`) }), ), Stream.runDrain, @@ -185,7 +185,7 @@ const FakeProtocol = Protocol.make({ event: Schema.String, initial: () => undefined, step: (_, frame) => Effect.succeed([undefined, [{ type: "text-delta", id: "text-0", text: frame }]] as const), - onHalt: () => [{ type: "request-finish", reason: "stop" }], + onHalt: () => [{ type: "finish", reason: "stop" }], }, }) diff --git a/packages/llm/src/index.ts b/packages/llm/src/index.ts index f4adf4859a..acf73b360e 100644 --- a/packages/llm/src/index.ts +++ b/packages/llm/src/index.ts @@ -17,6 +17,7 @@ export type { ExecutableTools, Tool as ToolShape, ToolExecute, + ToolExecuteContext, Tools, ToolSchema, } from "./tool" diff --git a/packages/llm/src/protocols/openai-responses.ts b/packages/llm/src/protocols/openai-responses.ts index e31a42cd5a..7cf734f027 100644 --- a/packages/llm/src/protocols/openai-responses.ts +++ b/packages/llm/src/protocols/openai-responses.ts @@ -380,7 +380,7 @@ type StepResult = readonly [ParserState, ReadonlyArray] const NO_EVENTS: StepResult["1"] = [] // `response.completed` / `response.incomplete` are clean finishes that emit a -// `request-finish` event; `response.failed` is a hard failure that emits a +// `finish` event; `response.failed` is a hard failure that emits a // `provider-error`. All three end the stream — kept in one set so `step` and // the protocol's `terminal` predicate stay in sync. const TERMINAL_TYPES = new Set(["response.completed", "response.incomplete", "response.failed"]) diff --git a/packages/llm/src/protocols/utils/lifecycle.ts b/packages/llm/src/protocols/utils/lifecycle.ts index 67039b137a..c249d75cee 100644 --- a/packages/llm/src/protocols/utils/lifecycle.ts +++ b/packages/llm/src/protocols/utils/lifecycle.ts @@ -80,7 +80,7 @@ export const finish = ( usage: input.usage, providerMetadata: input.providerMetadata, }), - LLMEvent.requestFinish(input), + LLMEvent.finish(input), ) return { ...stepped, stepStarted: false } } diff --git a/packages/llm/src/schema/events.ts b/packages/llm/src/schema/events.ts index 6e6bb1541b..6a088dc873 100644 --- a/packages/llm/src/schema/events.ts +++ b/packages/llm/src/schema/events.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { ContentBlockID, FinishReason, ProtocolID, ProviderMetadata, ResponseID, RouteID, ToolCallID } from "./ids" +import { ContentBlockID, FinishReason, ProtocolID, ProviderMetadata, RouteID, ToolCallID } from "./ids" import { ModelRef } from "./options" import { ToolResultValue } from "./messages" @@ -66,14 +66,13 @@ export class Usage extends Schema.Class("LLM.Usage")({ get visibleOutputTokens() { return Math.max(0, (this.outputTokens ?? 0) - (this.reasoningTokens ?? 0)) } + + static from(input: UsageInput) { + return input instanceof Usage ? input : new Usage(input) + } } -export const RequestStart = Schema.Struct({ - type: Schema.tag("request-start"), - id: ResponseID, - model: ModelRef, -}).annotate({ identifier: "LLM.Event.RequestStart" }) -export type RequestStart = Schema.Schema.Type +export type UsageInput = Usage | ConstructorParameters[0] export const StepStart = Schema.Struct({ type: Schema.tag("step-start"), @@ -185,13 +184,13 @@ export const StepFinish = Schema.Struct({ }).annotate({ identifier: "LLM.Event.StepFinish" }) export type StepFinish = Schema.Schema.Type -export const RequestFinish = Schema.Struct({ - type: Schema.tag("request-finish"), +export const Finish = Schema.Struct({ + type: Schema.tag("finish"), reason: FinishReason, usage: Schema.optional(Usage), providerMetadata: Schema.optional(ProviderMetadata), -}).annotate({ identifier: "LLM.Event.RequestFinish" }) -export type RequestFinish = Schema.Schema.Type +}).annotate({ identifier: "LLM.Event.Finish" }) +export type Finish = Schema.Schema.Type export const ProviderErrorEvent = Schema.Struct({ type: Schema.tag("provider-error"), @@ -202,7 +201,6 @@ export const ProviderErrorEvent = Schema.Struct({ export type ProviderErrorEvent = Schema.Schema.Type const llmEventTagged = Schema.Union([ - RequestStart, StepStart, TextStart, TextDelta, @@ -217,13 +215,15 @@ const llmEventTagged = Schema.Union([ ToolResult, ToolError, StepFinish, - RequestFinish, + Finish, ProviderErrorEvent, ]).pipe(Schema.toTaggedUnion("type")) type WithID = Omit & { readonly id: ID | string } +type WithUsage = Omit & { + readonly usage?: UsageInput +} -const responseID = (value: ResponseID | string) => ResponseID.make(value) const contentBlockID = (value: ContentBlockID | string) => ContentBlockID.make(value) const toolCallID = (value: ToolCallID | string) => ToolCallID.make(value) @@ -233,7 +233,6 @@ const toolCallID = (value: ToolCallID | string) => ToolCallID.make(value) * `events.filter(LLMEvent.guards["tool-call"])`. */ export const LLMEvent = Object.assign(llmEventTagged, { - requestStart: (input: WithID) => RequestStart.make({ ...input, id: responseID(input.id) }), stepStart: StepStart.make, textStart: (input: WithID) => TextStart.make({ ...input, id: contentBlockID(input.id) }), textDelta: (input: WithID) => TextDelta.make({ ...input, id: contentBlockID(input.id) }), @@ -252,11 +251,18 @@ export const LLMEvent = Object.assign(llmEventTagged, { toolCall: (input: WithID) => ToolCall.make({ ...input, id: toolCallID(input.id) }), toolResult: (input: WithID) => ToolResult.make({ ...input, id: toolCallID(input.id) }), toolError: (input: WithID) => ToolError.make({ ...input, id: toolCallID(input.id) }), - stepFinish: StepFinish.make, - requestFinish: RequestFinish.make, + stepFinish: (input: WithUsage) => + StepFinish.make({ + ...input, + usage: input.usage === undefined ? undefined : Usage.from(input.usage), + }), + finish: (input: WithUsage) => + Finish.make({ + ...input, + usage: input.usage === undefined ? undefined : Usage.from(input.usage), + }), providerError: ProviderErrorEvent.make, is: { - requestStart: llmEventTagged.guards["request-start"], stepStart: llmEventTagged.guards["step-start"], textStart: llmEventTagged.guards["text-start"], textDelta: llmEventTagged.guards["text-delta"], @@ -271,7 +277,7 @@ export const LLMEvent = Object.assign(llmEventTagged, { toolResult: llmEventTagged.guards["tool-result"], toolError: llmEventTagged.guards["tool-error"], stepFinish: llmEventTagged.guards["step-finish"], - requestFinish: llmEventTagged.guards["request-finish"], + finish: llmEventTagged.guards.finish, providerError: llmEventTagged.guards["provider-error"], }, }) diff --git a/packages/llm/src/tool-runtime.ts b/packages/llm/src/tool-runtime.ts index f464525827..d83dcc67ad 100644 --- a/packages/llm/src/tool-runtime.ts +++ b/packages/llm/src/tool-runtime.ts @@ -12,6 +12,7 @@ import { ToolFailure, ToolResultPart, type ToolResultValue, + Usage, } from "./schema" import { type AnyTool, type ExecutableTools, type Tools, toDefinitions } from "./tool" @@ -72,19 +73,42 @@ export const stream = (options: StreamOptions): Stream.Strea tools: [...options.request.tools.filter((tool) => !runtimeToolNames.has(tool.name)), ...runtimeTools], }) - const loop = (request: LLMRequest, step: number): Stream.Stream => + const loop = ( + request: LLMRequest, + step: number, + usage: Usage | undefined, + providerMetadata: ProviderMetadata | undefined, + ): Stream.Stream => Stream.unwrap( Effect.gen(function* () { - const state: StepState = { assistantContent: [], toolCalls: [], finishReason: undefined } + const state: StepState = { + assistantContent: [], + toolCalls: [], + finishReason: undefined, + usage: undefined, + providerMetadata: undefined, + } const modelStream = options .stream(request) + .pipe(Stream.map((event) => indexStep(event, step))) .pipe(Stream.tap((event) => Effect.sync(() => accumulate(state, event)))) + .pipe(Stream.filter((event) => event.type !== "finish")) const continuation = Stream.unwrap( Effect.gen(function* () { - if (state.finishReason !== "tool-calls" || state.toolCalls.length === 0) return Stream.empty - if (options.toolExecution === "none") return Stream.empty + const totalUsage = addUsage(usage, state.usage) + const totalProviderMetadata = mergeProviderMetadata(providerMetadata, state.providerMetadata) + const finishStream = Stream.fromIterable([ + LLMEvent.finish({ + reason: state.finishReason ?? "unknown", + usage: totalUsage, + providerMetadata: totalProviderMetadata, + }), + ]) + + if (state.finishReason !== "tool-calls" || state.toolCalls.length === 0) return finishStream + if (options.toolExecution === "none") return finishStream const dispatched = yield* Effect.forEach( state.toolCalls, @@ -93,10 +117,14 @@ export const stream = (options: StreamOptions): Stream.Strea ) const resultStream = Stream.fromIterable(dispatched.flatMap(([call, result]) => emitEvents(call, result))) - if (!options.stopWhen) return resultStream - if (options.stopWhen({ step, request })) return resultStream + if (!options.stopWhen) return resultStream.pipe(Stream.concat(finishStream)) + if (options.stopWhen({ step, request })) return resultStream.pipe(Stream.concat(finishStream)) - return resultStream.pipe(Stream.concat(loop(followUpRequest(request, state, dispatched), step + 1))) + return resultStream.pipe( + Stream.concat( + loop(followUpRequest(request, state, dispatched), step + 1, totalUsage, totalProviderMetadata), + ), + ) }), ) @@ -104,13 +132,21 @@ export const stream = (options: StreamOptions): Stream.Strea }), ) - return loop(initialRequest, 0) + return loop(initialRequest, 0, undefined, undefined) +} + +const indexStep = (event: LLMEvent, index: number): LLMEvent => { + if (event.type === "step-start") return LLMEvent.stepStart({ index }) + if (event.type === "step-finish") return LLMEvent.stepFinish({ ...event, index }) + return event } interface StepState { assistantContent: ContentPart[] toolCalls: ToolCallPart[] finishReason: FinishReason | undefined + usage: Usage | undefined + providerMetadata: ProviderMetadata | undefined } const accumulate = (state: StepState, event: LLMEvent) => { @@ -154,9 +190,43 @@ const accumulate = (state: StepState, event: LLMEvent) => { ) return } - if (event.type === "step-finish" || event.type === "request-finish") { + if (event.type === "step-finish") { state.finishReason = event.reason === "stop" && state.toolCalls.length > 0 ? "tool-calls" : event.reason + state.usage = addUsage(state.usage, event.usage) + state.providerMetadata = mergeProviderMetadata(state.providerMetadata, event.providerMetadata) + return } + if (event.type === "finish") { + state.finishReason ??= event.reason + state.usage ??= event.usage + state.providerMetadata = mergeProviderMetadata(state.providerMetadata, event.providerMetadata) + } +} + +const addUsage = (left: Usage | undefined, right: Usage | undefined) => { + if (!left) return right + if (!right) return left + type UsageKey = + | "inputTokens" + | "outputTokens" + | "nonCachedInputTokens" + | "cacheReadInputTokens" + | "cacheWriteInputTokens" + | "reasoningTokens" + | "totalTokens" + const sum = (key: UsageKey) => + left[key] === undefined && right[key] === undefined ? undefined : Number(left[key] ?? 0) + Number(right[key] ?? 0) + + return new Usage({ + inputTokens: sum("inputTokens"), + outputTokens: sum("outputTokens"), + nonCachedInputTokens: sum("nonCachedInputTokens"), + cacheReadInputTokens: sum("cacheReadInputTokens"), + cacheWriteInputTokens: sum("cacheWriteInputTokens"), + reasoningTokens: sum("reasoningTokens"), + totalTokens: sum("totalTokens"), + providerMetadata: mergeProviderMetadata(left.providerMetadata, right.providerMetadata), + }) } const sameProviderMetadata = (left: ProviderMetadata | undefined, right: ProviderMetadata | undefined) => @@ -200,17 +270,17 @@ const dispatch = (tools: Tools, call: ToolCallPart): Effect.Effect Effect.succeed({ type: "error" as const, value: failure.message } satisfies ToolResultValue), ), ) } -const decodeAndExecute = (tool: AnyTool, input: unknown): Effect.Effect => - tool._decode(input).pipe( +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)), + Effect.flatMap((decoded) => tool.execute!(decoded, { id: call.id, name: call.name })), Effect.flatMap((value) => tool._encode(value).pipe( Effect.mapError( diff --git a/packages/llm/src/tool.ts b/packages/llm/src/tool.ts index 311c8798b6..df0a1cd3d3 100644 --- a/packages/llm/src/tool.ts +++ b/packages/llm/src/tool.ts @@ -1,5 +1,5 @@ import { Effect, JsonSchema, Schema } from "effect" -import type { ToolDefinition as ToolDefinitionClass } from "./schema" +import type { ToolCallPart, ToolDefinition as ToolDefinitionClass } from "./schema" import { ToolDefinition, ToolFailure } from "./schema" /** @@ -8,9 +8,14 @@ import { ToolDefinition, ToolFailure } from "./schema" * beyond pure data conversion belongs in the handler closure. */ export type ToolSchema = Schema.Codec +export interface ToolExecuteContext { + readonly id: ToolCallPart["id"] + readonly name: ToolCallPart["name"] +} export type ToolExecute, Success extends ToolSchema> = ( params: Schema.Schema.Type, + context?: ToolExecuteContext, ) => Effect.Effect, ToolFailure> /** @@ -61,7 +66,7 @@ type TypedToolConfig = { type DynamicToolConfig = { readonly description: string readonly jsonSchema: JsonSchema.JsonSchema - readonly execute?: (params: unknown) => Effect.Effect + readonly execute?: (params: unknown, context?: ToolExecuteContext) => Effect.Effect } /** @@ -110,7 +115,7 @@ export function make, Success extends ToolSch export function make(config: { readonly description: string readonly jsonSchema: JsonSchema.JsonSchema - readonly execute: (params: unknown) => Effect.Effect + readonly execute: (params: unknown, context?: ToolExecuteContext) => Effect.Effect }): AnyExecutableTool export function make(config: { readonly description: string diff --git a/packages/llm/test/adapter.test.ts b/packages/llm/test/adapter.test.ts index 5ac8b9d818..80349a5ae5 100644 --- a/packages/llm/test/adapter.test.ts +++ b/packages/llm/test/adapter.test.ts @@ -51,7 +51,7 @@ const request = LLM.request({ const raiseEvent = (event: FakeEvent): import("../src/schema").LLMEvent => event.type === "finish" - ? { type: "request-finish", reason: event.reason } + ? { type: "finish", reason: event.reason } : { type: "text-delta", id: "text-0", text: event.text } const fakeProtocol = Protocol.make({ @@ -112,8 +112,8 @@ describe("llm route", () => { const events = Array.from(yield* llm.stream(request).pipe(Stream.runCollect)) const response = yield* llm.generate(request) - expect(events.map((event) => event.type)).toEqual(["text-delta", "request-finish"]) - expect(response.events.map((event) => event.type)).toEqual(["text-delta", "request-finish"]) + expect(events.map((event) => event.type)).toEqual(["text-delta", "finish"]) + expect(response.events.map((event) => event.type)).toEqual(["text-delta", "finish"]) }), ) diff --git a/packages/llm/test/llm.test.ts b/packages/llm/test/llm.test.ts index c01fe33b29..a20c48411e 100644 --- a/packages/llm/test/llm.test.ts +++ b/packages/llm/test/llm.test.ts @@ -127,7 +127,7 @@ describe("llm constructors", () => { LLMResponse.text({ events: [ { type: "text-delta", id: "text-0", text: "hi" }, - { type: "request-finish", reason: "stop" }, + { type: "finish", reason: "stop" }, ], }), ).toBe("hi") diff --git a/packages/llm/test/provider/anthropic-messages.test.ts b/packages/llm/test/provider/anthropic-messages.test.ts index 6417f73c2b..71204bcd63 100644 --- a/packages/llm/test/provider/anthropic-messages.test.ts +++ b/packages/llm/test/provider/anthropic-messages.test.ts @@ -124,7 +124,7 @@ describe("Anthropic Messages route", () => { providerMetadata: { anthropic: { signature: "sig_1" } }, }) expect(response.events.at(-1)).toMatchObject({ - type: "request-finish", + type: "finish", reason: "stop", providerMetadata: { anthropic: { stopSequence: "\n\nHuman:" } }, }) @@ -182,7 +182,7 @@ describe("Anthropic Messages route", () => { }, { type: "step-finish", index: 0, reason: "tool-calls", usage, providerMetadata: undefined }, { - type: "request-finish", + type: "finish", reason: "tool-calls", providerMetadata: undefined, usage, @@ -275,7 +275,7 @@ describe("Anthropic Messages route", () => { providerMetadata: { anthropic: { blockType: "web_search_tool_result" } }, }) expect(response.text).toBe("Found it.") - expect(response.events.at(-1)).toMatchObject({ type: "request-finish", reason: "stop" }) + expect(response.events.at(-1)).toMatchObject({ type: "finish", reason: "stop" }) }), ) diff --git a/packages/llm/test/provider/bedrock-converse.test.ts b/packages/llm/test/provider/bedrock-converse.test.ts index 7d1ad3f309..ffdd6e8008 100644 --- a/packages/llm/test/provider/bedrock-converse.test.ts +++ b/packages/llm/test/provider/bedrock-converse.test.ts @@ -169,12 +169,12 @@ describe("Bedrock Converse route", () => { const response = yield* LLMClient.generate(baseRequest).pipe(Effect.provide(fixedBytes(body))) expect(response.text).toBe("Hello!") - const finishes = response.events.filter((event) => event.type === "request-finish") + const finishes = response.events.filter((event) => event.type === "finish") // Bedrock splits the finish across `messageStop` (carries reason) and // `metadata` (carries usage). We consolidate them into a single - // terminal `request-finish` event with both. + // terminal `finish` event with both. expect(finishes).toHaveLength(1) - expect(finishes[0]).toMatchObject({ type: "request-finish", reason: "stop" }) + expect(finishes[0]).toMatchObject({ type: "finish", reason: "stop" }) expect(response.usage).toMatchObject({ inputTokens: 5, outputTokens: 2, @@ -213,7 +213,7 @@ describe("Bedrock Converse route", () => { { type: "tool-input-delta", id: "tool_1", name: "lookup", text: '{"query"' }, { type: "tool-input-delta", id: "tool_1", name: "lookup", text: ':"weather"}' }, ]) - expect(response.events.at(-1)).toMatchObject({ type: "request-finish", reason: "tool-calls" }) + expect(response.events.at(-1)).toMatchObject({ type: "finish", reason: "tool-calls" }) }), ) diff --git a/packages/llm/test/provider/gemini.test.ts b/packages/llm/test/provider/gemini.test.ts index 80c32c58b3..7e6bbc8466 100644 --- a/packages/llm/test/provider/gemini.test.ts +++ b/packages/llm/test/provider/gemini.test.ts @@ -232,7 +232,7 @@ describe("Gemini route", () => { { type: "text-end", id: "text-0" }, { type: "step-finish", index: 0, reason: "stop", usage, providerMetadata: undefined }, { - type: "request-finish", + type: "finish", reason: "stop", usage, }, @@ -291,7 +291,7 @@ describe("Gemini route", () => { }, { type: "step-finish", index: 0, reason: "tool-calls", usage, providerMetadata: undefined }, { - type: "request-finish", + type: "finish", reason: "tool-calls", usage, }, @@ -325,7 +325,7 @@ describe("Gemini route", () => { { type: "tool-call", id: "tool_0", name: "lookup", input: { query: "weather" } }, { type: "tool-call", id: "tool_1", name: "lookup", input: { query: "news" } }, ]) - expect(response.events.at(-1)).toMatchObject({ type: "request-finish", reason: "tool-calls" }) + expect(response.events.at(-1)).toMatchObject({ type: "finish", reason: "tool-calls" }) }), ) @@ -344,10 +344,10 @@ describe("Gemini route", () => { ), ) - expect(length.events.map((event) => event.type)).toEqual(["step-start", "step-finish", "request-finish"]) - expect(length.events.at(-1)).toMatchObject({ type: "request-finish", reason: "length" }) - expect(filtered.events.map((event) => event.type)).toEqual(["step-start", "step-finish", "request-finish"]) - expect(filtered.events.at(-1)).toMatchObject({ type: "request-finish", reason: "content-filter" }) + expect(length.events.map((event) => event.type)).toEqual(["step-start", "step-finish", "finish"]) + expect(length.events.at(-1)).toMatchObject({ type: "finish", reason: "length" }) + expect(filtered.events.map((event) => event.type)).toEqual(["step-start", "step-finish", "finish"]) + expect(filtered.events.at(-1)).toMatchObject({ type: "finish", reason: "content-filter" }) }), ) diff --git a/packages/llm/test/provider/openai-chat.test.ts b/packages/llm/test/provider/openai-chat.test.ts index 115c58849c..4303a69ffa 100644 --- a/packages/llm/test/provider/openai-chat.test.ts +++ b/packages/llm/test/provider/openai-chat.test.ts @@ -249,7 +249,7 @@ describe("OpenAI Chat route", () => { { type: "text-end", id: "text-0" }, { type: "step-finish", index: 0, reason: "stop", usage, providerMetadata: undefined }, { - type: "request-finish", + type: "finish", reason: "stop", usage, }, @@ -288,7 +288,7 @@ describe("OpenAI Chat route", () => { providerMetadata: undefined, }, { type: "step-finish", index: 0, reason: "tool-calls", usage: undefined, providerMetadata: undefined }, - { type: "request-finish", reason: "tool-calls", usage: undefined }, + { type: "finish", reason: "tool-calls", usage: undefined }, ]) }), ) diff --git a/packages/llm/test/provider/openai-compatible-chat.test.ts b/packages/llm/test/provider/openai-compatible-chat.test.ts index 7759ff7202..50aac41091 100644 --- a/packages/llm/test/provider/openai-compatible-chat.test.ts +++ b/packages/llm/test/provider/openai-compatible-chat.test.ts @@ -231,7 +231,7 @@ describe("OpenAI-compatible Chat route", () => { expect(response.text).toBe("Hello!") expect(response.usage).toMatchObject({ inputTokens: 5, outputTokens: 2, totalTokens: 7 }) - expect(response.events.at(-1)).toMatchObject({ type: "request-finish", reason: "stop" }) + expect(response.events.at(-1)).toMatchObject({ type: "finish", reason: "stop" }) }), ) }) diff --git a/packages/llm/test/provider/openai-responses.test.ts b/packages/llm/test/provider/openai-responses.test.ts index 8b4469f4ed..63452f61b0 100644 --- a/packages/llm/test/provider/openai-responses.test.ts +++ b/packages/llm/test/provider/openai-responses.test.ts @@ -366,7 +366,7 @@ describe("OpenAI Responses route", () => { usage, }, { - type: "request-finish", + type: "finish", reason: "stop", providerMetadata: { openai: { responseId: "resp_1", serviceTier: "default" } }, usage, @@ -447,7 +447,7 @@ describe("OpenAI Responses route", () => { }, { type: "step-finish", index: 0, reason: "tool-calls", usage, providerMetadata: undefined }, { - type: "request-finish", + type: "finish", reason: "tool-calls", providerMetadata: undefined, usage, diff --git a/packages/llm/test/recorded-scenarios.ts b/packages/llm/test/recorded-scenarios.ts index bdba8580fd..3af7a77608 100644 --- a/packages/llm/test/recorded-scenarios.ts +++ b/packages/llm/test/recorded-scenarios.ts @@ -120,8 +120,8 @@ export const runWeatherToolLoop = (request: LLMRequest) => export const expectFinish = ( events: ReadonlyArray, - reason: Extract["reason"], -) => expect(events.at(-1)).toMatchObject({ type: "request-finish", reason }) + reason: Extract["reason"], +) => expect(events.at(-1)).toMatchObject({ type: "finish", reason }) export const expectWeatherToolCall = (response: LLMResponse) => expect(response.toolCalls).toMatchObject([ @@ -129,10 +129,12 @@ export const expectWeatherToolCall = (response: LLMResponse) => ]) export const expectWeatherToolLoop = (events: ReadonlyArray) => { - const finishes = events.filter(LLMEvent.is.requestFinish) - expect(finishes).toHaveLength(2) - expect(finishes[0]?.reason).toBe("tool-calls") - expect(finishes.at(-1)?.reason).toBe("stop") + const finishes = events.filter(LLMEvent.is.finish) + expect(finishes).toHaveLength(1) + expect(finishes[0]?.reason).toBe("stop") + + const stepFinishes = events.filter(LLMEvent.is.stepFinish) + expect(stepFinishes.map((event) => event.reason)).toEqual(["tool-calls", "stop"]) const toolCalls = events.filter(LLMEvent.is.toolCall) expect(toolCalls).toHaveLength(1) @@ -272,7 +274,7 @@ export const eventSummary = (events: ReadonlyArray) => { summary.push({ type: "tool-error", name: event.name, message: event.message }) continue } - if (event.type === "request-finish") { + if (event.type === "finish") { summary.push({ type: "finish", reason: event.reason, usage: usageSummary(event.usage) }) } } diff --git a/packages/llm/test/schema.test.ts b/packages/llm/test/schema.test.ts index 23bd9fd9bb..01d6fadd9f 100644 --- a/packages/llm/test/schema.test.ts +++ b/packages/llm/test/schema.test.ts @@ -44,6 +44,11 @@ describe("llm schema", () => { expect(() => Schema.decodeUnknownSync(LLMEvent)({ type: "bogus" })).toThrow() }) + test("finish constructors accept usage input", () => { + expect(LLMEvent.stepFinish({ index: 0, reason: "stop", usage: { inputTokens: 1 } }).usage).toBeInstanceOf(Usage) + expect(LLMEvent.finish({ reason: "stop", usage: { outputTokens: 2 } }).usage).toBeInstanceOf(Usage) + }) + test("content part tagged union exposes guards", () => { expect(ContentPart.guards.text({ type: "text", text: "hi" })).toBe(true) expect(ContentPart.guards.media({ type: "text", text: "hi" })).toBe(false) diff --git a/packages/llm/test/tool-runtime.test.ts b/packages/llm/test/tool-runtime.test.ts index 040a11fb68..573021c4c2 100644 --- a/packages/llm/test/tool-runtime.test.ts +++ b/packages/llm/test/tool-runtime.test.ts @@ -4,7 +4,8 @@ import { GenerationOptions, LLM, LLMEvent, LLMRequest, LLMResponse, ToolChoice } import { LLMClient } from "../src/route" import * as AnthropicMessages from "../src/protocols/anthropic-messages" import * as OpenAIChat from "../src/protocols/openai-chat" -import { tool, ToolFailure } from "../src/tool" +import { tool, ToolFailure, type ToolExecuteContext } from "../src/tool" +import { ToolRuntime } from "../src/tool-runtime" import { it } from "./lib/effect" import * as TestToolRuntime from "./lib/tool-runtime" import { dynamicResponse, scriptedResponses } from "./lib/http" @@ -129,7 +130,7 @@ describe("LLMClient tools", () => { name: "get_weather", result: { type: "json", value: { temperature: 22, condition: "sunny" } }, }) - expect(events.at(-1)?.type).toBe("request-finish") + expect(events.at(-1)?.type).toBe("finish") expect(LLMResponse.text({ events })).toBe("It's sunny in Paris.") }), ) @@ -148,11 +149,40 @@ describe("LLMClient tools", () => { ), ) - expect(events.filter(LLMEvent.is.requestFinish)).toHaveLength(1) + expect(events.filter(LLMEvent.is.finish)).toHaveLength(1) expect(events.find(LLMEvent.is.toolResult)).toMatchObject({ type: "tool-result", id: "call_1" }) }), ) + it.effect("passes tool call context to execute", () => + Effect.gen(function* () { + let context: ToolExecuteContext | undefined + const contextual = tool({ + description: "Capture tool context.", + parameters: Schema.Struct({ value: Schema.String }), + success: Schema.Struct({ ok: Schema.Boolean }), + execute: (_params, ctx) => + Effect.sync(() => { + context = ctx + return { ok: true } + }), + }) + const events = Array.from( + yield* TestToolRuntime.runTools({ request: baseRequest, tools: { contextual } }).pipe( + Stream.runCollect, + Effect.provide( + scriptedResponses([ + sseEvents(toolCallChunk("call_ctx", "contextual", '{"value":"x"}'), finishChunk("tool_calls")), + ]), + ), + ), + ) + + expect(events.some(LLMEvent.is.toolResult)).toBe(true) + expect(context).toEqual({ id: "call_ctx", name: "contextual" }) + }), + ) + it.effect("can expose tool schemas without executing tool calls", () => Effect.gen(function* () { const layer = scriptedResponses([ @@ -319,7 +349,7 @@ describe("LLMClient tools", () => { "text-delta", "text-end", "step-finish", - "request-finish", + "finish", ]) expect(LLMResponse.text({ events })).toBe("Done.") }), @@ -343,7 +373,57 @@ describe("LLMClient tools", () => { ), ) - expect(events.filter(LLMEvent.is.requestFinish)).toHaveLength(2) + expect(events.filter(LLMEvent.is.finish)).toHaveLength(1) + expect(events.filter(LLMEvent.is.stepStart).map((event) => event.index)).toEqual([0, 1]) + expect(events.filter(LLMEvent.is.stepFinish).map((event) => event.index)).toEqual([0, 1]) + }), + ) + + it.effect("emits one final finish with aggregate usage", () => + Effect.gen(function* () { + let calls = 0 + const events = Array.from( + yield* ToolRuntime.stream({ + request: baseRequest, + tools: { get_weather }, + stopWhen: ToolRuntime.stepCountIs(2), + stream: () => + Stream.fromIterable( + calls++ === 0 + ? [ + LLMEvent.stepStart({ index: 0 }), + LLMEvent.toolCall({ id: "call_1", name: "get_weather", input: { city: "Paris" } }), + LLMEvent.stepFinish({ + index: 0, + reason: "tool-calls", + usage: { inputTokens: 1, outputTokens: 2, totalTokens: 3 }, + }), + LLMEvent.finish({ + reason: "tool-calls", + usage: { inputTokens: 1, outputTokens: 2, totalTokens: 3 }, + }), + ] + : [ + LLMEvent.stepStart({ index: 0 }), + LLMEvent.textDelta({ id: "text_1", text: "Done." }), + LLMEvent.stepFinish({ + index: 0, + reason: "stop", + usage: { inputTokens: 4, outputTokens: 5, totalTokens: 9 }, + }), + LLMEvent.finish({ reason: "stop", usage: { inputTokens: 4, outputTokens: 5, totalTokens: 9 } }), + ], + ), + }).pipe(Stream.runCollect), + ) + + expect(events.filter(LLMEvent.is.stepFinish).map((event) => event.index)).toEqual([0, 1]) + expect(events.filter(LLMEvent.is.finish)).toHaveLength(1) + expect(events.find(LLMEvent.is.finish)?.usage).toMatchObject({ + inputTokens: 5, + outputTokens: 7, + totalTokens: 12, + }) }), ) @@ -362,7 +442,7 @@ describe("LLMClient tools", () => { }).pipe(Stream.runCollect, Effect.provide(layer)), ) - expect(events.filter(LLMEvent.is.requestFinish)).toHaveLength(1) + expect(events.filter(LLMEvent.is.finish)).toHaveLength(1) expect(events.find(LLMEvent.is.toolResult)).toMatchObject({ type: "tool-result", id: "call_1" }) }), ) diff --git a/packages/opencode/package.json b/packages/opencode/package.json index e9b811fc5e..f3cea500c0 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -91,7 +91,6 @@ "@ai-sdk/openai-compatible": "2.0.41", "@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", @@ -108,6 +107,7 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", + "@opencode-ai/ui": "workspace:*", "@openrouter/ai-sdk-provider": "2.8.1", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.6.1", @@ -129,7 +129,6 @@ "bonjour-service": "1.3.0", "bun-pty": "0.4.8", "chokidar": "4.0.3", - "cli-sound": "1.1.3", "clipboardy": "4.0.0", "cross-spawn": "catalog:", "decimal.js": "10.5.0", @@ -141,6 +140,7 @@ "glob": "13.0.5", "google-auth-library": "10.5.0", "gray-matter": "4.0.3", + "htmlparser2": "8.0.2", "ignore": "7.0.5", "immer": "11.1.4", "jsonc-parser": "3.3.1", diff --git a/packages/opencode/specs/effect/errors.md b/packages/opencode/specs/effect/errors.md index e19199ef49..5266ca5101 100644 --- a/packages/opencode/specs/effect/errors.md +++ b/packages/opencode/specs/effect/errors.md @@ -1,41 +1,22 @@ -# Typed error migration +# Typed Error Migration -Plan for moving `packages/opencode` from temporary defect/`NamedError` -compatibility toward typed Effect service errors and explicit HTTP error -contracts. +This note expands the `ERR`, `RENDER`, and `HTTP` tracks from +[`todo.md`](./todo.md). It is the current reference for expected failures, +typed service errors, and HTTP error boundaries. ## Goal - Expected service failures live on the Effect error channel. - Service interfaces expose those failures in their return types. -- Domain errors are authored with Effect Schema so they are reusable by services, - tests, HTTP routes, tools, and OpenAPI generation. -- HTTP status codes and wire compatibility are handled at the HTTP boundary, not - inside service modules. -- `Effect.die`, `throw`, `catchDefect`, and global cause inspection are reserved - for defects, compatibility bridges, or final fallback behavior. +- Domain errors are authored with `Schema.TaggedErrorClass`. +- `Effect.die(...)` is reserved for defects: bugs, impossible states, + violated invariants, and final unknown-boundary fallbacks. +- HTTP status codes and public wire bodies are handled at HTTP route + boundaries, not inside service modules. +- User-facing boundaries render useful structured error details instead of + opaque `Error: SomeName` strings. -## Current State - -- Many migrated services use Effect internally, but expected failures are still a - mix of `NamedError.create(...)`, `namedSchemaError(...)`, `class extends Error`, - `throw`, and `Effect.die(...)`. -- Some services already use `Schema.TaggedErrorClass`, for example `Account`, - `Auth`, `Permission`, `Question`, `Installation`, and parts of - `Workspace`. -- The temporary HttpApi compatibility middleware recognizes `NamedError`, - `Session.BusyError`, and a few name-based cases, then emits the legacy - `{ name, data }` JSON body. -- Effect `HttpApi` only knows how to encode errors that are declared on the - endpoint, group, or middleware. Undeclared expected errors become defects and - eventually fall through to generic HTTP handling. -- The temporary HttpApi error middleware catches defect-wrapped legacy errors to - preserve runtime behavior, but it is intentionally a bridge rather than the - final model. - -## End State - -Service modules own domain failures. +## Service Error Shape ```ts export class SessionBusyError extends Schema.TaggedErrorClass()("SessionBusyError", { @@ -50,281 +31,90 @@ export interface Interface { } ``` -HTTP modules own transport mapping. +Rules: + +- Use `Schema.TaggedErrorClass` for expected domain failures. +- Export a domain-level `Error` union from each service module. +- Put expected errors in service method signatures. +- Use `yield* new DomainError(...)` for direct early failures in + `Effect.gen` / `Effect.fn`. +- Use `Schema.Defect` for unknown cause fields when preserving the cause is + useful for logs or callers. +- Use `Effect.try(...)`, `Effect.tryPromise(...)`, `Effect.mapError`, + `Effect.catchTag`, and `Effect.catchTags` to translate external + failures into domain errors. +- Do not use `throw`, `Effect.die(...)`, or `catchDefect` for expected + user, IO, validation, missing-resource, auth, provider, worktree, or + busy-state failures. + +## HTTP Boundary Shape + +Service modules stay transport-agnostic. They should not import HTTP +status codes, `HttpApiError`, `HttpServerResponse`, or route-specific +error schemas. + +HTTP handlers translate service errors into public endpoint errors: ```ts const get = Effect.fn("SessionHttpApi.get")(function* (ctx: { params: { sessionID: SessionID } }) { return yield* session .get(ctx.params.sessionID) - .pipe( - Effect.catchTag("StorageNotFoundError", () => new SessionNotFoundHttpError({ sessionID: ctx.params.sessionID })), - ) + .pipe(Effect.catchTag("StorageNotFoundError", () => notFound("Session not found"))) }) ``` -HTTP-visible error schemas carry their own response status through Effect -HttpApi's `httpApiStatus` annotation. Prefer `HttpApiSchema.status(...)`, or the -equivalent declaration annotation, instead of maintaining a parallel status map. +Endpoint definitions declare which public errors can be emitted. Public +HTTP error schemas carry their response status with `httpApiStatus` or the +equivalent HttpApi schema annotation. -```ts -export class SessionNotFoundHttpError extends Schema.TaggedErrorClass()( - "SessionNotFoundHttpError", - { - sessionID: SessionID, - message: Schema.String, - }, - { httpApiStatus: 404 }, -) {} -``` +The service error and HTTP error may be the same class only when the wire +shape is intentionally public. Use separate HTTP error schemas when the +service error contains internals, low-level causes, retry hints, or data +that should not be exposed to API clients. -Endpoint definitions still declare which HTTP-visible error schemas can be -emitted. The status annotation is only used if the error is part of the endpoint, -group, or middleware error schema and the handler fails with that error on the -typed error channel. +## Mapping Guidance -```ts -HttpApiEndpoint.get("get", SessionPaths.get, { - success: Session.Info, - error: [SessionNotFoundHttpError, SessionBusyHttpError], -}) -``` +- Keep one-off translations inline in the handler. +- Extract tiny shared helpers when the same translation repeats across a + route group. +- Do not create one giant `unknown -> status` mapper. +- Do not grow generic HTTP middleware into a registry of domain errors. +- Preserve existing public `{ name, data }` bodies until a deliberate + breaking API change. +- Use built-in `HttpApiError.*` only when its generated body and SDK + surface are intentionally the public contract. -The service error and HTTP error may be the same class when the wire shape is a -deliberate public contract. They should be different classes when the service -error contains internals, low-level causes, retry hints, or anything that should -not be exposed to API clients. +## Middleware Guidance -## Rules +HTTP middleware should be cross-cutting: auth, context, schema decode +formatting, routing, and final unknown-defect fallback. -- Use `Schema.TaggedErrorClass` for new expected domain errors. -- Include `cause: Schema.optional(Schema.Defect)` only when preserving an - underlying unknown failure is useful for logs or callers. -- Export a domain-level error union from each service module, for example - `export type Error = NotFoundError | BusyError | Storage.Error`. -- Put expected errors in service method signatures, for example - `Effect.Effect`. -- Use `yield* new DomainError(...)` for direct early failures inside - `Effect.gen` / `Effect.fn`. -- Use `Effect.try({ try, catch })`, `Effect.mapError`, or `Effect.catchTag` to - convert external exceptions into domain errors. -- Use `HttpApiSchema.status(...)` or `{ httpApiStatus: code }` on HTTP-visible - error schemas so Effect `HttpApiBuilder` and OpenAPI generation get the status - from the schema itself. -- Do not use `Effect.die(...)` for user, IO, validation, missing-resource, auth, - provider, worktree, or busy-state failures. -- Do not use `catchDefect` to recover expected domain errors. If recovery is - needed, the upstream effect should fail with a typed error instead. -- Do not make service modules import `HttpApiError`, `HttpServerResponse`, HTTP - status codes, or route-specific error schemas. -- Keep raw `HttpRouter` routes free to use `HttpServerRespondable` when that is - the right transport abstraction, but prefer declared `HttpApi` errors for - normal JSON API endpoints. +The current compatibility middleware still knows about some legacy domain +errors. As route groups declare expected errors and handlers map them, that +middleware should shrink. It should not gain new name checks. -## HTTP Boundary Shape +Unknown `500` responses should log full details server-side with +`Cause.pretty(cause)` and return a safe public body. -Create an HttpApi-local error module, likely -`src/server/routes/instance/httpapi/errors.ts`. +## Migration Order -That module should provide: +Prefer small vertical slices: -- Legacy-compatible public schemas for `{ name, data }` error bodies that must - remain SDK-compatible while route groups declare typed errors. -- Small constructors or mapping helpers for common API errors such as not found, - bad request, conflict, and unknown internal errors. -- Route-group-specific adapters only when they encode domain-specific public - data. -- A single place to document which public error shape is legacy-compatible and - which shape is new Effect-native API surface. +1. Fix rendering at one user-visible boundary. +2. Convert one service domain to `Schema.TaggedErrorClass` errors. +3. Map those errors at the affected HTTP handlers. +4. Remove the corresponding name-based middleware branch if possible. +5. Add or update focused tests for both service error tags and HTTP wire + bodies. -Avoid one giant `unknown -> status` mapper. Prefer small, explicit mappers close -to the handler or route group. +Good early domains are storage not-found, worktree errors, and provider +auth validation errors because they currently drive HTTP behavior. -```ts -const mapSessionError = (effect: Effect.Effect) => - effect.pipe( - Effect.catchTag("StorageNotFoundError", (error) => new SessionNotFoundHttpError({ message: error.message })), - Effect.catchTag("SessionBusyError", (error) => new SessionBusyHttpError({ message: error.message })), - ) -``` +## Checklist For A PR -Use built-in `HttpApiError.BadRequest`, `HttpApiError.NotFound`, and related -types only when their generated response body and SDK surface are intentionally -acceptable. Use a custom schema-backed error when clients need the legacy -`{ name, data }` body or a domain-specific error payload. - -## Migration Phases - -### 1. Stabilize The Bridge - -Keep the temporary HttpApi error middleware only as a compatibility bridge while -typed errors are introduced. - -- Add tests that prove the bridge catches legacy `NamedError` defects. -- Add tests that prove declared HttpApi errors still use the declared endpoint - contract. -- Stop returning stack traces in unknown HTTP `500` responses; log the full - `Cause.pretty(cause)` server-side instead. -- Add a comment or TODO that names this plan and states the bridge must shrink - as route groups migrate. - -### 2. Define The Shared HTTP Error Helpers - -Add the `httpapi/errors.ts` module before converting route groups. - -- Define a legacy `{ name, data }` body helper for SDK-compatible errors. -- Define `UnknownError` for generic internal failures with a safe public message. -- Define `BadRequestError` and `NotFoundError` equivalents only if the actual - wire body must match the existing SDK surface. -- Put the HTTP status on the public schema with `HttpApiSchema.status(...)` or - `{ httpApiStatus: code }`; do not keep a separate name-to-status table. -- Keep conversion helpers pure and small. They should not inspect `Cause` or - accept `unknown` unless they are final fallback helpers. - -### 3. Convert One Vertical Slice - -Start with session read routes because they already have local `mapNotFound` -logic and are heavily covered by existing HttpApi tests. - -- Convert `Session.BusyError` from a plain `Error` to a typed service error, or - add a typed wrapper while preserving the old constructor until callers are - migrated. -- Replace `catchDefect` in `httpapi/handlers/session.ts` with typed error - mapping. -- Add endpoint error schemas for the affected session endpoints. -- Prove behavior with focused tests in `test/server/httpapi-session.test.ts`. -- Remove the migrated cases from the global compatibility middleware. - -### 4. Convert Legacy NamedError Domains - -Move legacy `NamedError.create(...)` services to Effect Schema-backed errors in -small domain PRs. - -Priority order: - -1. `storage/storage.ts` and `storage/db.ts` not-found errors. -2. `worktree/index.ts` `Worktree*` errors. -3. `provider/auth.ts` validation failures and `provider/provider.ts` model-not-found errors. -4. `mcp/index.ts`, `skill/index.ts`, `lsp/client.ts`, and `ide/index.ts` service errors. -5. Config and CLI-only errors after HTTP-facing domains are stable. - -For each domain: - -- Replace `NamedError.create(...)` with `Schema.TaggedErrorClass` when the error - is primarily a service error. -- Keep or add a separate HTTP error schema when the legacy `{ name, data }` wire - shape must remain stable. -- Update service interface return types to include the new error union. -- Replace `throw new X(...)` inside `Effect.fn` with `yield* new X(...)`. -- Replace async exceptions with `Effect.try({ catch })` or explicit `mapError`. -- Add service-level tests that assert the error tag and data, not just the HTTP - status. - -### 5. Declare HttpApi Errors Group By Group - -For each HttpApi group: - -- Inventory every service call and the typed errors it can return. -- Add only the public error schemas that endpoint can actually emit. -- Map service errors to HTTP errors in the handler file. -- Keep built-in `HttpApiError` only for generic request/validation failures where - the generated contract is accepted. -- Update `httpapi/public.ts` compatibility transforms only when the generated - spec cannot represent the desired source shape directly. -- Regenerate the SDK after OpenAPI-visible changes and verify the diff is - intentional. - -Suggested route order: - -1. `session` not-found and busy-state reads. -2. `experimental` worktree mutations. -3. `provider` auth and model selection errors. -4. `mcp` OAuth and connection errors. -5. Remaining route groups as typed error contracts are declared. - -### 6. Remove Defect Recovery - -After enough route groups declare their expected errors: - -- Delete `catchDefect` recovery for domain errors. -- Delete name-prefix checks such as `error.name.startsWith("Worktree")` from - HTTP middleware. -- Delete `NamedError` branches from the Effect HttpApi compatibility middleware - once no Effect route depends on them. -- Leave one final unknown-defect fallback that logs server-side and returns a - safe generic `500` body. - -## Inventory Checklist - -Use this checklist when touching a service or route group. - -- [ ] Does the service interface expose every expected failure in the Effect - error type? -- [ ] Are user-caused, provider-caused, IO, auth, missing-resource, and busy-state - failures modeled as typed errors instead of defects? -- [ ] Does the service avoid importing HTTP status, `HttpApiError`, or response - classes? -- [ ] Does the handler map each service error into a declared endpoint error? -- [ ] Does the endpoint `error` field include every public error the handler can - emit? -- [ ] Does OpenAPI/SDK output either stay byte-identical or have an explicitly - reviewed diff? -- [ ] Do tests cover both service-level error typing and HTTP-level status/body? -- [ ] Did the PR remove any now-unneeded case from the temporary compatibility - middleware? - -## Testing Requirements - -For service conversions: - -- Test the service method directly with `testEffect(...)`. -- Assert on `_tag` or class identity and the structured fields. -- Avoid testing by string-matching `Cause.pretty(...)`. - -For HttpApi conversions: - -- Add or update the focused `test/server/httpapi-*.test.ts` file. -- Assert status code, content type, and exact JSON body for declared public - errors. -- Add a regression test that the temporary middleware is no longer needed for the - migrated route. -- Keep compatibility tests aligned with the existing SDK contract until the - public error shape intentionally changes. - -## Verification Commands - -Run from `packages/opencode` unless noted otherwise. - -```bash -bun run prettier --write -bunx oxlint -bun typecheck -bun run test -- test/server/httpapi-session.test.ts -``` - -Run SDK generation from the repo root when schemas or OpenAPI-visible errors -change. - -```bash -./packages/sdk/js/script/build.ts -``` - -## Open Questions - -- Should legacy V1 routes keep `{ name, data }` forever while V2 routes expose a - more Effect-native tagged error body? -- Should storage not-found remain generic, or should callers map it to - domain-specific not-found errors before crossing service boundaries? -- Should `namedSchemaError(...)` stay as a long-term public-wire helper, or only - as a migration bridge for old `NamedError` contracts? -- Which SDK version boundary lets us stop remapping built-in Effect HttpApi error - schemas in `httpapi/public.ts`? - -## Success Criteria - -- New service code no longer uses `die` for expected failures. -- A route reviewer can read an endpoint definition and see every public error it - can return. -- The temporary HttpApi error middleware shrinks over time instead of gaining new - name-based cases. -- Service tests prove domain error types without going through HTTP. -- HTTP tests prove status/body contracts without relying on defect recovery. +- [ ] Expected failures are typed errors, not defects. +- [ ] Service method signatures expose the expected error union. +- [ ] HTTP handlers translate domain errors at the boundary. +- [ ] Public HTTP error bodies preserve existing wire contracts. +- [ ] Generic middleware gets smaller or stays unchanged. +- [ ] Focused tests cover the service error and any public HTTP response. diff --git a/packages/opencode/specs/effect/guide.md b/packages/opencode/specs/effect/guide.md new file mode 100644 index 0000000000..5df0293448 --- /dev/null +++ b/packages/opencode/specs/effect/guide.md @@ -0,0 +1,251 @@ +# Effect Guide + +How we write Effect code in `packages/opencode`. The companion roadmap is +[`todo.md`](./todo.md). + +This guide describes the preferred shape for new work and migrations. If a +legacy file differs, migrate it only when it is already in scope. + +## Service Shape + +Use one module per service: flat top-level exports, traced Effect methods, +explicit layers, and a self-reexport at the bottom. + +```ts +export interface Interface { + readonly get: (id: FooID) => Effect.Effect +} + +export class Service extends Context.Service()("@opencode/Foo") {} + +export const layer = Layer.effect( + Service, + Effect.gen(function* () { + const state = yield* InstanceState.make(Effect.fn("Foo.state")(() => Effect.succeed({}))) + + const get = Effect.fn("Foo.get")(function* (id: FooID) { + const s = yield* InstanceState.get(state) + return yield* loadFoo(s, id) + }) + + return Service.of({ get }) + }), +) + +export const defaultLayer = layer.pipe(Layer.provide(FooDep.defaultLayer)) + +export * as Foo from "./foo" +``` + +Rules: + +- Do not use `export namespace Foo { ... }`. +- Use `Effect.fn("Foo.method")` for public service methods. +- Use `Effect.fnUntraced` for small internal helpers that do not need a + span. +- Keep helpers as non-exported top-level declarations in the same file. +- Self-reexport with `export * as Foo from "."` for `index.ts`, otherwise + `export * as Foo from "./foo"`. +- In `src/config`, keep the existing top-of-file self-export pattern. + +## Runtime Boundaries + +Most code should run through [`AppRuntime`](../../src/effect/app-runtime.ts). +It hosts `AppLayer`, shares the global `memoMap`, and restores the current +instance/workspace refs when crossing from non-Effect code. + +Use `AppRuntime.runPromise(effect)` at app boundaries such as CLI commands, +HTTP handlers, or plain async adapters. + +`makeRuntime(...)` still exists for a few intentional service-local +boundaries and migration leftovers. Do not add a new service-local runtime +unless the service truly cannot live in `AppLayer`. + +## Runtime Flags + +Read opencode runtime flags through +[`RuntimeFlags.Service`](../../src/effect/runtime-flags.ts), not through +mutable `Flag` or late `process.env` reads. + +Tests should vary behavior with explicit layer variants: + +```ts +const it = testEffect(MyService.defaultLayer.pipe(Layer.provide(RuntimeFlags.layer({ experimentalScout: true })))) +``` + +Do not mutate `process.env` or `Flag` after services/layers are built. + +## Per-Instance State + +Use [`InstanceState`](../../src/effect/instance-state.ts) when two open +directories should not share one copy of a service's state. It is backed by +a `ScopedCache`, keyed by directory, and disposed automatically when an +instance is unloaded. + +Put subscriptions, finalizers, and scoped background work inside the +`InstanceState.make(...)` initializer: + +```ts +const cache = + yield * + InstanceState.make( + Effect.fn("Foo.state")(function* () { + const bus = yield* Bus.Service + + yield* bus.subscribeAll().pipe( + Stream.runForEach((event) => handleEvent(event)), + Effect.forkScoped, + ) + + yield* Effect.acquireRelease(openResource, closeResource) + + return yield* loadInitialState() + }), + ) +``` + +Do not add separate `started` flags on top of `InstanceState`. Let +`ScopedCache` handle run-once and deduplication. + +To make `init()` non-blocking, fork at the caller/bootstrap boundary. Do +not fork inside `InstanceState.make(...)` just to return early with +partially initialized state. + +## Errors + +Expected domain failures belong on the Effect error channel. Defects are +for bugs, impossible states, and final unknown-boundary fallbacks. + +```ts +export class SessionBusyError extends Schema.TaggedErrorClass()("SessionBusyError", { + sessionID: SessionID, + message: Schema.String, +}) {} + +export type Error = Storage.Error | SessionBusyError + +export interface Interface { + readonly get: (id: SessionID) => Effect.Effect +} +``` + +Rules: + +- Use `Schema.TaggedErrorClass` for new expected domain errors. +- Export a domain-level `Error` union from service modules. +- In `Effect.gen` / `Effect.fn`, prefer `yield* new MyError(...)` for + direct expected failures. +- Use `Schema.Defect` for unknown cause fields. +- Use `Effect.try(...)`, `Effect.tryPromise(...)`, `Effect.mapError`, + `Effect.catchTag`, and `Effect.catchTags` to translate external + failures into domain errors. +- Do not use `Effect.die(...)` for user, IO, validation, missing-resource, + auth, provider, or busy-state failures. + +## HTTP Error Boundaries + +Service modules stay HTTP-agnostic. They should not import HTTP status +codes, `HttpApiError`, `HttpServerResponse`, or route-specific error +schemas. + +HTTP handlers translate service errors into endpoint-declared public error +schemas. Keep mappings inline when they are one-off; extract tiny shared +helpers only when the same translation repeats. + +Do not turn generic middleware into a registry of domain errors. Middleware +should handle cross-cutting concerns and the final unknown-defect fallback. + +Preserve legacy public wire shapes, such as `{ name, data }`, until a +deliberate breaking API change. + +## Schemas + +Use Effect Schema as the source of truth. + +- Use `Schema.Class` for exported data objects with a clear identity. +- Use `Schema.Struct` for local shapes and simple nested objects. +- Use `Schema.brand` for single-value IDs. +- Reuse named refinements instead of re-spelling constraints. +- Prefer narrow boundary helpers over generic Schema-to-Zod bridges. + +Intentional boundaries: + +- Public plugin tools still expose Zod through `tool.schema = z`. +- Tool parameter JSON Schema is generated through tool-specific helpers. +- Public config and TUI schemas are generated through the schema script. + +## Preferred Services + +In effectified code, yield existing services instead of dropping to ad hoc +platform APIs. + +- Use `AppFileSystem.Service` instead of raw `fs/promises` for app file IO. +- Use `AppProcess.Service` instead of direct `ChildProcessSpawner.spawn` or + legacy process helpers. +- Use `HttpClient.HttpClient` instead of raw `fetch` inside Effect code. +- Use `Path.Path`, `Config`, `Clock`, and `DateTime` when already inside + Effect. +- Use `Effect.callback` for callback-based APIs. +- Use `Effect.void` instead of `Effect.succeed(undefined)`. +- Use `Effect.cached` when concurrent callers should share one in-flight + computation. + +For background loops, use `Effect.repeat` or `Effect.schedule` with +`Effect.forkScoped` in the owning layer/state scope. + +## Promise And ALS Bridges + +[`EffectBridge`](../../src/effect/bridge.ts) is the sanctioned helper for +Promise/callback interop that needs to preserve instance/workspace context. +Keep it, but reduce its dependency on legacy `Instance.current` / +`Instance.restore` over time. + +`Instance.bind` / `Instance.restore` are transitional legacy tools. Use +them only for native callbacks that still require legacy ALS context. Do +not use them for `setTimeout`, `Promise.then`, `EventEmitter.on`, or +Effect fibers. + +## Testing + +Detailed test migration rules live in +[`test/EFFECT_TEST_MIGRATION.md`](../../test/EFFECT_TEST_MIGRATION.md). + +Core pattern: + +```ts +const it = testEffect(Layer.mergeAll(MyService.defaultLayer)) + +describe("my service", () => { + it.instance("does the thing", () => + Effect.gen(function* () { + const svc = yield* MyService.Service + expect(yield* svc.run()).toEqual("ok") + }), + ) +}) +``` + +Rules: + +- Use `it.effect(...)` for TestClock/TestConsole tests. +- Use `it.live(...)` for real timers, filesystem mtimes, child processes, + git, locks, or other live integration behavior. +- Use `it.instance(...)` for service tests that need a scoped instance. +- Prefer Effect-aware fixtures from `test/fixture/fixture.ts`. +- Avoid sleeps; wait for real events or deterministic state transitions. +- Avoid mutable `process.env`, `Flag`, or module-global changes after + layers are built. +- Use `Layer.mock` for partial service stubs. +- Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` test + wrappers. + +## Verification + +From `packages/opencode`: + +```bash +bun run typecheck +bun run test -- path/to/test.ts +``` + +Do not run tests from the repo root; the repo has a guard for that. diff --git a/packages/opencode/specs/effect/migration.md b/packages/opencode/specs/effect/migration.md index 13838e833d..5355feccc7 100644 --- a/packages/opencode/specs/effect/migration.md +++ b/packages/opencode/specs/effect/migration.md @@ -1,291 +1,62 @@ -# Effect patterns +# Effect Migration Patterns -Practical reference for new and migrated Effect code in `packages/opencode`. +This is the compact reference for moving code toward the current Effect +shape. The high-level roadmap is [`todo.md`](./todo.md); examples and +rules are in [`guide.md`](./guide.md). -## Choose scope +## Default Shape -Use `InstanceState` (from `src/effect/instance-state.ts`) for services that need per-directory state, per-instance cleanup, or project-bound background work. InstanceState uses a `ScopedCache` keyed by directory, so each open project gets its own copy of the state that is automatically cleaned up on disposal. +- Service methods return `Effect`. +- Service methods are named with `Effect.fn("Domain.method")`. +- Expected failures are typed errors on the error channel. +- Dependencies are yielded once at layer construction and closed over by + methods. +- `defaultLayer` wires production dependencies; tests can use open layers + when replacing dependencies. -Use `makeRuntime` (from `src/effect/run-service.ts`) to create a per-service `ManagedRuntime` that lazily initializes and shares layers via a global `memoMap`. Returns `{ runPromise, runFork, runCallback }`. +## Instance State -- Global services (no per-directory state): Account, Auth, AppFileSystem, Installation, Truncate, Worktree -- Instance-scoped (per-directory state via InstanceState): Agent, Bus, Command, Config, File, FileWatcher, Format, LSP, MCP, Permission, Plugin, ProviderAuth, Pty, Question, SessionStatus, Skill, Snapshot, ToolRegistry, Vcs +Use `InstanceState` for per-directory state, subscriptions, scoped +background work, and per-instance cleanup. -Rule of thumb: if two open directories should not share one copy of the service, it needs `InstanceState`. +Do not add ad hoc `started` flags on top of `InstanceState`; the scoped +cache handles run-once and concurrent deduplication. -## Instance context transition +## Runtime Boundaries -See `instance-context.md` for the phased plan to remove the legacy ALS / promise-backed `Instance` helper and move request / CLI / tool boundaries onto Effect-provided instance scope. +Prefer `AppRuntime` for crossing from non-Effect code into the shared app +layer. -## Service shape +`makeRuntime(...)` exists for intentional service-local boundaries and +legacy facades. Do not add new service-local runtimes unless the service is +genuinely outside `AppLayer`. -Every service follows the same pattern: one module, flat top-level exports, traced Effect methods, and a self-reexport at the bottom when the file is the public module. +## Platform Edges -```ts -export interface Interface { - readonly get: (id: FooID) => Effect.Effect -} +- Use `AppFileSystem.Service` instead of raw filesystem APIs in + effectified services. +- Use `AppProcess.Service` instead of raw process wrappers. +- Use `HttpClient.HttpClient` instead of raw `fetch` in Effect code. +- Use `Effect.cached` for shared in-flight work. +- Use `Effect.callback` for callback APIs. -export class Service extends Context.Service()("@opencode/Foo") {} +## Tests During Migration -export const layer = Layer.effect( - Service, - Effect.gen(function* () { - const state = yield* InstanceState.make( - Effect.fn("Foo.state")(() => Effect.succeed({ ... })), - ) +When migrating code, migrate touched tests toward +[`test/EFFECT_TEST_MIGRATION.md`](../../test/EFFECT_TEST_MIGRATION.md): - const get = Effect.fn("Foo.get")(function* (id: FooID) { - const s = yield* InstanceState.get(state) - // ... - }) +- `testEffect(...)` +- `it.effect`, `it.live`, or `it.instance` +- explicit layers for behavior changes +- deterministic waits instead of sleeps +- no mutable env/global flags after layers are built - return Service.of({ get }) - }), -) +## Migration Checklist -export const defaultLayer = layer.pipe(Layer.provide(FooDep.layer)) - -export * as Foo from "." -``` - -Rules: - -- Keep the service surface in one module; prefer flat top-level exports over `export namespace Foo { ... }` -- Use `Effect.fn("Foo.method")` for Effect methods -- Use a self-reexport (`export * as Foo from "."` or `"./foo"`) for the public namespace projection -- Avoid service-local `makeRuntime(...)` facades unless a file is still intentionally in the older migration phase -- No `Layer.fresh` for normal per-directory isolation; use `InstanceState` - -## Schema boundaries - -Use Effect Schema directly at HTTP, tool, and AI SDK boundaries. For provider-facing JSON Schema, use a boundary-specific helper such as `ToolJsonSchema.fromSchema(...)`; do not reintroduce generic Effect Schema → Zod conversion. - -## InstanceState init patterns - -The `InstanceState.make` init callback receives a `Scope`, so you can use `Effect.acquireRelease`, `Effect.addFinalizer`, and `Effect.forkScoped` inside it. Resources acquired this way are automatically cleaned up when the instance is disposed or invalidated by `ScopedCache`. This makes it the right place for: - -- **Subscriptions**: Yield `Bus.Service` at the layer level, then use `Stream` + `forkScoped` inside the init closure. The fiber is automatically interrupted when the instance scope closes: - -```ts -const bus = yield * Bus.Service - -const cache = - yield * - InstanceState.make( - Effect.fn("Foo.state")(function* (ctx) { - // ... load state ... - - yield* bus.subscribeAll().pipe( - Stream.runForEach((event) => - Effect.sync(() => { - /* handle */ - }), - ), - Effect.forkScoped, - ) - - return { - /* state */ - } - }), - ) -``` - -- **Resource cleanup**: Use `Effect.acquireRelease` or `Effect.addFinalizer` for resources that need teardown (native watchers, process handles, etc.): - -```ts -yield * - Effect.acquireRelease( - Effect.sync(() => nativeAddon.watch(dir)), - (watcher) => Effect.sync(() => watcher.close()), - ) -``` - -- **Background fibers**: Use `Effect.forkScoped` — the fiber is interrupted on disposal. -- **Side effects at init**: Config notification, event wiring, etc. all belong in the init closure. Callers just do `InstanceState.get(cache)` to trigger everything, and `ScopedCache` deduplicates automatically. - -The key insight: don't split init into a separate method with a `started` flag. Put everything in the `InstanceState.make` closure and let `ScopedCache` handle the run-once semantics. - -## Effect.cached for deduplication - -Use `Effect.cached` when multiple concurrent callers should share a single in-flight computation. It memoizes the result and deduplicates concurrent fibers — second caller joins the first caller's fiber instead of starting a new one. - -```ts -// Inside the layer — yield* to initialize the memo -let cached = yield * Effect.cached(loadExpensive()) - -const get = Effect.fn("Foo.get")(function* () { - return yield* cached // concurrent callers share the same fiber -}) - -// To invalidate: swap in a fresh memo -const invalidate = Effect.fn("Foo.invalidate")(function* () { - cached = yield* Effect.cached(loadExpensive()) -}) -``` - -Prefer `Effect.cached` over these patterns: - -- Storing a `Fiber.Fiber | undefined` with manual check-and-fork (e.g. `file/index.ts` `ensure`) -- Storing a `Promise` task for deduplication (e.g. `skill/index.ts` `ensure`) -- `let cached: X | undefined` with check-and-load (races when two callers see `undefined` before either resolves) - -`Effect.cached` handles the run-once + concurrent-join semantics automatically. For invalidatable caches, reassign with `yield* Effect.cached(...)` — the old memo is discarded. - -## Scheduled Tasks - -For loops or periodic work, use `Effect.repeat` or `Effect.schedule` with `Effect.forkScoped` in the layer definition. - -## Preferred Effect services - -In effectified services, prefer yielding existing Effect services over dropping down to ad hoc platform APIs. - -Prefer these first: - -- `FileSystem.FileSystem` instead of raw `fs/promises` for effectful file I/O -- `ChildProcessSpawner.ChildProcessSpawner` with `ChildProcess.make(...)` instead of custom process wrappers -- `HttpClient.HttpClient` instead of raw `fetch` -- `Path.Path` instead of mixing path helpers into service code when you already need a path service -- `Config` for effect-native configuration reads -- `Clock` / `DateTime` for time reads inside effects - -## Child processes - -For child process work in services, yield `ChildProcessSpawner.ChildProcessSpawner` in the layer and use `ChildProcess.make(...)`. - -Keep shelling-out code inside the service, not in callers. - -## Shared leaf models - -Shared schema or model files can stay outside the service namespace when lower layers also depend on them. - -That is fine for leaf files like `schema.ts`. Keep the service surface in the owning namespace. - -## Migration checklist - -Service-shape migrated (single namespace, traced methods, `InstanceState` where needed). - -This checklist is only about the service shape migration. Many of these services still keep `makeRuntime(...)` plus async facade exports; that facade-removal phase is tracked separately in `facades.md`. - -- [x] `Account` — `account/index.ts` -- [x] `Agent` — `agent/agent.ts` -- [x] `AppFileSystem` — `filesystem/index.ts` -- [x] `Auth` — `auth/index.ts` (uses `zod()` helper for Schema→Zod interop) -- [x] `Bus` — `bus/index.ts` -- [x] `Command` — `command/index.ts` -- [x] `Config` — `config/config.ts` -- [x] `Discovery` — `skill/discovery.ts` (dependency-only layer, no standalone runtime) -- [x] `File` — `file/index.ts` -- [x] `FileWatcher` — `file/watcher.ts` -- [x] `Format` — `format/index.ts` -- [x] `Installation` — `installation/index.ts` -- [x] `LSP` — `lsp/index.ts` -- [x] `MCP` — `mcp/index.ts` -- [x] `McpAuth` — `mcp/auth.ts` -- [x] `Permission` — `permission/index.ts` -- [x] `Plugin` — `plugin/index.ts` -- [x] `Project` — `project/project.ts` -- [x] `ProviderAuth` — `provider/auth.ts` -- [x] `Pty` — `pty/index.ts` -- [x] `Question` — `question/index.ts` -- [x] `SessionStatus` — `session/status.ts` -- [x] `Skill` — `skill/index.ts` -- [x] `Snapshot` — `snapshot/index.ts` -- [x] `ToolRegistry` — `tool/registry.ts` -- [x] `Truncate` — `tool/truncate.ts` -- [x] `Vcs` — `project/vcs.ts` -- [x] `Worktree` — `worktree/index.ts` - -- [x] `Session` — `session/index.ts` -- [x] `SessionProcessor` — `session/processor.ts` -- [x] `SessionPrompt` — `session/prompt.ts` -- [x] `SessionCompaction` — `session/compaction.ts` -- [x] `SessionSummary` — `session/summary.ts` -- [x] `SessionRevert` — `session/revert.ts` -- [x] `Instruction` — `session/instruction.ts` -- [x] `SystemPrompt` — `session/system.ts` -- [x] `Provider` — `provider/provider.ts` -- [x] `Storage` — `storage/storage.ts` -- [x] `ShareNext` — `share/share-next.ts` -- [x] `SessionTodo` — `session/todo.ts` - -Still open at the service-shape level: - -- [ ] `SyncEvent` — `sync/index.ts` (deferred pending sync with James) -- [ ] `Workspace` — `control-plane/workspace.ts` (deferred pending sync with James) - -## Tool migration - -Tool-specific migration guidance and checklist live in `tools.md`. - -## Effect service adoption in already-migrated code - -Some already-effectified areas still use raw `Filesystem.*` or `Process.spawn` in their implementation or helper modules. These are low-hanging fruit — the layers already exist, they just need the dependency swap. - -### `Filesystem.*` → `AppFileSystem.Service` (yield in layer) - -- [x] `config/config.ts` — `installDependencies()` now uses `AppFileSystem` -- [x] `provider/provider.ts` — recent model state now reads via `AppFileSystem.Service` - -### `Process.spawn` → `ChildProcessSpawner` (yield in layer) - -- [x] `format/formatter.ts` — direct `Process.spawn()` checks removed (`air`, `uv`) -- [ ] `lsp/server.ts` — multiple `Process.spawn()` installs/download helpers - -## Filesystem consolidation - -`util/filesystem.ts` is still used widely across `src/`, and raw `fs` / `fs/promises` imports still exist in multiple tooling and infrastructure files. As services and tools are effectified, they should switch from `Filesystem.*` to yielding `AppFileSystem.Service` where possible — this should happen naturally during each migration, not as a separate sweep. - -Tool-specific filesystem cleanup notes live in `tools.md`. - -## Primitives & utilities - -- [ ] `util/lock.ts` — reader-writer lock → Effect Semaphore/Permit -- [ ] `util/flock.ts` — file-based distributed lock with heartbeat → Effect.repeat + addFinalizer -- [ ] `util/process.ts` — child process spawn wrapper → return Effect instead of Promise -- [ ] `util/lazy.ts` — replace uses in Effect code with Effect.cached; keep for sync-only code - -## Destroying the facades - -This phase is no longer broadly open. There are 5 `makeRuntime(...)` call sites under `src/`, and only a small subset are still ordinary facade-removal targets. The live checklist now lives in `facades.md`. - -These facades exist because cyclic imports used to force each service to build its own independent runtime. Now that the layer DAG is acyclic and `AppRuntime` (`src/effect/app-runtime.ts`) composes everything into one `ManagedRuntime`, we're removing them. - -### Process - -For each service, the migration is roughly: - -1. **Find callers.** `grep -n "Namespace\.(methodA|methodB|...)"` across `src/` and `test/`. Skip the service file itself. -2. **Migrate production callers.** For each effectful caller that does `Effect.tryPromise(() => Namespace.method(...))`: - - Add the service to the caller's layer R type (`Layer.Layer`) - - Yield it at the top of the layer: `const ns = yield* Namespace.Service` - - Replace `Effect.tryPromise(() => Namespace.method(...))` with `yield* ns.method(...)` (or `ns.method(...).pipe(Effect.orElseSucceed(...))` for the common fallback case) - - Add `Layer.provide(Namespace.defaultLayer)` to the caller's own `defaultLayer` chain -3. **Fix tests that used the caller's raw `.layer`.** Any test that composes `Caller.layer` (not `defaultLayer`) needs to also provide the newly-required service tag. The fastest fix is usually switching to `Caller.defaultLayer` since it now pulls in the new dependency. -4. **Migrate test callers of the facade.** Tests calling `Namespace.method(...)` directly get converted to full effectful style using `testEffect(Namespace.defaultLayer)` + `it.live` / `it.effect` + `yield* svc.method(...)`. Don't wrap the test body in `Effect.promise(async () => {...})` — do the whole thing in `Effect.gen` and use `AppFileSystem.Service` / `tmpdirScoped` / `Effect.addFinalizer` for what used to be raw `fs` / `Bun.write` / `try/finally`. -5. **Delete the facades.** Once `grep` shows zero callers, remove the `export async function` block AND the `makeRuntime(...)` line from the service namespace. Also remove the now-unused `import { makeRuntime }`. - -### Pitfalls - -- **Layer caching inside tests.** `testEffect(layer)` constructs the Storage (or whatever) service once and memoizes it. If a test then tries `inner.pipe(Effect.provide(customStorage))` to swap in a differently-configured Storage, the outer cached one wins and the inner provision is a no-op. Fix: wrap the overriding layer in `Layer.fresh(...)`, which forces a new instance to be built instead of hitting the memoMap cache. This lets a single `testEffect(...)` serve both simple and per-test-customized cases. -- **`Effect.tryPromise` → `yield*` drops the Promise layer.** The old code was `Effect.tryPromise(() => Storage.read(...))` — a `tryPromise` wrapper because the facade returned a Promise. The new code is `yield* storage.read(...)` directly — the service method already returns an Effect, so no wrapper is needed. Don't reach for `Effect.promise` or `Effect.tryPromise` during migration; if you're using them on a service method call, you're doing it wrong. -- **Raw `.layer` test callers break silently in the type checker.** When you add a new R requirement to a service's `.layer`, any test that composes it raw (not `defaultLayer`) becomes under-specified. `tsgo` will flag this — the error looks like `Type 'Storage.Service' is not assignable to type '... | Service | TestConsole'`. Usually the fix is to switch that composition to `defaultLayer`, or add `Layer.provide(NewDep.defaultLayer)` to the custom composition. -- **Tests that do async setup with `fs`, `Bun.write`, `tmpdir`.** Convert these to `AppFileSystem.Service` calls inside `Effect.gen`, and use `tmpdirScoped()` instead of `tmpdir()` so cleanup happens via the scope finalizer. For file operations on the actual filesystem (not via a service), a small helper like `const writeJson = Effect.fnUntraced(function* (file, value) { const fs = yield* AppFileSystem.Service; yield* fs.makeDirectory(path.dirname(file), { recursive: true }); yield* fs.writeFileString(file, JSON.stringify(value, null, 2)) })` keeps the migration tests clean. - -### Migration log - -- `SessionStatus` — migrated 2026-04-11. Replaced the last route and retry-policy callers with `AppRuntime.runPromise(SessionStatus.Service.use(...))` and removed the `makeRuntime(...)` facade. -- `ShareNext` — migrated 2026-04-11. Swapped remaining async callers to `AppRuntime.runPromise(ShareNext.Service.use(...))`, removed the `makeRuntime(...)` facade, and kept instance bootstrap on the shared app runtime. -- `SessionTodo` — migrated 2026-04-10. Already matched the target service shape in `session/todo.ts`: single namespace, traced Effect methods, and no `makeRuntime(...)` facade remained; checklist updated to reflect the completed migration. -- `Storage` — migrated 2026-04-10. One production caller (`Session.diff`) and all storage.test.ts tests converted to effectful style. Facades and `makeRuntime` removed. -- `SessionRunState` — migrated 2026-04-11. Single caller in `server/routes/instance/session.ts` converted; facade removed. -- `Account` — migrated 2026-04-11. Callers in `server/routes/instance/experimental.ts` and `cli/cmd/account.ts` converted; facade removed. -- `Instruction` — migrated 2026-04-11. Test-only callers converted; facade removed. -- `FileWatcher` — migrated 2026-04-11. Callers in `project/bootstrap.ts` and test converted; facade removed. -- `Question` — migrated 2026-04-11. Callers in `server/routes/instance/question.ts` and test converted; facade removed. -- `Truncate` — migrated 2026-04-11. Caller in `tool/tool.ts` and test converted; facade removed. - -## Route handler effectification - -Route-handler migration guidance and checklist live in `routes.md`. +- [ ] The code has a single Effect body instead of Promise wrappers around + service calls. +- [ ] Expected failures are typed errors, not thrown exceptions or defects. +- [ ] Layer requirements are explicit. +- [ ] Tests use Effect-aware fixtures and focused layers. +- [ ] Public behavior and wire shapes are preserved unless intentionally + changed. diff --git a/packages/opencode/specs/effect/routes.md b/packages/opencode/specs/effect/routes.md index 8066bda346..7dcd80ce96 100644 --- a/packages/opencode/specs/effect/routes.md +++ b/packages/opencode/specs/effect/routes.md @@ -1,57 +1,61 @@ -# Route handler effectification +# HTTP Route Patterns -Practical reference for converting server route handlers in `packages/opencode` to a single `AppRuntime.runPromise(Effect.gen(...))` body. +Current guidance for `packages/opencode/src/server/routes/instance/httpapi`. -## Goal +## Handler Shape -Route handlers should wrap their entire body in a single `AppRuntime.runPromise(Effect.gen(...))` call, yielding services from context rather than calling facades one-by-one. - -This eliminates multiple `runPromise` round-trips and lets handlers compose naturally. +Use `HttpApiBuilder.group(...)` for normal JSON and streaming HTTP API +endpoints. Yield stable services once while building the handler layer, +then close over those services in endpoint implementations. ```ts -// Before - one facade call per service -;async (c) => { - await SessionRunState.assertNotBusy(id) - await Session.removeMessage({ sessionID: id, messageID }) - return c.json(true) -} +export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", (handlers) => + Effect.gen(function* () { + const session = yield* Session.Service -// After - one Effect.gen, yield services from context -;async (c) => { - await AppRuntime.runPromise( - Effect.gen(function* () { - const state = yield* SessionRunState.Service - const session = yield* Session.Service - yield* state.assertNotBusy(id) - yield* session.removeMessage({ sessionID: id, messageID }) - }), - ) - return c.json(true) -} + return handlers.handle("list", () => session.list()) + }), +) ``` -## Rules +Use raw `HttpRouter` only for routes that do not fit the request/response +HttpApi model, such as WebSocket upgrades or catch-all fallback routes. -- Wrap the whole handler body in one `AppRuntime.runPromise(Effect.gen(...))` call when the handler is service-heavy. -- Yield services from context instead of calling async facades repeatedly. -- When independent service calls can run in parallel, use `Effect.all(..., { concurrency: "unbounded" })`. -- Prefer one composed Effect body over multiple separate `runPromise(...)` calls in the same handler. +Do not rebuild stable layers inside request handlers. Provide stable +services at the route/layer boundary and use request-level provisioning +only for request-derived context. -## Current route files +## Error Boundaries -Current instance route files live under `src/server/routes/instance/httpapi`. -Most handlers already yield stable services at route-layer construction and then -close over those services in endpoint implementations. +Expected service errors should be mapped at the handler boundary to +endpoint-declared public HTTP errors. Keep one-off mappings inline. Extract +small helpers when the same mapping repeats. -Files still worth tracking here: +Generic middleware should not become a domain-error mapper. It should +handle cross-cutting concerns and final unknown-defect fallback. -- [ ] `handlers/session.ts` — still the heaviest mixed file; some paths keep compatibility translations and direct event publication -- [ ] `handlers/experimental.ts` — mixed state; some handlers still rely on request-local context reads -- [ ] `middleware/*` — still contains compatibility policy for auth, compression, errors, instance context, and workspace routing -- [ ] `public.ts` — still owns SDK/OpenAPI compatibility translation shims -- [ ] raw route modules — WebSocket and catch-all routes should stay explicit and avoid rebuilding stable layers per request +Public JSON errors should be explicit schema contracts declared on each +endpoint or group. Built-in `HttpApiError.*` is fine only when its generated +body is intentionally the public wire shape. -## Notes +Preserve existing `{ name, data }` error bodies until a deliberate breaking +API change. -- Route conversion is now less about backend migration and more about removing the remaining direct `Instance.*` reads, request-local service plumbing, and OpenAPI compatibility shims. -- Prefer route-layer service capture over rebuilding or providing stable layers inside individual handlers. +## OpenAPI Compatibility + +`public.ts` still owns SDK/OpenAPI compatibility transforms. Shrink those +transforms by tightening source schemas one workaround at a time. + +When an OpenAPI-visible source schema changes: + +- verify the generated SDK diff is intentional +- preserve legacy compatibility unless the PR explicitly changes it +- prefer source-schema fixes over new post-processing rules + +## Checklist For Route PRs + +- [ ] Stable services are yielded at handler-layer construction. +- [ ] Expected domain errors are translated at the route boundary. +- [ ] Endpoint/group error schemas describe the public body and status. +- [ ] Middleware does not gain new domain-specific name checks. +- [ ] Raw routes are used only when HttpApi is the wrong abstraction. diff --git a/packages/opencode/specs/effect/schema.md b/packages/opencode/specs/effect/schema.md index 1fc6a44783..12ac267048 100644 --- a/packages/opencode/specs/effect/schema.md +++ b/packages/opencode/specs/effect/schema.md @@ -1,22 +1,15 @@ -# Schema migration +# Schema Migration -Practical reference for migrating data types in `packages/opencode` from -Zod-first definitions to Effect Schema. +Use Effect Schema as the source of truth for domain models, DTOs, IDs, +inputs, outputs, and typed errors. -## Goal +This is guidance, not an inventory. Do not use this file to track which +schema modules are complete; verify current state with `git grep` before +starting a migration. -Use Effect Schema as the source of truth for domain models, IDs, inputs, -outputs, and typed errors. Prefer native Effect Schema, Standard Schema, and -native JSON Schema generation at HTTP, tool, and AI SDK boundaries. +## Preferred Shapes -The long-term driver is `specs/effect/http-api.md`: Schema-first DTOs should -flow through `HttpApi` / `HttpRouter` without a Zod translation layer. - -## Preferred shapes - -### Data objects - -Use `Schema.Class` for structured data. +Use `Schema.Class` for exported data objects with a clear domain identity: ```ts export class Info extends Schema.Class("Foo.Info")({ @@ -26,18 +19,16 @@ export class Info extends Schema.Class("Foo.Info")({ }) {} ``` -If a schema needs local static helpers, use the two-step `withStatics` pattern: +Use `Schema.Struct` for local shapes and simple nested objects: ```ts -export const Info = Schema.Struct({ +const Payload = Schema.Struct({ id: FooID, - name: Schema.String, -}).pipe(withStatics((s) => ({ decode: Schema.decodeUnknownOption(s) }))) + value: Schema.String, +}) ``` -### Errors - -Use `Schema.TaggedErrorClass` for domain errors. +Use `Schema.TaggedErrorClass` for expected domain errors: ```ts export class NotFoundError extends Schema.TaggedErrorClass()("FooNotFoundError", { @@ -45,309 +36,53 @@ export class NotFoundError extends Schema.TaggedErrorClass()("Foo }) {} ``` -### IDs and branded leaf types +Use branded schema-backed IDs for single-value domain identifiers. -Keep branded/schema-backed IDs as Effect schemas. +## Boundary Rule -### Refinements +Effect Schema should own the type. Boundaries should consume Effect Schema +directly or use narrow boundary-specific helpers. Avoid reintroducing a +generic Effect Schema -> Zod bridge. -Reuse named refinements instead of re-spelling numeric or string constraints in -every schema. Boundary JSON Schema helpers should normalize native Effect JSON -Schema output only where a provider requires it. +Current intentional boundaries: + +- Public plugin tools still expose Zod through `tool.schema = z`. +- Tool parameters use tool-specific JSON Schema helpers. +- Public config and TUI schema generation goes through the schema script. +- AI SDK object generation uses Standard Schema / JSON Schema helpers. + +When Zod must stay temporarily, leave a short note explaining the boundary +or compatibility reason. + +## Refinements + +Reuse named refinements instead of re-spelling constraints: ```ts const PositiveInt = Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThan(0)) const NonNegativeInt = Schema.Number.check(Schema.isInt()).check(Schema.isGreaterThanOrEqualTo(0)) -const HexColor = Schema.String.check(Schema.isPattern(/^#[0-9a-fA-F]{6}$/)) ``` -## Compatibility rule +Prefer domain-named leaf schemas when the name improves callers or error +messages. Avoid adding brands purely for novelty. -During migration, route validators, tool parameters, and AI SDK schemas should -consume Effect schemas directly or use a narrow boundary helper. Avoid -maintaining a second hand-written Zod schema. +## Migration Order -The default should be: +For a domain that still has mixed schemas: -- Effect Schema owns the type -- new domain models should not start Zod-first unless there is a concrete - boundary-specific need +1. Shared leaf models and branded IDs. +2. Exported `Info`, `Input`, `Output`, and event payload types. +3. Expected domain errors. +4. Service-local internal models. +5. HTTP/tool/AI boundary validators. -## When Zod can stay +Keep public wire shapes stable unless the PR is explicitly a breaking API +change. -It is fine to keep a Zod-native schema temporarily when: +## Checklist For A PR -- the type is only used at an HTTP or tool boundary and is not reused elsewhere -- the validator is part of an existing public API that explicitly accepts Zod -- the migration would force unrelated churn across a large call graph - -When this happens, prefer leaving a short note or TODO rather than silently -creating a parallel schema source of truth. - -## Boundary helpers - -Use narrow helpers at concrete boundaries instead of a generic Schema → Zod bridge. - -- Tool parameters: `ToolJsonSchema.fromSchema(...)` and `ToolJsonSchema.fromTool(...)` -- Public config/TUI schemas: `packages/opencode/script/schema.ts` -- AI SDK object generation: `Schema.toStandardSchemaV1(...)` plus `Schema.toStandardJSONSchemaV1(...)` - -Plugin tools are the main remaining intentional Zod boundary because the public -plugin API exposes `tool.schema = z` and `args: z.ZodRawShape`. - -### Local `DeepMutable` in `config/config.ts` - -`Schema.Struct` produces `readonly` types. Some consumer code (notably the -`Config` service) mutates `Info` objects directly, so a readonly-stripping -utility is needed when casting the derived zod schema's output type. - -`Types.DeepMutable` from effect-smol would be a drop-in, but it widens -`unknown` to `{}` in the fallback branch — a bug that affects any schema -using `Schema.Record(String, Schema.Unknown)`. - -Tracked upstream as `effect:core/x228my`: "Types.DeepMutable widens unknown -to `{}`." Once that lands, the local `DeepMutable` copy can be deleted and -`Types.DeepMutable` used directly. - -## Ordering - -Migrate in this order: - -1. Shared leaf models and `schema.ts` files -2. Exported `Info`, `Input`, `Output`, and DTO types -3. Tagged domain errors -4. Service-local internal models -5. Route and tool boundary validators that can switch to native Effect Schema helpers - -This keeps shared types canonical first and makes boundary updates mostly -mechanical. - -## Progress tracker - -### `src/config/` ✅ complete - -All of `packages/opencode/src/config/` has been migrated. The `export const -` values are all Effect Schema at source. - -A file is considered "done" when: - -- its exported schema values (`Info`, `Input`, `Event`, `Definition`, etc.) - are authored as Effect Schema -- any remaining Zod is an explicit boundary compatibility choice, not a - hand-written parallel source of truth - -Files that meet this bar but still carry a compatibility boundary are checked -off with an inline note describing the boundary and what unblocks its removal. - -- [x] skills, formatter, console-state, mcp, lsp, permission (leaves), model-id, command, plugin, provider -- [x] server, layout -- [x] keybinds -- [x] permission#Info -- [x] agent -- [x] config.ts root - -### `src/*/schema.ts` leaf modules - -These are the highest-priority next targets. Each is a small, self-contained -schema module with a clear domain. - -- [x] `src/account/schema.ts` -- [x] `src/control-plane/schema.ts` -- [x] `src/permission/schema.ts` -- [x] `src/project/schema.ts` -- [x] `src/provider/schema.ts` -- [x] `src/pty/schema.ts` -- [x] `src/question/schema.ts` -- [x] `src/session/schema.ts` -- [x] `src/storage/schema.ts` -- [x] `src/sync/schema.ts` -- [x] `src/tool/schema.ts` -- [x] `src/util/schema.ts` - -### Session domain - -Major cluster. Message + event types flow through the SSE API and every SDK -output, so byte-identical SDK surface is critical. - -Suggested order for this cluster, starting from the leaves that `session.ts` -and the SSE/event surface depend on: - -1. `src/session/schema.ts` ✅ already migrated -2. `src/provider/schema.ts` if `message-v2.ts` still relies on zod-first IDs -3. `src/lsp/*` schema leaves needed by `LSP.Range` -4. `src/snapshot/*` leaves used by `Snapshot.FileDiff` -5. `src/session/message-v2.ts` -6. `src/session/message.ts` -7. `src/session/prompt.ts` -8. `src/session/revert.ts` -9. `src/session/summary.ts` -10. `src/session/status.ts` -11. `src/session/todo.ts` -12. `src/session/session.ts` -13. `src/session/compaction.ts` - -Dependency sketch: - -```text -session.ts -|- project/schema.ts -|- control-plane/schema.ts -|- permission/schema.ts -|- snapshot/* -|- message-v2.ts -| |- provider/schema.ts -| |- lsp/* -| |- snapshot/* -| |- sync/index.ts -| `- bus/bus-event.ts -|- sync/index.ts -|- bus/bus-event.ts -`- util/update-schema.ts -``` - -Working rule for this cluster: - -- migrate reusable leaf schemas and nested payload objects first -- migrate aggregate DTOs like `Session.Info` after their nested pieces exist as - named Schema values -- leave zod-only event/update helpers in place temporarily when converting - them would force unrelated churn across sync/bus boundaries - -`message-v2.ts` first-pass outline: - -1. Schema-backed imports already available - - `SessionID`, `MessageID`, `PartID` - - `ProviderID`, `ModelID` -2. Local leaf objects to extract and migrate first - - output format payloads - - common part bases like `PartBase` - - timestamp/range helper objects like `time.start/end` - - file/source helper objects - - token/cost/model helper objects -3. Part variants built from those leaves - - `SnapshotPart`, `PatchPart`, `TextPart`, `ReasoningPart` - - `FilePart`, `AgentPart`, `CompactionPart`, `SubtaskPart` - - retry/step/tool related parts -4. Higher-level unions and DTOs - - `FilePartSource` - - part unions - - message unions and assistant/user payloads -5. Errors and event payloads last - - `NamedError.create(...)` shapes can stay temporarily if converting them to - `Schema.TaggedErrorClass` would force unrelated churn - - `SyncEvent.define(...)` and `BusEvent.define(...)` payloads can use - derived `.zod` at remaining zod-based HTTP/OpenAPI boundaries - -Possible later tightening after the Schema-first migration is stable: - -- promote repeated opaque strings and timestamp numbers into branded/newtype - leaf schemas where that adds domain value without changing the wire format - -- [x] `src/session/compaction.ts` -- [x] `src/session/message-v2.ts` -- [x] `src/session/message.ts` -- [x] `src/session/prompt.ts` -- [x] `src/session/revert.ts` -- [x] `src/session/session.ts` -- [x] `src/session/status.ts` -- [x] `src/session/summary.ts` -- [x] `src/session/todo.ts` - -### Provider domain - -- [x] `src/provider/auth.ts` -- [x] `src/provider/models.ts` -- [x] `src/provider/provider.ts` - -### Tool schemas - -Each tool declares its parameters via a zod schema. Tools are consumed by -both the in-process runtime and the AI SDK's tool-calling layer, so the -emitted JSON Schema must stay byte-identical. - -- [x] `src/tool/apply_patch.ts` -- [x] `src/tool/bash.ts` -- [x] `src/tool/edit.ts` -- [x] `src/tool/glob.ts` -- [x] `src/tool/grep.ts` -- [x] `src/tool/invalid.ts` -- [x] `src/tool/lsp.ts` -- [x] `src/tool/plan.ts` -- [x] `src/tool/question.ts` -- [x] `src/tool/read.ts` -- [x] `src/tool/registry.ts` -- [x] `src/tool/skill.ts` -- [x] `src/tool/task.ts` -- [x] `src/tool/todo.ts` -- [x] `src/tool/tool.ts` -- [x] `src/tool/webfetch.ts` -- [x] `src/tool/websearch.ts` -- [x] `src/tool/write.ts` - -### HTTP route boundaries - -The server route tree now lives under `src/server/routes/instance/httpapi` and -uses Effect HttpApi contracts for request and response schemas. Remaining schema -work is no longer a Hono route migration; it is compatibility cleanup around -derived `.zod` statics, OpenAPI translation shims, and route groups that still -need explicit SDK-visible error contracts. - -Good follow-up targets: - -- shrink `public.ts` legacy OpenAPI translation shims one SDK-compatible slice at a time -- replace production `.zod.safeParse(...)` call sites with Effect Schema decoders -- remove derived `.zod` statics after their production consumers are gone -- declare route-group errors directly instead of relying on compatibility middleware - -### Everything else - -Small / shared / control-plane / CLI. Mostly independent; can be done -piecewise. - -- [ ] `src/acp/agent.ts` -- [ ] `src/agent/agent.ts` -- [x] `src/bus/bus-event.ts` -- [ ] `src/bus/index.ts` -- [ ] `src/cli/cmd/tui/config/tui-migrate.ts` -- [ ] `src/cli/cmd/tui/config/tui-schema.ts` -- [ ] `src/cli/cmd/tui/config/tui.ts` -- [ ] `src/cli/cmd/tui/event.ts` -- [ ] `src/cli/ui.ts` -- [ ] `src/command/index.ts` -- [x] `src/control-plane/adapters/worktree.ts` -- [x] `src/control-plane/types.ts` -- [x] `src/control-plane/workspace.ts` -- [ ] `src/file/index.ts` -- [ ] `src/file/ripgrep.ts` -- [ ] `src/file/watcher.ts` -- [ ] `src/format/index.ts` -- [ ] `src/id/id.ts` -- [ ] `src/ide/index.ts` -- [ ] `src/installation/index.ts` -- [ ] `src/lsp/client.ts` -- [ ] `src/lsp/lsp.ts` -- [ ] `src/mcp/auth.ts` -- [ ] `src/patch/index.ts` -- [ ] `src/plugin/github-copilot/models.ts` -- [ ] `src/project/project.ts` -- [ ] `src/project/vcs.ts` -- [ ] `src/pty/index.ts` -- [ ] `src/skill/index.ts` -- [ ] `src/snapshot/index.ts` -- [ ] `src/storage/db.ts` -- [ ] `src/storage/storage.ts` -- [x] `src/sync/index.ts` — public API (`SyncEvent.define`) is Schema-first; `payloads()` still derives zod for the remaining HTTP/OpenAPI boundary -- [ ] `src/util/fn.ts` -- [ ] `src/util/log.ts` -- [ ] `src/util/update-schema.ts` -- [ ] `src/worktree/index.ts` - -## Notes - -- Prefer one canonical schema definition. Avoid maintaining parallel Zod and - Effect definitions for the same domain type. -- Keep the migration incremental. Converting the domain model first is more - valuable than converting every boundary in the same change. -- Every migrated file should leave the generated SDK output (`packages/sdk/ -openapi.json` and `packages/sdk/js/src/v2/gen/types.gen.ts`) byte-identical - unless the change is deliberately user-visible. +- [ ] There is one schema source of truth for each migrated type. +- [ ] Remaining Zod is an intentional boundary choice. +- [ ] Public JSON/OpenAPI output is unchanged or intentionally updated. +- [ ] Derived helpers are narrow and boundary-specific. +- [ ] Tests assert behavior, not duplicated schema implementation details. diff --git a/packages/opencode/specs/effect/todo.md b/packages/opencode/specs/effect/todo.md new file mode 100644 index 0000000000..9261811c38 --- /dev/null +++ b/packages/opencode/specs/effect/todo.md @@ -0,0 +1,237 @@ +# Effect TODO + +Short roadmap for Effect cleanup in `packages/opencode`. + +Current patterns and examples live in [`guide.md`](./guide.md). Test +migration rules live in +[`test/EFFECT_TEST_MIGRATION.md`](../../test/EFFECT_TEST_MIGRATION.md). +Older deep-dive notes in this directory may still be useful, but treat +this roadmap and the guide as the current entry points. + +This is a planning map, not a verified inventory. Before starting a task, +re-run a targeted `git grep` from current `dev` and update this file if +the inventory changed. + +## Priorities + +```text +P0 ERR + RENDER + HTTP + Make expected failures typed, render them well, and stop relying on + generic HTTP error guesswork. + +P1 TEST + Convert touched tests to the ideal Effect test patterns from the guide. + +P2 RF + Move mutable runtime flags into typed runtime/config services. + +P3 GLOBAL + Make global paths explicit and remove import-time side effects. + +P4 INST + BRIDGE + Remove ambient Instance coupling while keeping Promise/callback interop. + +P5 PROC + FS + Replace raw process/filesystem edges with typed Effect services. + +P6 OA + Shrink OpenAPI compatibility shims as source schemas improve. +``` + +## Work Paths + +- `ERR` Typed errors — replace legacy `NamedError.create(...)` and + `Effect.die(...)` for expected service failures with + `Schema.TaggedErrorClass` errors on the Effect error channel. + Shrinks: [`NamedError`](../../../core/src/util/error.ts) usage. +- `RENDER` User-visible error rendering — preserve structured typed-error + details at CLI, HTTP, and tool boundaries. + Shrinks: opaque `Error: Name` rendering. +- `HTTP` HTTP route cleanup — make route errors explicit instead of + relying on generic middleware to guess status/body from error names. + Shrinks: [`middleware/error.ts`](../../src/server/routes/instance/httpapi/middleware/error.ts) + and route-level compatibility shims. +- `TEST` Effect test migration — use `testEffect`, `it.live`, and + `it.instance` with explicit layers. + Shrinks: Promise-style tests, sleeps, mutable global test flags. +- `RF` RuntimeFlags / Flag deletion — move mutable + [`Flag`](../../../core/src/flag/flag.ts) reads into typed runtime/config + services. + Shrinks: [`flag.ts`](../../../core/src/flag/flag.ts), + [`test/fixture/flag.ts`](../../test/fixture/flag.ts). +- `GLOBAL` Global paths / import side effects — make global path state + explicit and testable instead of mutable module state. + Shrinks: [`global.ts`](../../../core/src/global.ts) import-time side + effects, mutable `Global.Path` overrides, and its `Flag` dependency. +- `INST` Instance shim — remove ambient `Instance` usage and old ALS + access patterns. + Shrinks: [`src/project/instance.ts`](../../src/project/instance.ts). +- `BRIDGE` Promise/callback interop — keep bridge helpers, but reduce + legacy ALS coupling. + Shrinks: [`src/effect/bridge.ts`](../../src/effect/bridge.ts) + dependency on [`project/instance.ts`](../../src/project/instance.ts). +- `PROC` AppProcess migration — prefer `AppProcess.Service` over raw + process wrappers. + Shrinks: direct spawn callsites and legacy process helpers. +- `FS` AppFileSystem migration — prefer `AppFileSystem.Service` over raw + filesystem APIs. + Shrinks: direct `fs` / `Bun.file` service callsites where inappropriate. +- `RT` Runtime/facade cleanup — remove service-local `makeRuntime` + facades when not intentional. + Shrinks: async facade exports around services and + [`run-service.ts`](../../src/effect/run-service.ts) usage. +- `OA` OpenAPI compatibility — tighten source schemas instead of + post-processing generated OpenAPI. + Shrinks: schema workaround blocks in + [`public.ts`](../../src/server/routes/instance/httpapi/public.ts). + +## P0: Errors, Rendering, And HTTP + +This should be the next big cleanup theme. The codebase is moving toward +typed Effect failures, but the user-facing boundaries still leak old +shapes and sometimes collapse rich errors into opaque strings. + +### Problems + +- Some expected service failures still use `NamedError.create(...)`. +- Some expected service failures still become `Effect.die(...)`, which + makes them defects instead of typed, recoverable failures. +- CLI and HTTP boundaries can render structured errors as generic + `Error: SomeName` output. +- HTTP error middleware still guesses status codes from error names like + `Worktree*` or `ProviderAuthValidationFailed`. +- Route handlers and route groups do not consistently declare the public + error body they intend to expose. +- Repeated route error translations do not yet have a clear home: some + should stay inline, some deserve tiny shared mapper helpers. +- Unknown 500s should log full detail server-side while returning a safe + public body. + +### Target Shape + +- Services define expected failures with `Schema.TaggedErrorClass`. +- Services export an `Error` union and include it in method return types. +- Expected failures stay on the Effect error channel. +- `Effect.die(...)` is reserved for defects: bugs, impossible states, + violated invariants, or final unknown-boundary fallbacks. +- Inside `Effect.gen` / `Effect.fn`, use `yield* new MyError(...)` for + direct expected failures. +- Domain services do not import HTTP status codes, `HttpApiError`, or + route-specific error schemas. +- HTTP route groups make their public error contracts obvious. +- Handlers map service errors to declared HTTP errors at the boundary. +- Shared mapper helpers are only for repeated translations, not a giant + central registry of every domain error. +- Generic HTTP middleware should shrink; it should not accumulate more + name-based domain knowledge. + +### First PR Candidates + +- [ ] `RENDER-1` Fix CLI top-level rendering for typed config errors. +- [ ] `ERR-1` Convert [`storage/storage.ts`](../../src/storage/storage.ts) + not-found errors. +- [ ] `ERR-2` Convert [`worktree/index.ts`](../../src/worktree/index.ts) + errors and remove matching HTTP name checks where possible. +- [ ] `ERR-3` Convert [`provider/auth.ts`](../../src/provider/auth.ts) + validation errors. +- [ ] `HTTP-1` Remove the unknown-500 stack leak from + [`middleware/error.ts`](../../src/server/routes/instance/httpapi/middleware/error.ts). +- [ ] `HTTP-2` Audit one route group for explicit error contracts and + decide which mappings stay inline vs. shared helper. + +## P1: Tests + +When touching tests, migrate them toward the ideal patterns in +[`test/EFFECT_TEST_MIGRATION.md`](../../test/EFFECT_TEST_MIGRATION.md): + +- Use `testEffect(...)` with explicit layers. +- Prefer `it.instance(...)` for service tests that need an instance. +- Prefer `it.live(...)` for real timers, filesystem mtimes, child + processes, git, locks, or other live integration behavior. +- Avoid sleeps; wait on real events or deterministic state transitions. +- Do not mutate `process.env` or mutable globals after layers are built. +- Use explicit layer variants, such as `RuntimeFlags.layer(...)`, for + behavior changes. + +## P2: RuntimeFlags / Flag Deletion + +Recently completed: + +- [x] Plugin/pure-mode flags moved to RuntimeFlags. +- [x] Tool visibility flags moved to RuntimeFlags. +- [x] Built-in websearch provider selection uses the same runtime flags as + tool visibility. +- [x] Removed global default-plugin disabling from test preload. + +Recommended next PRs: + +```text +RF-1 scout consumers ─┐ + ├─ can run in parallel +RF-2 plan-mode prompt ┘ + └─ RF-3 event-system cluster, stacked only if RF-2 still touches prompt.ts + +RF-4 workspaces cluster: later, after mutable Flag tests are cleaned up +``` + +- [ ] `RF-1` Move scout reads in [`agent.ts`](../../src/agent/agent.ts) + and [`reference.ts`](../../src/reference/reference.ts). +- [ ] `RF-2` Move plan-mode prompt read in + [`session/prompt.ts`](../../src/session/prompt.ts). +- [ ] `RF-3` Move event-system reads in session prompt/processor/ + compaction and TUI debug plugin. +- [ ] `RF-4` Move workspaces reads in session/sync/control-plane after + tests stop relying on mutable `Flag` timing. +- [ ] Delete [`test/fixture/flag.ts`](../../test/fixture/flag.ts) once + tests no longer mutate `Flag`. +- [ ] Delete [`flag.ts`](../../../core/src/flag/flag.ts) once no packages + import it. + +## P3: Global Paths + +[`global.ts`](../../../core/src/global.ts) is real connective tissue, not +just cosmetic ugliness. It currently mixes path calculation, import-time +directory creation, `Flock` setup, mutable exported `Path` state, and a +`Flag` dependency. + +Problems to reduce: + +- Importing the module creates directories. +- Tests override `Global.Path` by mutating exported module state. +- Most callers use `Global.Path` directly instead of the Effect service. +- `Global.make()` still reads mutable `Flag.OPENCODE_CONFIG_DIR`. + +Next PR candidates: + +- [ ] Replace mutable `Global.Path` test overrides with explicit test + layers or scoped helpers. +- [ ] Move directory creation and `Flock` setup behind an explicit init + boundary where possible. +- [ ] Remove the `Flag` dependency from global path resolution. + +## P4: Instance And Bridge + +[`project/instance.ts`](../../src/project/instance.ts) is the deletion +target. [`effect/bridge.ts`](../../src/effect/bridge.ts) is not a near-term +deletion target; Promise/callback interop will continue to exist. + +Goal: + +- Keep a sanctioned bridge for Promise/callback boundaries. +- Reduce bridge dependence on legacy `Instance.restore` / `Instance.current`. +- Move callers toward `InstanceRef`, `WorkspaceRef`, `InstanceState`, or + explicit context where practical. +- Delete `project/instance.ts` only after ambient Instance coupling is gone. + +## Lower Priority Tracks + +- `PROC` / `FS` — continue AppProcess and AppFileSystem migrations as + focused PRs when touching relevant files. +- `RT` — remove service-local runtime facades only when they are not an + intentional boundary. +- `OA` — shrink [`public.ts`](../../src/server/routes/instance/httpapi/public.ts) + by tightening source schemas one workaround at a time. +- `fetch` → `HttpClient` — migrate raw fetch callsites when the caller is + already effectful or being effectified. +- `Tools` — remaining tool cleanup is narrow: `webfetch` HTML extraction + and `shell` raw stream/promise edges. diff --git a/packages/opencode/specs/tui-plugins.md b/packages/opencode/specs/tui-plugins.md index c1a9b271c1..e9ece6c0a2 100644 --- a/packages/opencode/specs/tui-plugins.md +++ b/packages/opencode/specs/tui-plugins.md @@ -29,6 +29,16 @@ Example: "plugin": ["@acme/opencode-plugin@1.2.3", ["./plugins/demo.tsx", { "label": "demo" }]], "plugin_enabled": { "acme.demo": false + }, + "attention": { + "enabled": true, + "notifications": true, + "sound": true, + "volume": 0.4, + "sound_pack": "opencode.default", + "sounds": { + "error": "/Users/me/sounds/error.mp3" + } } } ``` @@ -45,6 +55,11 @@ Example: - Internal plugins can declare `enabled: false` to be registered but inactive by default; `plugin_enabled` and runtime KV can still enable them by id. - `plugin_enabled` is merged across config layers. - Runtime enable/disable state is also stored in KV under `plugin_enabled`; that KV state overrides config on startup. +- `attention.enabled` defaults to `false`; when `false`, it disables all `api.attention.notify(...)` delivery. +- `attention.notifications` and `attention.sound` independently control terminal-mediated desktop notifications and built-in sounds. +- `attention.volume` sets the default built-in sound volume from `0` to `1`. +- `attention.sound_pack` selects the initial semantic sound pack. Persisted runtime selection in KV can override it. +- `attention.sounds` overrides individual semantic sound slots such as `error`, `done`, or `subagent_done`. - `leader_timeout` is a top-level TUI setting. - `keybinds` is a flat object keyed by command id; values are key binding values (`false`, `"none"`, a key string/object, a binding object, or an array of key strings/objects/binding objects). - `keybinds.leader` sets the key used by `` shortcuts. @@ -212,6 +227,7 @@ That is what makes local config-scoped plugins able to import `@opencode-ai/plug Top-level API groups exposed to `tui(api, options, meta)`: - `api.app.version` +- `api.attention.notify(input)` - `api.keys.formatSequence(parts)`, `formatBindings(bindings)` - `api.keymap` - `api.route.register(routes)` / `api.route.navigate(name, params?)` / `api.route.current` @@ -246,6 +262,24 @@ Top-level API groups exposed to `tui(api, options, meta)`: - `formatBindings(bindings)` formats binding lists and returns `undefined` when there is nothing to show. - For generic config-to-bindings helpers, import `createBindingLookup` from `@opencode-ai/plugin/tui`. +### Attention + +- `api.attention.notify({ title?, message, notification?, sound? })` requests user attention while keeping terminal focus, notifications, and audio owned by the host. +- `message` is required; `title` defaults to `"opencode"`; `notification` defaults to enabled with `when: "blurred"`; `sound` defaults to enabled with `when: "always"`. +- `when: "always"` requests delivery regardless of terminal focus state. +- `when: "focused"` only requests delivery after the terminal is known focused; `when: "blurred"` only requests delivery after the terminal is known blurred. +- Example: `notification: { when: "blurred" }, sound: { name: "question", when: "always" }` plays sound while focused but only triggers system notifications when blurred. +- Semantic sound names are `"default"`, `"question"`, `"permission"`, `"error"`, `"done"`, and `"subagent_done"`. +- `sound: true` plays the `"default"` sound; `sound: { name: "question" }` plays a named semantic sound. +- `sound: { volume }` overrides volume for that call; `sound: false` disables sound for that call; `notification: false` disables system notification for that call. +- `api.attention.soundboard.registerPack({ id, name?, sounds })` registers a sound pack and returns a disposer. Relative paths resolve from the plugin root and are cleaned up on plugin deactivation. +- `api.attention.soundboard.activate(id, { persist })` selects the active pack. `persist: true` writes the selected pack id to TUI KV state, not `tui.json`. +- `api.attention.soundboard.current()` and `list()` expose the active/registered packs for plugin UX. +- Config `attention.sounds` overrides active-pack sounds by slot. Failed loads fall back to the active pack and then `opencode.default`. +- The host strips ANSI/control characters and collapses newlines before sending text to the terminal notification API. +- Terminal and OS settings decide whether a requested notification is visibly displayed. +- Prefer privacy-safe messages such as `"A question needs your input"`; avoid full commands, paths, prompts, errors, secrets, or file contents unless the plugin intentionally exposes them. + ### Routes - Reserved route names: `home` and `session`. diff --git a/packages/opencode/specs/v2/notifications.md b/packages/opencode/specs/v2/notifications.md new file mode 100644 index 0000000000..96018f9944 --- /dev/null +++ b/packages/opencode/specs/v2/notifications.md @@ -0,0 +1,13 @@ +# TUI Notifications Default + +Problem: + +- v1 defaults `attention.enabled` to `false` +- users can opt in with `attention.enabled = true` +- v2 should make core TUI notifications a default behavior + +## v2 Target + +Flip `attention.enabled` to `true` by default in v2. + +Keep `attention.enabled = false` as the explicit opt-out. diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 867b830cf2..aa123d5991 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -1094,8 +1094,8 @@ export class Agent implements ACPAgent { const currentModeId = await (async () => { if (!availableModes.length) return undefined - const defaultAgentName = await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultAgent())) - const resolvedModeId = availableModes.find((mode) => mode.name === defaultAgentName)?.id ?? availableModes[0].id + const defaultAgent = await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultInfo())) + const resolvedModeId = availableModes.find((mode) => mode.name === defaultAgent.name)?.id ?? availableModes[0].id this.sessionManager.setMode(sessionId, resolvedModeId) return resolvedModeId })() @@ -1328,7 +1328,8 @@ export class Agent implements ACPAgent { if (!current) { this.sessionManager.setModel(session.id, model) } - const agent = session.modeId ?? (await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultAgent()))) + const agent = + session.modeId ?? (await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultInfo()))).name const parts: Array< | { type: "text"; text: string; synthetic?: boolean; ignored?: boolean } diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index c1a644282b..1e4d7e1563 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -15,12 +15,12 @@ import PROMPT_TITLE from "./prompt/title.txt" import { Permission } from "@/permission" import { mergeDeep, pipe, sortBy, values } from "remeda" import { Global } from "@opencode-ai/core/global" -import { Flag } from "@opencode-ai/core/flag/flag" import path from "path" import { Plugin } from "@/plugin" import { Skill } from "../skill" import { Effect, Context, Layer, Schema } from "effect" import { InstanceState } from "@/effect/instance-state" +import { RuntimeFlags } from "@/effect/runtime-flags" import * as Option from "effect/Option" import * as OtelTracer from "@effect/opentelemetry/Tracer" import { type DeepMutable } from "@opencode-ai/core/schema" @@ -57,6 +57,7 @@ const GeneratedAgent = Schema.Struct({ export interface Interface { readonly get: (agent: string) => Effect.Effect readonly list: () => Effect.Effect + readonly defaultInfo: () => Effect.Effect readonly defaultAgent: () => Effect.Effect readonly generate: (input: { description: string @@ -80,6 +81,7 @@ export const layer = Layer.effect( const plugin = yield* Plugin.Service const skill = yield* Skill.Service const provider = yield* Provider.Service + const flags = yield* RuntimeFlags.Service const state = yield* InstanceState.make( Effect.fn("Agent.state")(function* (ctx) { @@ -194,7 +196,7 @@ export const layer = Layer.effect( mode: "subagent", native: true, }, - ...(Flag.OPENCODE_EXPERIMENTAL_SCOUT + ...(flags.experimentalScout ? { scout: { name: "scout", @@ -333,23 +335,28 @@ export const layer = Layer.effect( ) }) - const defaultAgent = Effect.fnUntraced(function* () { + const defaultInfo = Effect.fnUntraced(function* () { const c = yield* config.get() if (c.default_agent) { const agent = agents[c.default_agent] if (!agent) throw new Error(`default agent "${c.default_agent}" not found`) if (agent.mode === "subagent") throw new Error(`default agent "${c.default_agent}" is a subagent`) if (agent.hidden === true) throw new Error(`default agent "${c.default_agent}" is hidden`) - return agent.name + return agent } const visible = Object.values(agents).find((a) => a.mode !== "subagent" && a.hidden !== true) if (!visible) throw new Error("no primary visible agent found") - return visible.name + return visible + }) + + const defaultAgent = Effect.fnUntraced(function* () { + return (yield* defaultInfo()).name }) return { get, list, + defaultInfo, defaultAgent, } satisfies State }), @@ -362,6 +369,9 @@ export const layer = Layer.effect( list: Effect.fn("Agent.list")(function* () { return yield* InstanceState.useEffect(state, (s) => s.list()) }), + defaultInfo: Effect.fn("Agent.defaultInfo")(function* () { + return yield* InstanceState.useEffect(state, (s) => s.defaultInfo()) + }), defaultAgent: Effect.fn("Agent.defaultAgent")(function* () { return yield* InstanceState.useEffect(state, (s) => s.defaultAgent()) }), @@ -444,6 +454,7 @@ export const defaultLayer = layer.pipe( Layer.provide(Auth.defaultLayer), Layer.provide(Config.defaultLayer), Layer.provide(Skill.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), ) export * as Agent from "./agent" diff --git a/packages/opencode/src/agent/subagent-permissions.ts b/packages/opencode/src/agent/subagent-permissions.ts index 1174ec31ad..051f42e37b 100644 --- a/packages/opencode/src/agent/subagent-permissions.ts +++ b/packages/opencode/src/agent/subagent-permissions.ts @@ -5,10 +5,10 @@ import type { Agent } from "./agent" * Build the `permission` ruleset for a subagent's session when it's spawned * via the task tool. Combines: * - * 1. The parent **agent's** deny rules — Plan Mode and other agent-level - * restrictions live on the agent ruleset, not on the session, so a + * 1. The parent **agent's** edit-class deny rules — Plan Mode's file-edit + * restriction lives on the agent ruleset, not on the session, so a * subagent that only inherited the parent SESSION's permission would - * silently bypass them. (#26514) + * silently bypass it. (#26514) * 2. The parent **session's** deny rules and external_directory rules — * same forwarding the original code already did. * 3. Default `todowrite` and `task` denies if the subagent's own ruleset @@ -21,7 +21,8 @@ export function deriveSubagentSessionPermission(input: { }): Permission.Ruleset { const canTask = input.subagent.permission.some((rule) => rule.permission === "task") const canTodo = input.subagent.permission.some((rule) => rule.permission === "todowrite") - const parentAgentDenies = input.parentAgent?.permission.filter((rule) => rule.action === "deny") ?? [] + const parentAgentDenies = + input.parentAgent?.permission.filter((rule) => rule.action === "deny" && rule.permission === "edit") ?? [] return [ ...parentAgentDenies, ...input.parentSessionPermission.filter( diff --git a/packages/opencode/src/audio.d.ts b/packages/opencode/src/audio.d.ts index c7c947450d..7b99d097a3 100644 --- a/packages/opencode/src/audio.d.ts +++ b/packages/opencode/src/audio.d.ts @@ -3,6 +3,11 @@ declare module "*.wav" { export default file } +declare module "*.mp3" { + const file: string + export default file +} + declare module "*.wasm" { const file: string export default file diff --git a/packages/opencode/src/cli/cmd/debug/index.ts b/packages/opencode/src/cli/cmd/debug/index.ts index 6e2643f688..67ea51af6d 100644 --- a/packages/opencode/src/cli/cmd/debug/index.ts +++ b/packages/opencode/src/cli/cmd/debug/index.ts @@ -16,6 +16,7 @@ import { SkillCommand } from "./skill" import { SnapshotCommand } from "./snapshot" import { AgentCommand } from "./agent" import { StartupCommand } from "./startup" +import { V2Command } from "./v2" export const DebugCommand = cmd({ command: "debug", @@ -31,6 +32,7 @@ export const DebugCommand = cmd({ .command(SnapshotCommand) .command(StartupCommand) .command(AgentCommand) + .command(V2Command) .command(InfoCommand) .command(PathsCommand) .command(WaitCommand) diff --git a/packages/opencode/src/cli/cmd/debug/v2.ts b/packages/opencode/src/cli/cmd/debug/v2.ts new file mode 100644 index 0000000000..a4e69cc494 --- /dev/null +++ b/packages/opencode/src/cli/cmd/debug/v2.ts @@ -0,0 +1,40 @@ +import { EOL } from "os" +import { Effect, Layer, Option } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" +import { effectCmd } from "../../effect-cmd" +import { PluginBoot } from "@/v2/plugin-boot" + +const layer = Catalog.defaultLayer.pipe(Layer.provide(PluginBoot.defaultLayer)) + +export const V2Command = effectCmd({ + command: "v2", + describe: "debug v2 catalog and built-in plugins", + instance: false, + handler: Effect.fn("Cli.debug.v2")(function* () { + const result = yield* Effect.gen(function* () { + const catalog = yield* Catalog.Service + + const providers = (yield* catalog.provider.available()).sort((a, b) => a.id.localeCompare(b.id)) + const all = (yield* catalog.provider.all()).sort((a, b) => a.id.localeCompare(b.id)) + return { + providers, + default: catalog.model + .default() + .pipe(Effect.map(Option.map((item) => item.id)), Effect.map(Option.getOrUndefined)), + small: Object.fromEntries( + yield* Effect.all( + all.map((provider) => + Effect.map( + catalog.model.small(provider.id), + (model) => [provider.id, Option.getOrUndefined(Option.map(model, (item) => item.id))] as const, + ), + ), + { concurrency: "unbounded" }, + ), + ), + } + }).pipe(Effect.provide(layer), Effect.orDie) + + process.stdout.write(JSON.stringify(result, null, 2) + EOL) + }), +}) diff --git a/packages/opencode/src/cli/cmd/providers.ts b/packages/opencode/src/cli/cmd/providers.ts index 749139e2dc..426ea89fc5 100644 --- a/packages/opencode/src/cli/cmd/providers.ts +++ b/packages/opencode/src/cli/cmd/providers.ts @@ -124,6 +124,7 @@ const handlePluginAuth = Effect.fn("Cli.providers.pluginAuth")(function* ( yield* put(saveProvider, { type: "api", key: result.key, + ...(result.metadata ? { metadata: result.metadata } : {}), }) } yield* spinner.stop("Login successful") @@ -156,6 +157,7 @@ const handlePluginAuth = Effect.fn("Cli.providers.pluginAuth")(function* ( yield* put(saveProvider, { type: "api", key: result.key, + ...(result.metadata ? { metadata: result.metadata } : {}), }) } yield* Prompt.log.success("Login successful") @@ -191,10 +193,11 @@ const handlePluginAuth = Effect.fn("Cli.providers.pluginAuth")(function* ( } if (result.type === "success") { const saveProvider = result.provider ?? provider + const merged = { ...(metadata.metadata ?? {}), ...(result.metadata ?? {}) } yield* put(saveProvider, { type: "api", key: result.key ?? apiKey, - ...metadata, + ...(Object.keys(merged).length ? { metadata: merged } : {}), }) yield* Prompt.log.success("Login successful") } diff --git a/packages/opencode/src/cli/cmd/stats.ts b/packages/opencode/src/cli/cmd/stats.ts index 3dadea9dd0..7ee16c2e21 100644 --- a/packages/opencode/src/cli/cmd/stats.ts +++ b/packages/opencode/src/cli/cmd/stats.ts @@ -1,6 +1,7 @@ import { Effect } from "effect" import { effectCmd } from "../effect-cmd" import { Session } from "@/session/session" +import { NotFoundError } from "@/storage/storage" import { Database } from "@/storage/db" import { SessionTable } from "../../session/session.sql" import { Project } from "@/project/project" @@ -162,7 +163,9 @@ const aggregateSessionStats = Effect.fn("Cli.stats.aggregate")(function* ( filteredSessions, (session) => Effect.gen(function* () { - const messages = yield* svc.messages({ sessionID: session.id }) + const messages = yield* svc + .messages({ sessionID: session.id }) + .pipe(Effect.catchIf(NotFoundError.isInstance, () => Effect.succeed([]))) const sessionCost = session.cost ?? 0 const sessionTokens = session.tokens ?? { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } } diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index d7f2cd14b0..29cca133bb 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -2,6 +2,7 @@ import { render, TimeToFirstDraw, useRenderer, useTerminalDimensions } from "@op import { createDefaultOpenTuiKeymap } from "@opentui/keymap/opentui" import * as Clipboard from "@tui/util/clipboard" import * as Selection from "@tui/util/selection" +import * as TuiAudio from "@tui/util/audio" import { createCliRenderer, MouseButton, type CliRendererConfig } from "@opentui/core" import { RouteProvider, useRoute } from "@tui/context/route" import { @@ -63,6 +64,7 @@ import { TuiConfig } from "@/cli/cmd/tui/config/tui" import { TuiPluginRuntime } from "@/cli/cmd/tui/plugin/runtime" import { createTuiApi } from "@/cli/cmd/tui/plugin/api" import type { RouteMap } from "@/cli/cmd/tui/plugin/api" +import { createTuiAttention } from "@/cli/cmd/tui/attention" import { FormatError, FormatUnknownError } from "@/cli/error" import { CommandPaletteProvider, useCommandPalette } from "./context/command-palette" import { OpencodeKeymapProvider, registerOpencodeKeymap, useBindings, useOpencodeKeymap } from "./keymap" @@ -176,10 +178,10 @@ export function tui(input: { unguard?.() resolve() } - const onBeforeExit = async () => { offKeymap() await TuiPluginRuntime.dispose() + TuiAudio.dispose() } const renderer = await createCliRenderer(rendererConfig(input.config)) @@ -283,6 +285,7 @@ function App(props: { onSnapshot?: () => Promise }) { routeRev() return routes.get(name)?.at(-1)?.render } + const attention = createTuiAttention({ renderer, config: tuiConfig, kv }) const api = createTuiApi({ tuiConfig, @@ -298,11 +301,13 @@ function App(props: { onSnapshot?: () => Promise }) { theme: themeState, toast, renderer, + attention, }) const [ready, setReady] = createSignal(false) TuiPluginRuntime.init({ api, config: tuiConfig, + dispose: () => attention.dispose(), }) .catch((error) => { console.error("Failed to load TUI plugins", error) @@ -320,7 +325,10 @@ function App(props: { onSnapshot?: () => Promise }) { }, { priority: 1 }, ) - onCleanup(offSelectionKeys) + onCleanup(() => { + offSelectionKeys() + attention.dispose() + }) // Wire up console copy-to-clipboard via opentui's onCopySelection callback renderer.console.onCopySelection = async (text: string) => { diff --git a/packages/opencode/src/cli/cmd/tui/asset/charge.wav b/packages/opencode/src/cli/cmd/tui/asset/charge.wav deleted file mode 100644 index d9597899cd..0000000000 Binary files a/packages/opencode/src/cli/cmd/tui/asset/charge.wav and /dev/null differ diff --git a/packages/opencode/src/cli/cmd/tui/asset/pulse-a.wav b/packages/opencode/src/cli/cmd/tui/asset/pulse-a.wav deleted file mode 100644 index 2ebb6a38bc..0000000000 Binary files a/packages/opencode/src/cli/cmd/tui/asset/pulse-a.wav and /dev/null differ diff --git a/packages/opencode/src/cli/cmd/tui/asset/pulse-b.wav b/packages/opencode/src/cli/cmd/tui/asset/pulse-b.wav deleted file mode 100644 index 4e1b59c964..0000000000 Binary files a/packages/opencode/src/cli/cmd/tui/asset/pulse-b.wav and /dev/null differ diff --git a/packages/opencode/src/cli/cmd/tui/asset/pulse-c.wav b/packages/opencode/src/cli/cmd/tui/asset/pulse-c.wav deleted file mode 100644 index feb56cacda..0000000000 Binary files a/packages/opencode/src/cli/cmd/tui/asset/pulse-c.wav and /dev/null differ diff --git a/packages/opencode/src/cli/cmd/tui/attention.ts b/packages/opencode/src/cli/cmd/tui/attention.ts new file mode 100644 index 0000000000..f6480961dc --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/attention.ts @@ -0,0 +1,262 @@ +import type { + TuiAttention, + TuiAttentionNotifyInput, + TuiAttentionNotifyResult, + TuiAttentionNotifySkipReason, + TuiAttentionWhen, + TuiKV, + TuiAttentionSoundName, + TuiAttentionSoundPack, + TuiAttentionSoundPackInfo, +} from "@opencode-ai/plugin/tui" +import stripAnsi from "strip-ansi" +import type { TuiConfig } from "./config/tui" +import { isAttentionSoundName } from "./config/tui-schema" +import * as TuiAudio from "@tui/util/audio" +import defaultSoundPath from "@opencode-ai/ui/audio/bip-bop-01.mp3" with { type: "file" } +import questionSoundPath from "@opencode-ai/ui/audio/bip-bop-03.mp3" with { type: "file" } +import permissionSoundPath from "@opencode-ai/ui/audio/staplebops-06.mp3" with { type: "file" } +import errorSoundPath from "@opencode-ai/ui/audio/nope-03.mp3" with { type: "file" } +import doneSoundPath from "@opencode-ai/ui/audio/bip-bop-01.mp3" with { type: "file" } +import subagentDoneSoundPath from "@opencode-ai/ui/audio/yup-01.mp3" with { type: "file" } +import * as Log from "@opencode-ai/core/util/log" + +type FocusState = "unknown" | "focused" | "blurred" + +type AttentionRenderer = { + readonly isDestroyed: boolean + on(event: "focus" | "blur", listener: () => void): unknown + off(event: "focus" | "blur", listener: () => void): unknown + triggerNotification(message: string, title?: string): boolean +} + +type RegisteredSoundPack = TuiAttentionSoundPack & { + builtin: boolean +} + +type TuiAttentionHost = TuiAttention & { + dispose(): void +} + +const log = Log.create({ service: "tui.attention" }) + +const DEFAULT_TITLE = "opencode" +const DEFAULT_PACK_ID = "opencode.default" +const KV_SOUND_PACK = "attention_sound_pack" +const TITLE_LIMIT = 80 +const MESSAGE_LIMIT = 240 +const BUILTIN_PACK: RegisteredSoundPack = { + id: DEFAULT_PACK_ID, + name: "OpenCode Default", + builtin: true, + sounds: { + default: defaultSoundPath, + question: questionSoundPath, + permission: permissionSoundPath, + error: errorSoundPath, + done: doneSoundPath, + subagent_done: subagentDoneSoundPath, + }, +} + +function skipped(reason: TuiAttentionNotifySkipReason): TuiAttentionNotifyResult { + return { + ok: false, + notification: false, + sound: false, + skipped: reason, + } +} + +function normalizeText(input: string | undefined, fallback: string, limit: number) { + const text = stripAnsi(input ?? "") + .replace(/[ \t]*[\r\n]+[ \t]*/g, " ") + .replace(/[\u0000-\u0009\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "") + .trim() + const normalized = text.length ? text : fallback + return Array.from(normalized).slice(0, limit).join("") +} + +function clampVolume(volume: number) { + if (!Number.isFinite(volume)) return 0 + return Math.min(1, Math.max(0, volume)) +} + +function soundVolume(input: TuiAttentionNotifyInput, config: Pick) { + if (!config.attention.sound) return + if (input.sound === false) return + if (input.sound === undefined) return clampVolume(config.attention.volume) + if (input.sound === true) return clampVolume(config.attention.volume) + return clampVolume(input.sound.volume ?? config.attention.volume) +} + +function normalizePack(pack: TuiAttentionSoundPack): RegisteredSoundPack | undefined { + const id = pack.id.trim() + if (!id) return + return { + id, + name: pack.name?.trim() || undefined, + builtin: false, + sounds: Object.fromEntries( + Object.entries(pack.sounds).filter( + (item): item is [TuiAttentionSoundName, string] => + isAttentionSoundName(item[0]) && typeof item[1] === "string" && item[1].trim().length > 0, + ), + ), + } +} + +function focusSkip(when: TuiAttentionWhen, focus: FocusState) { + if (when === "always") return + if (focus === "unknown") return "focus_unknown" + if (when === "blurred" && focus === "focused") return "focused" + if (when === "focused" && focus === "blurred") return "blurred" +} + +export function createTuiAttention(input: { + renderer: AttentionRenderer + config: Pick + kv?: TuiKV + audio?: Pick +}): TuiAttentionHost { + let focus: FocusState = "unknown" + let disposed = false + let activePackID: string | undefined + const packs = new Map([[BUILTIN_PACK.id, BUILTIN_PACK]]) + const audio = input.audio ?? TuiAudio + + const onFocus = () => { + focus = "focused" + } + const onBlur = () => { + focus = "blurred" + } + + input.renderer.on("focus", onFocus) + input.renderer.on("blur", onBlur) + + function configuredPackID() { + const stored = input.kv?.get(KV_SOUND_PACK, undefined) + return activePackID ?? stored ?? input.config.attention.sound_pack + } + + function currentPack() { + return packs.get(configuredPackID()) ?? BUILTIN_PACK + } + + function soundCandidates(name: TuiAttentionSoundName) { + return [input.config.attention.sounds[name], currentPack().sounds[name], BUILTIN_PACK.sounds[name]].filter( + (item, index, list): item is string => typeof item === "string" && list.indexOf(item) === index, + ) + } + + async function playSound(name: TuiAttentionSoundName, volume: number) { + try { + for (const file of soundCandidates(name)) { + const current = await audio.loadSoundFile(file).catch((error) => { + log.debug("failed to load attention sound", { file, error }) + return null + }) + if (disposed) return false + if (current == null) continue + if (audio.play(current, { volume }) != null) return true + } + return false + } catch (error) { + log.debug("failed to play attention sound", { error }) + return false + } + } + + return { + async notify(request) { + try { + if (!input.config.attention.enabled) return skipped("attention_disabled") + if (disposed || input.renderer.isDestroyed) return skipped("renderer_destroyed") + + const message = normalizeText(request.message, "", MESSAGE_LIMIT) + if (!message) return skipped("empty_message") + + const requestedNotification = typeof request.notification === "object" ? request.notification : undefined + const notificationSkip = focusSkip(requestedNotification?.when ?? "blurred", focus) + const notificationRequested = input.config.attention.notifications && request.notification !== false + const shouldNotify = notificationRequested && !notificationSkip + const notification = shouldNotify + ? (() => { + try { + return input.renderer.triggerNotification( + message, + normalizeText(request.title, DEFAULT_TITLE, TITLE_LIMIT), + ) + } catch (error) { + log.debug("failed to trigger attention notification", { error }) + return false + } + })() + : false + const volume = soundVolume(request, input.config) + const requestedSound = typeof request.sound === "object" ? request.sound : undefined + const soundSkip = volume === undefined ? undefined : focusSkip(requestedSound?.when ?? "always", focus) + const soundName = + requestedSound?.name && isAttentionSoundName(requestedSound.name) ? requestedSound.name : "default" + const sound = volume === undefined || soundSkip ? false : await playSound(soundName, volume) + + if (!notification && !sound) { + if (notificationRequested && notificationSkip) return skipped(notificationSkip) + if (soundSkip) return skipped(soundSkip) + } + + return { + ok: notification || sound, + notification, + sound, + } + } catch (error) { + log.debug("failed to handle attention notification", { error }) + return { + ok: false, + notification: false, + sound: false, + } + } + }, + soundboard: { + registerPack(pack) { + const next = normalizePack(pack) + if (!next) return () => {} + packs.set(next.id, next) + let disposed = false + return () => { + if (disposed) return + disposed = true + if (packs.get(next.id) === next) packs.delete(next.id) + } + }, + activate(id, options) { + const pack = packs.get(id) + if (!pack) return false + activePackID = pack.id + if (options?.persist) input.kv?.set(KV_SOUND_PACK, pack.id) + return true + }, + current() { + return currentPack().id + }, + list(): TuiAttentionSoundPackInfo[] { + const current = currentPack().id + return Array.from(packs.values()).map((pack) => ({ + id: pack.id, + name: pack.name, + active: pack.id === current, + builtin: pack.builtin, + })) + }, + }, + dispose() { + if (disposed) return + disposed = true + input.renderer.off("focus", onFocus) + input.renderer.off("blur", onBlur) + }, + } +} diff --git a/packages/opencode/src/cli/cmd/tui/component/logo.tsx b/packages/opencode/src/cli/cmd/tui/component/logo.tsx index e3e8074cd1..557b868774 100644 --- a/packages/opencode/src/cli/cmd/tui/component/logo.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/logo.tsx @@ -2,7 +2,6 @@ import { BoxRenderable, MouseButton, MouseEvent, RGBA, TextAttributes } from "@o import { useRenderer } from "@opentui/solid" import { For, createMemo, createSignal, onCleanup, onMount, type JSX } from "solid-js" import { useTheme, tint } from "@tui/context/theme" -import * as Sound from "@tui/util/sound" import { go, logo } from "@/cli/logo" export type LogoShape = { @@ -563,7 +562,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } = const [now, setNow] = createSignal(0) let box: BoxRenderable | undefined let timer: ReturnType | undefined - let hum = false const stop = () => { if (!timer) return @@ -575,10 +573,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } = const t = performance.now() setNow(t) const item = hold() - if (item && !hum && t - item.at >= HOLD) { - hum = true - Sound.start() - } if (item && t - item.at >= CHARGE) { burst(item.x, item.y) } @@ -605,8 +599,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } = onCleanup(() => { stop() - hum = false - Sound.dispose() }) onMount(() => { @@ -626,14 +618,12 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } = setNow(t) if (!last) setRelease(undefined) setHold({ x, y, at: t, glyph: select(x, y, ctx) }) - hum = false start() } const burst = (x: number, y: number) => { const item = hold() if (!item) return - hum = false const t = performance.now() const age = t - item.at const rise = ramp(age, HOLD, CHARGE) @@ -655,7 +645,6 @@ export function Logo(props: { shape?: LogoShape; ink?: RGBA; idle?: boolean } = ]) setNow(t) start() - Sound.pulse(lerp(0.8, 1, level)) } const frame = createMemo(() => { diff --git a/packages/opencode/src/cli/cmd/tui/config/tui-schema.ts b/packages/opencode/src/cli/cmd/tui/config/tui-schema.ts index 80765da3c7..2c99f2a5ef 100644 --- a/packages/opencode/src/cli/cmd/tui/config/tui-schema.ts +++ b/packages/opencode/src/cli/cmd/tui/config/tui-schema.ts @@ -1,12 +1,47 @@ import { ConfigPlugin } from "@/config/plugin" import { TuiKeybind } from "./keybind" import { Schema } from "effect" +import { isRecord } from "@/util/record" +import { Filesystem } from "@/util/filesystem" +import { TuiAttentionSoundNames, type TuiAttentionSoundName } from "@opencode-ai/plugin/tui" + +export type TuiAttentionSoundPaths = Partial> + +export function isAttentionSoundName(value: string): value is TuiAttentionSoundName { + return TuiAttentionSoundNames.includes(value as TuiAttentionSoundName) +} + +export function resolveAttentionSoundPaths( + root: string, + sounds: unknown, + options?: { trim?: boolean }, +): TuiAttentionSoundPaths { + if (!isRecord(sounds)) return {} + return Object.fromEntries( + Object.entries(sounds).flatMap(([name, file]) => { + if (!isAttentionSoundName(name)) return [] + if (typeof file !== "string") return [] + const value = options?.trim ? file.trim() : file + if (!value) return [] + return [[name, Filesystem.resolveFilePath(root, value)]] + }), + ) +} export const KeymapLeaderTimeoutDefault = 2000 const KeymapLeaderTimeout = Schema.Int.check(Schema.isGreaterThan(0)).annotate({ description: "Leader key timeout in milliseconds", }) +const TuiAttentionSounds = Schema.Struct({ + default: Schema.optional(Schema.String), + question: Schema.optional(Schema.String), + permission: Schema.optional(Schema.String), + error: Schema.optional(Schema.String), + done: Schema.optional(Schema.String), + subagent_done: Schema.optional(Schema.String), +}) + export const ScrollSpeed = Schema.Number.check(Schema.isGreaterThanOrEqualTo(0.001)) export const ScrollAcceleration = Schema.Struct({ @@ -17,6 +52,15 @@ export const DiffStyle = Schema.Literals(["auto", "stacked"]).annotate({ description: "Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column", }) +export const Attention = Schema.Struct({ + enabled: Schema.optional(Schema.Boolean), + notifications: Schema.optional(Schema.Boolean), + sound: Schema.optional(Schema.Boolean), + volume: Schema.optional(Schema.Number.check(Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(1))), + sound_pack: Schema.optional(Schema.String), + sounds: Schema.optional(TuiAttentionSounds), +}).annotate({ description: "Attention notification and sound settings" }) + export const TuiInfo = Schema.Struct({ $schema: Schema.optional(Schema.String), theme: Schema.optional(Schema.String), @@ -24,6 +68,7 @@ export const TuiInfo = Schema.Struct({ plugin: Schema.optional(Schema.Array(ConfigPlugin.Spec)), plugin_enabled: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)), leader_timeout: Schema.optional(KeymapLeaderTimeout), + attention: Schema.optional(Attention), scroll_speed: Schema.optional(ScrollSpeed).annotate({ description: "TUI scroll speed", }), diff --git a/packages/opencode/src/cli/cmd/tui/config/tui.ts b/packages/opencode/src/cli/cmd/tui/config/tui.ts index e53e20d343..562b369db1 100644 --- a/packages/opencode/src/cli/cmd/tui/config/tui.ts +++ b/packages/opencode/src/cli/cmd/tui/config/tui.ts @@ -1,5 +1,6 @@ export * as TuiConfig from "./tui" +import path from "path" import { createBindingLookup } from "@opentui/keymap/extras" import { mergeDeep, unique } from "remeda" import { Context, Effect, Fiber, Layer, Schema } from "effect" @@ -7,7 +8,7 @@ import { ConfigParse } from "@/config/parse" import { InvalidError } from "@/config/error" import * as ConfigPaths from "@/config/paths" import { migrateTuiConfig } from "./tui-migrate" -import { KeymapLeaderTimeoutDefault, TuiInfo } from "./tui-schema" +import { KeymapLeaderTimeoutDefault, resolveAttentionSoundPaths, TuiInfo } from "./tui-schema" import { Flag } from "@opencode-ai/core/flag/flag" import { isRecord } from "@/util/record" import { Global } from "@opencode-ai/core/global" @@ -22,6 +23,7 @@ import * as Log from "@opencode-ai/core/util/log" import { ConfigVariable } from "@/config/variable" import { Npm } from "@opencode-ai/core/npm" import type { DeepMutable } from "@opencode-ai/core/schema" +import type { TuiAttentionSoundName } from "@opencode-ai/plugin/tui" const log = Log.create({ service: "tui.config" }) @@ -33,7 +35,15 @@ type Acc = { plugin_origins: ConfigPlugin.Origin[] } -export type Resolved = Omit & { +export type Resolved = Omit & { + attention: { + enabled: boolean + notifications: boolean + sound: boolean + volume: number + sound_pack: string + sounds: Partial> + } keybinds: TuiKeybind.BindingLookupView leader_timeout: number // Internal resolved plugin list used by runtime loading. @@ -101,7 +111,16 @@ const loadState = Effect.fn("TuiConfig.loadState")(function* (ctx: { directory: }) } } - const validated = ConfigParse.schema(Info, normalized, configFilepath) + const parsed = ConfigParse.schema(Info, normalized, configFilepath) + const validated = parsed.attention?.sounds + ? { + ...parsed, + attention: { + ...parsed.attention, + sounds: resolveAttentionSoundPaths(path.dirname(configFilepath), parsed.attention.sounds), + }, + } + : parsed return yield* resolvePlugins(validated, configFilepath) }).pipe( // catchCause (not tapErrorCause + orElseSucceed) because JSONC parsing and validation @@ -197,6 +216,14 @@ const loadState = Effect.fn("TuiConfig.loadState")(function* (ctx: { directory: const parsedKeybinds = TuiKeybind.parse(keybinds) const result: Resolved = { ...acc.result, + attention: { + enabled: acc.result.attention?.enabled ?? false, + notifications: acc.result.attention?.notifications ?? true, + sound: acc.result.attention?.sound ?? true, + volume: acc.result.attention?.volume ?? 0.4, + sound_pack: acc.result.attention?.sound_pack ?? "opencode.default", + sounds: acc.result.attention?.sounds ?? {}, + }, keybinds: createBindingLookup(TuiKeybind.toBindingConfig(parsedKeybinds), { commandMap: TuiKeybind.CommandMap, bindingDefaults: TuiKeybind.bindingDefaults(), diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx index 07a2844e93..8c50914df3 100644 --- a/packages/opencode/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx @@ -1,11 +1,52 @@ -import { createMemo, For } from "solid-js" +import type { TuiPluginApi } from "@opencode-ai/plugin/tui" +import { createMemo, For, type Accessor } from "solid-js" import { DEFAULT_THEMES, useTheme } from "@tui/context/theme" import { Flag } from "@opencode-ai/core/flag/flag" +import { useCommandShortcut } from "../../keymap" const themeCount = Object.keys(DEFAULT_THEMES).length -const themeTip = `Use {highlight}/themes{/highlight} or {highlight}Ctrl+X T{/highlight} to switch between ${themeCount} built-in themes` type TipPart = { text: string; highlight: boolean } +type TipShortcut = Accessor +type Shortcuts = { + agentCycle: TipShortcut + childFirst: TipShortcut + childNext: TipShortcut + childPrevious: TipShortcut + commandList: TipShortcut + editorOpen: TipShortcut + helpShow: TipShortcut + inputClear: TipShortcut + inputNewline: TipShortcut + inputPaste: TipShortcut + inputUndo: TipShortcut + leader: TipShortcut + messagesCopy: TipShortcut + messagesFirst: TipShortcut + messagesLast: TipShortcut + messagesPageDown: TipShortcut + messagesPageUp: TipShortcut + messagesToggleConceal: TipShortcut + modelCycleRecent: TipShortcut + modelList: TipShortcut + sessionCycleRecent: TipShortcut + sessionCycleRecentReverse: TipShortcut + sessionExport: TipShortcut + sessionInterrupt: TipShortcut + sessionList: TipShortcut + sessionNew: TipShortcut + sessionParent: TipShortcut + sessionPinToggle: TipShortcut + sessionQuickSwitch1: TipShortcut + sessionQuickSwitch9: TipShortcut + sessionSidebarToggle: TipShortcut + sessionTimeline: TipShortcut + sessionToggleRecent: TipShortcut + statusView: TipShortcut + terminalSuspend: TipShortcut + themeList: TipShortcut +} +type Tip = string | ((shortcuts: Shortcuts) => string | undefined) function parse(tip: string): TipPart[] { const parts: TipPart[] = [] @@ -33,17 +74,86 @@ function parse(tip: string): TipPart[] { const NO_MODELS_TIP = "Run {highlight}/connect{/highlight} to add an AI provider and start coding" -export function Tips(props: { connected?: boolean }) { +function shortcutText(value: string) { + return `{highlight}${value}{/highlight}` +} + +function commandText(command: string, shortcut: string) { + if (!shortcut) return shortcutText(command) + return `${shortcutText(command)} or ${shortcutText(shortcut)}` +} + +function press(shortcut: string, text: string) { + if (!shortcut) return undefined + return `Press ${shortcutText(shortcut)} ${text}` +} + +function configShortcut(api: TuiPluginApi, command: string): TipShortcut { + return () => + api.tuiConfig.keybinds + .get(command) + .map((binding) => api.keys.formatSequence(Array.from(api.keymap.parseKeySequence(binding.key)))) + .filter(Boolean) + .join(", ") +} + +export function Tips(props: { api: TuiPluginApi; connected?: boolean }) { const theme = useTheme().theme - const randomTip = TIPS[Math.floor(Math.random() * TIPS.length)] - const parts = createMemo(() => parse(props.connected === false ? NO_MODELS_TIP : randomTip)) + const tipOffset = Math.random() + const shortcuts: Shortcuts = { + agentCycle: useCommandShortcut("agent.cycle"), + childFirst: configShortcut(props.api, "session.child.first"), + childNext: configShortcut(props.api, "session.child.next"), + childPrevious: configShortcut(props.api, "session.child.previous"), + commandList: useCommandShortcut("command.palette.show"), + editorOpen: useCommandShortcut("prompt.editor"), + helpShow: useCommandShortcut("help.show"), + inputClear: useCommandShortcut("prompt.clear"), + inputNewline: useCommandShortcut("input.newline"), + inputPaste: useCommandShortcut("prompt.paste"), + inputUndo: useCommandShortcut("input.undo"), + leader: configShortcut(props.api, "leader"), + messagesCopy: configShortcut(props.api, "messages.copy"), + messagesFirst: configShortcut(props.api, "session.first"), + messagesLast: configShortcut(props.api, "session.last"), + messagesPageDown: configShortcut(props.api, "session.page.down"), + messagesPageUp: configShortcut(props.api, "session.page.up"), + messagesToggleConceal: configShortcut(props.api, "session.toggle.conceal"), + modelCycleRecent: useCommandShortcut("model.cycle_recent"), + modelList: useCommandShortcut("model.list"), + sessionCycleRecent: useCommandShortcut("session.cycle_recent"), + sessionCycleRecentReverse: useCommandShortcut("session.cycle_recent_reverse"), + sessionExport: configShortcut(props.api, "session.export"), + sessionInterrupt: configShortcut(props.api, "session.interrupt"), + sessionList: useCommandShortcut("session.list"), + sessionNew: useCommandShortcut("session.new"), + sessionParent: configShortcut(props.api, "session.parent"), + sessionPinToggle: configShortcut(props.api, "session.pin.toggle"), + sessionQuickSwitch1: useCommandShortcut("session.quick_switch.1"), + sessionQuickSwitch9: useCommandShortcut("session.quick_switch.9"), + sessionSidebarToggle: configShortcut(props.api, "session.sidebar.toggle"), + sessionTimeline: configShortcut(props.api, "session.timeline"), + sessionToggleRecent: configShortcut(props.api, "session.toggle.recent"), + statusView: useCommandShortcut("opencode.status"), + terminalSuspend: useCommandShortcut("terminal.suspend"), + themeList: useCommandShortcut("theme.switch"), + } + const tip = createMemo(() => { + if (props.connected === false) return NO_MODELS_TIP + const tips = TIPS.flatMap((item) => { + const value = typeof item === "string" ? item : item(shortcuts) + return value ? [value] : [] + }) + return tips[Math.floor(tipOffset * tips.length)] ?? NO_MODELS_TIP + }) + const parts = createMemo(() => parse(tip())) return ( ● Tip{" "} - + {(part) => {part.text}} @@ -52,46 +162,66 @@ export function Tips(props: { connected?: boolean }) { ) } -const TIPS = [ +const TIPS: Tip[] = [ "Type {highlight}@{/highlight} followed by a filename to fuzzy search and attach files", "Start a message with {highlight}!{/highlight} to run shell commands directly (e.g., {highlight}!ls -la{/highlight})", - "Press {highlight}Tab{/highlight} to cycle between Build and Plan agents", + (shortcuts) => press(shortcuts.agentCycle(), "to cycle between Build and Plan agents"), "Use {highlight}/undo{/highlight} to revert the last message and file changes", "Use {highlight}/redo{/highlight} to restore previously undone messages and file changes", "Run {highlight}/share{/highlight} to create a public link to your conversation at opencode.ai", "Drag and drop images or PDFs into the terminal to add them as context", - "Press {highlight}Ctrl+V{/highlight} to paste images from your clipboard into the prompt", - "Press {highlight}Ctrl+X E{/highlight} or {highlight}/editor{/highlight} to compose messages in your external editor", + (shortcuts) => press(shortcuts.inputPaste(), "to paste images from your clipboard into the prompt"), + (shortcuts) => `Use ${commandText("/editor", shortcuts.editorOpen())} to compose messages in your external editor`, "Run {highlight}/init{/highlight} to auto-generate project rules based on your codebase", - "Run {highlight}/models{/highlight} or {highlight}Ctrl+X M{/highlight} to see and switch between available AI models", - themeTip, - "Press {highlight}Ctrl+X N{/highlight} or {highlight}/new{/highlight} to start a fresh conversation session", - "Use {highlight}/sessions{/highlight} or {highlight}Ctrl+X L{/highlight} to list and continue previous conversations", + (shortcuts) => `Use ${commandText("/models", shortcuts.modelList())} to see and switch between available AI models`, + (shortcuts) => `Use ${commandText("/themes", shortcuts.themeList())} to switch between ${themeCount} built-in themes`, + (shortcuts) => `Use ${commandText("/new", shortcuts.sessionNew())} to start a fresh conversation session`, + (shortcuts) => `Use ${commandText("/sessions", shortcuts.sessionList())} to list and continue previous conversations`, ...(Flag.OPENCODE_EXPERIMENTAL_SESSION_SWITCHING - ? [ - "Press {highlight}Ctrl+F{/highlight} in the session list to pin a session so it stays at the top", - "Pinned and recent sessions are bound to {highlight}Ctrl+X 1{/highlight} through {highlight}Ctrl+X 9{/highlight} for one-press switching", - "Press {highlight}Ctrl+X ]{/highlight} / {highlight}Ctrl+X [{/highlight} to cycle through recently visited sessions", - "Press {highlight}Ctrl+H{/highlight} in the session list to show or hide a session in the Recent group", - ] + ? ([ + (shortcuts) => + press(shortcuts.sessionPinToggle(), "in the session list to pin a session so it stays at the top"), + (shortcuts) => + shortcuts.sessionQuickSwitch1() && shortcuts.sessionQuickSwitch9() + ? `Pinned and recent sessions are bound to ${shortcutText(shortcuts.sessionQuickSwitch1())} through ${shortcutText(shortcuts.sessionQuickSwitch9())} for one-press switching` + : undefined, + (shortcuts) => + shortcuts.sessionCycleRecent() && shortcuts.sessionCycleRecentReverse() + ? `Press ${shortcutText(shortcuts.sessionCycleRecent())} / ${shortcutText(shortcuts.sessionCycleRecentReverse())} to cycle through recently visited sessions` + : undefined, + (shortcuts) => + press(shortcuts.sessionToggleRecent(), "in the session list to show or hide a session in the Recent group"), + ] satisfies Tip[]) : []), "Run {highlight}/compact{/highlight} to summarize long sessions near context limits", - "Press {highlight}Ctrl+X X{/highlight} or {highlight}/export{/highlight} to save the conversation as Markdown", - "Press {highlight}Ctrl+X Y{/highlight} to copy the assistant's last message to clipboard", - "Press {highlight}Ctrl+P{/highlight} to see all available actions and commands", + (shortcuts) => `Use ${commandText("/export", shortcuts.sessionExport())} to save the conversation as Markdown`, + (shortcuts) => press(shortcuts.messagesCopy(), "to copy the assistant's last message to clipboard"), + (shortcuts) => press(shortcuts.commandList(), "to see all available actions and commands"), "Run {highlight}/connect{/highlight} to add API keys for 75+ supported LLM providers", - "The leader key is {highlight}Ctrl+X{/highlight}; combine with other keys for quick actions", - "Press {highlight}F2{/highlight} to quickly switch between recently used models", - "Press {highlight}Ctrl+X B{/highlight} to show/hide the sidebar panel", - "Use {highlight}PageUp{/highlight}/{highlight}PageDown{/highlight} to navigate through conversation history", - "Press {highlight}Ctrl+G{/highlight} or {highlight}Home{/highlight} to jump to the beginning of the conversation", - "Press {highlight}Ctrl+Alt+G{/highlight} or {highlight}End{/highlight} to jump to the most recent message", - "Press {highlight}Shift+Enter{/highlight} or {highlight}Ctrl+J{/highlight} to add newlines in your prompt", - "Press {highlight}Ctrl+C{/highlight} when typing to clear the input field", - "Press {highlight}Escape{/highlight} to stop the AI mid-response", + (shortcuts) => `The leader key is ${shortcutText(shortcuts.leader())}; combine with other keys for quick actions`, + (shortcuts) => press(shortcuts.modelCycleRecent(), "to quickly switch between recently used models"), + (shortcuts) => press(shortcuts.sessionSidebarToggle(), "in a session to show or hide the sidebar panel"), + (shortcuts) => + shortcuts.messagesPageUp() && shortcuts.messagesPageDown() + ? `Use ${shortcutText(shortcuts.messagesPageUp())}/${shortcutText(shortcuts.messagesPageDown())} to navigate through conversation history` + : undefined, + (shortcuts) => press(shortcuts.messagesFirst(), "to jump to the beginning of the conversation"), + (shortcuts) => press(shortcuts.messagesLast(), "to jump to the most recent message"), + (shortcuts) => press(shortcuts.inputNewline(), "to add newlines in your prompt"), + (shortcuts) => press(shortcuts.inputClear(), "when typing to clear the input field"), + (shortcuts) => press(shortcuts.sessionInterrupt(), "to stop the AI mid-response"), "Switch to {highlight}Plan{/highlight} agent to get suggestions without making actual changes", "Use {highlight}@agent-name{/highlight} in prompts to invoke specialized subagents", - "Press {highlight}Ctrl+X Right/Left{/highlight} to cycle through parent and child sessions", + (shortcuts) => { + const items = [ + shortcuts.sessionParent(), + shortcuts.childFirst(), + shortcuts.childPrevious(), + shortcuts.childNext(), + ].filter(Boolean) + if (!items.length) return undefined + return `Use ${items.map(shortcutText).join(" / ")} to move between parent and child sessions` + }, "Create {highlight}opencode.json{/highlight} for server settings and {highlight}tui.json{/highlight} for TUI settings", "Place TUI settings in {highlight}~/.config/opencode/tui.json{/highlight} for global config", "Add {highlight}$schema{/highlight} to your config for autocomplete in your editor", @@ -99,22 +229,21 @@ const TIPS = [ "Override any keybind in {highlight}tui.json{/highlight} via the {highlight}keybinds{/highlight} section", "Set any keybind to {highlight}none{/highlight} to disable it completely", "Configure local or remote MCP servers in the {highlight}mcp{/highlight} config section", - "OpenCode auto-handles OAuth for remote MCP servers requiring auth", - "Add {highlight}.md{/highlight} files to {highlight}.opencode/command/{/highlight} to define reusable custom prompts", + "Add {highlight}.md{/highlight} files to {highlight}.opencode/commands/{/highlight} to define reusable custom prompts", "Use {highlight}$ARGUMENTS{/highlight}, {highlight}$1{/highlight}, {highlight}$2{/highlight} in custom commands for dynamic input", "Use backticks in commands to inject shell output (e.g., {highlight}`git status`{/highlight})", - "Add {highlight}.md{/highlight} files to {highlight}.opencode/agent/{/highlight} for specialized AI personas", + "Add {highlight}.md{/highlight} files to {highlight}.opencode/agents/{/highlight} for specialized AI personas", "Configure per-agent permissions for {highlight}edit{/highlight}, {highlight}bash{/highlight}, and {highlight}webfetch{/highlight} tools", 'Use patterns like {highlight}"git *": "allow"{/highlight} for granular bash permissions', 'Set {highlight}"rm -rf *": "deny"{/highlight} to block destructive commands', 'Configure {highlight}"git push": "ask"{/highlight} to require approval before pushing', - "OpenCode auto-formats files using prettier, gofmt, ruff, and more", - 'Set {highlight}"formatter": false{/highlight} in config to disable all auto-formatting', + 'Set {highlight}"formatter": true{/highlight} in config to enable built-in formatters like prettier, gofmt, and ruff', + 'Set {highlight}"formatter": false{/highlight} in config to disable formatters enabled by another config layer', "Define custom formatter commands with file extensions in config", - "OpenCode uses LSP servers for intelligent code analysis", + 'Set {highlight}"lsp": true{/highlight} in config to enable built-in LSP servers for code analysis', "Create {highlight}.ts{/highlight} files in {highlight}.opencode/tools/{/highlight} to define new LLM tools", "Tool definitions can invoke scripts written in Python, Go, etc", - "Add {highlight}.ts{/highlight} files to {highlight}.opencode/plugin/{/highlight} for event hooks", + "Add {highlight}.ts{/highlight} files to {highlight}.opencode/plugins/{/highlight} for event hooks", "Use plugins to send OS notifications when sessions complete", "Create a plugin to prevent OpenCode from reading sensitive files", "Use {highlight}opencode run{/highlight} for non-interactive scripting", @@ -133,7 +262,7 @@ const TIPS = [ 'Use {highlight}"theme": "system"{/highlight} to match your terminal\'s colors', "Create JSON theme files in {highlight}.opencode/themes/{/highlight} directory", "Themes support dark/light variants for both modes", - "Reference ANSI colors 0-255 in custom themes", + "Use numeric xterm color codes 0-255 in custom theme JSON", "Use {highlight}{env:VAR_NAME}{/highlight} syntax to reference environment variables in config", "Use {highlight}{file:path}{/highlight} to include file contents in config values", "Use {highlight}instructions{/highlight} in config to load additional rules files", @@ -149,18 +278,23 @@ const TIPS = [ "Permission {highlight}external_directory{/highlight} protects files outside project", "Run {highlight}opencode debug config{/highlight} to troubleshoot configuration", "Use {highlight}--print-logs{/highlight} flag to see detailed logs in stderr", - "Press {highlight}Ctrl+X G{/highlight} or {highlight}/timeline{/highlight} to jump to specific messages", - "Press {highlight}Ctrl+X H{/highlight} to toggle code block visibility in messages", - "Press {highlight}Ctrl+X S{/highlight} or {highlight}/status{/highlight} to see system status info", + (shortcuts) => `Use ${commandText("/timeline", shortcuts.sessionTimeline())} to jump to specific messages`, + (shortcuts) => press(shortcuts.messagesToggleConceal(), "to toggle code block visibility in messages"), + (shortcuts) => `Use ${commandText("/status", shortcuts.statusView())} to see system status info`, "Enable {highlight}scroll_acceleration{/highlight} in {highlight}tui.json{/highlight} for smooth macOS-style scrolling", - "Toggle username display in chat via command palette ({highlight}Ctrl+P{/highlight})", + (shortcuts) => + shortcuts.commandList() + ? `Toggle username display in chat via the command palette (${shortcutText(shortcuts.commandList())})` + : "Toggle username display in chat via the command palette", "Run {highlight}docker run -it --rm ghcr.io/anomalyco/opencode{/highlight} for containerized use", "Use {highlight}/connect{/highlight} with OpenCode Zen for curated, tested models", "Commit your project's {highlight}AGENTS.md{/highlight} file to Git for team sharing", "Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs", - "Run {highlight}/help{/highlight} or {highlight}Ctrl+X H{/highlight} to show the help dialog", + (shortcuts) => `Use ${commandText("/help", shortcuts.helpShow())} to show the help dialog`, "Use {highlight}/rename{/highlight} to rename the current session", ...(process.platform === "win32" - ? ["Press {highlight}Ctrl+Z{/highlight} to undo changes in your prompt"] - : ["Press {highlight}Ctrl+Z{/highlight} to suspend the terminal and return to your shell"]), + ? ([(shortcuts) => press(shortcuts.inputUndo(), "to undo changes in your prompt")] satisfies Tip[]) + : ([ + (shortcuts) => press(shortcuts.terminalSuspend(), "to suspend the terminal and return to your shell"), + ] satisfies Tip[])), ] diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/home/tips.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/home/tips.tsx index 69071b1f7c..598366c08c 100644 --- a/packages/opencode/src/cli/cmd/tui/feature-plugins/home/tips.tsx +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/home/tips.tsx @@ -24,9 +24,9 @@ function View(props: { api: TuiPluginApi; hidden: boolean; show: boolean; connec })) return ( - + - + ) diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/notifications.ts b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/notifications.ts new file mode 100644 index 0000000000..cda815f5fc --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/notifications.ts @@ -0,0 +1,94 @@ +import type { Event } from "@opencode-ai/sdk/v2" +import type { TuiAttentionSoundName, TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/tui" +import type { InternalTuiPlugin } from "../../plugin/internal" + +const id = "internal:notifications" + +type SessionError = Extract["properties"]["error"] + +function notify(api: TuiPluginApi, sessionID: string | undefined, message: string, sound: TuiAttentionSoundName) { + const session = sessionID ? api.state.session.get(sessionID) : undefined + const isSubagent = session?.parentID !== undefined + void api.attention.notify({ + title: session?.title, + message, + notification: isSubagent ? false : { when: "blurred" }, + sound: { name: sound, when: "always" }, + }) +} + +function sessionErrorMessage(error: SessionError) { + if (error?.name === "MessageAbortedError") return "Session aborted" + const data = error?.data + if (data && typeof data === "object" && "message" in data && data.message === "SSE read timed out") { + return "Model stopped responding" + } + return "Session error" +} + +const tui: TuiPlugin = async (api) => { + const active = new Set() + const errored = new Set() + const questions = new Set() + const permissions = new Set() + + api.event.on("question.asked", (event) => { + if (questions.has(event.properties.id)) return + questions.add(event.properties.id) + notify(api, event.properties.sessionID, "Question needs input", "question") + }) + + api.event.on("question.replied", (event) => { + questions.delete(event.properties.requestID) + }) + + api.event.on("question.rejected", (event) => { + questions.delete(event.properties.requestID) + }) + + api.event.on("permission.asked", (event) => { + if (permissions.has(event.properties.id)) return + permissions.add(event.properties.id) + notify(api, event.properties.sessionID, "Permission needs input", "permission") + }) + + api.event.on("permission.replied", (event) => { + permissions.delete(event.properties.requestID) + }) + + api.event.on("session.status", (event) => { + const sessionID = event.properties.sessionID + if (event.properties.status.type === "busy" || event.properties.status.type === "retry") { + active.add(sessionID) + errored.delete(sessionID) + return + } + + if (event.properties.status.type !== "idle") return + if (!active.has(sessionID)) return + active.delete(sessionID) + + if (errored.has(sessionID)) { + errored.delete(sessionID) + return + } + + const session = api.state.session.get(sessionID) + notify(api, sessionID, "Session done", session?.parentID ? "subagent_done" : "done") + }) + + api.event.on("session.error", (event) => { + const sessionID = event.properties.sessionID + if (!sessionID) return + if (!active.has(sessionID)) return + errored.add(sessionID) + notify(api, sessionID, sessionErrorMessage(event.properties.error), "error") + }) +} + +const plugin: InternalTuiPlugin = { + id, + tui, +} + +export default plugin diff --git a/packages/opencode/src/cli/cmd/tui/plugin/api.tsx b/packages/opencode/src/cli/cmd/tui/plugin/api.tsx index 8958a92853..05bfa31d14 100644 --- a/packages/opencode/src/cli/cmd/tui/plugin/api.tsx +++ b/packages/opencode/src/cli/cmd/tui/plugin/api.tsx @@ -40,6 +40,7 @@ type Input = { theme: ReturnType toast: ReturnType renderer: TuiPluginApi["renderer"] + attention: TuiPluginApi["attention"] } function routeRegister(routes: RouteMap, list: TuiRouteDefinition[], bump: () => void) { @@ -206,6 +207,7 @@ export function createTuiApi(input: Input): TuiPluginApi { } return { app: appApi(), + attention: input.attention, // Keep deprecated `api.command` working for v1 plugins; remove in v2. command: createCommandShim(input.keymap, input.dialog, input.tuiConfig.keybinds), keys: { diff --git a/packages/opencode/src/cli/cmd/tui/plugin/internal.ts b/packages/opencode/src/cli/cmd/tui/plugin/internal.ts index 664b5c1ac1..5e0aec3ba1 100644 --- a/packages/opencode/src/cli/cmd/tui/plugin/internal.ts +++ b/packages/opencode/src/cli/cmd/tui/plugin/internal.ts @@ -7,10 +7,11 @@ import SidebarTodo from "../feature-plugins/sidebar/todo" import SidebarFiles from "../feature-plugins/sidebar/files" import SidebarFooter from "../feature-plugins/sidebar/footer" import PluginManager from "../feature-plugins/system/plugins" +import Notifications from "../feature-plugins/system/notifications" import SessionV2Debug from "../feature-plugins/system/session-v2" import WhichKey from "../feature-plugins/system/which-key" import type { TuiPlugin, TuiPluginModule } from "@opencode-ai/plugin/tui" -import { Flag } from "@opencode-ai/core/flag/flag" +import type { RuntimeFlags } from "@/effect/runtime-flags" export type InternalTuiPlugin = Omit & { id: string @@ -18,16 +19,19 @@ export type InternalTuiPlugin = Omit & { enabled?: boolean } -export const INTERNAL_TUI_PLUGINS: InternalTuiPlugin[] = [ - HomeFooter, - HomeTips, - SidebarContext, - SidebarMcp, - SidebarLsp, - SidebarTodo, - SidebarFiles, - SidebarFooter, - PluginManager, - WhichKey, - ...(Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM ? [SessionV2Debug] : []), -] +export function internalTuiPlugins(flags: Pick): InternalTuiPlugin[] { + return [ + HomeFooter, + HomeTips, + SidebarContext, + SidebarMcp, + SidebarLsp, + SidebarTodo, + SidebarFiles, + SidebarFooter, + Notifications, + PluginManager, + WhichKey, + ...(flags.experimentalEventSystem ? [SessionV2Debug] : []), + ] +} diff --git a/packages/opencode/src/cli/cmd/tui/plugin/runtime.ts b/packages/opencode/src/cli/cmd/tui/plugin/runtime.ts index dad4595e7f..420826ad0c 100644 --- a/packages/opencode/src/cli/cmd/tui/plugin/runtime.ts +++ b/packages/opencode/src/cli/cmd/tui/plugin/runtime.ts @@ -17,6 +17,7 @@ import { TuiConfig } from "@/cli/cmd/tui/config/tui" import * as Log from "@opencode-ai/core/util/log" import { errorData, errorMessage } from "@/util/error" import { isRecord } from "@/util/record" +import { resolveAttentionSoundPaths } from "../config/tui-schema" import { readPackageThemes, readPluginId, @@ -34,11 +35,13 @@ import { Filesystem } from "@/util/filesystem" import { Process } from "@/util/process" import { Flock } from "@opencode-ai/core/util/flock" import { Flag } from "@opencode-ai/core/flag/flag" -import { INTERNAL_TUI_PLUGINS, type InternalTuiPlugin } from "./internal" +import { internalTuiPlugins, type InternalTuiPlugin } from "./internal" import { setupSlots, Slot as View } from "./slots" import type { HostPluginApi, HostSlots } from "./slots" import { ConfigPlugin } from "@/config/plugin" import { createCommandShim } from "./command-shim" +import { RuntimeFlags } from "@/effect/runtime-flags" +import { Effect } from "effect" ensureRuntimePluginSupport({ additional: keymapRuntimeModules }) @@ -51,7 +54,7 @@ type PluginLoad = { id: string module: TuiPluginModule origin: ConfigPlugin.Origin - theme_root: string + plugin_root: string theme_files: string[] } @@ -106,6 +109,7 @@ const ScopedKeymapMethods = new Set([ type RuntimeState = { directory: string api: Api + dispose?: () => void slots: HostSlots plugins: PluginEntry[] plugins_by_id: Map @@ -156,6 +160,37 @@ function createScopedKeymap(keymap: TuiPluginApi["keymap"], scope: PluginScope): }) } +function createScopedAttention( + attention: TuiPluginApi["attention"], + scope: PluginScope, + root: string, +): TuiPluginApi["attention"] { + return { + notify(input) { + return attention.notify(input) + }, + soundboard: { + registerPack(pack) { + return scope.track( + attention.soundboard.registerPack({ + ...pack, + sounds: resolveAttentionSoundPaths(root, pack.sounds, { trim: true }), + }), + ) + }, + activate(id, options) { + return attention.soundboard.activate(id, options) + }, + current() { + return attention.soundboard.current() + }, + list() { + return attention.soundboard.list() + }, + }, + } +} + type CleanupResult = { type: "ok" } | { type: "error"; error: unknown } | { type: "timeout" } function runCleanup(fn: () => unknown, ms: number): Promise { @@ -204,8 +239,7 @@ function createThemeInstaller( plugin: PluginEntry, ): TuiTheme["install"] { return async (file) => { - const raw = file.startsWith("file://") ? fileURLToPath(file) : file - const src = path.isAbsolute(raw) ? raw : path.resolve(root, raw) + const src = Filesystem.resolveFilePath(root, file) const name = path.basename(src, path.extname(src)) const source_dir = path.dirname(meta.source) const local_dir = @@ -330,7 +364,7 @@ function loadInternalPlugin(item: InternalTuiPlugin): PluginLoad { scope: "global", source: target, }, - theme_root: process.cwd(), + plugin_root: process.cwd(), theme_files: [], } } @@ -352,7 +386,7 @@ async function readThemeFiles(spec: string, pkg?: PluginPackage) { async function syncPluginThemes(plugin: PluginEntry) { if (!plugin.load.theme_files.length) return if (plugin.meta.state === "same") return - const install = createThemeInstaller(plugin.load.origin, plugin.load.theme_root, plugin.load.spec, plugin) + const install = createThemeInstaller(plugin.load.origin, plugin.load.plugin_root, plugin.load.spec, plugin) for (const file of plugin.load.theme_files) { await install(file).catch((error) => { warn("failed to sync tui plugin oc-themes", { path: plugin.load.spec, id: plugin.id, theme: file, error }) @@ -552,7 +586,7 @@ function pluginApi(runtime: RuntimeState, plugin: PluginEntry, scope: PluginScop } const theme: TuiPluginApi["theme"] = Object.assign(Object.create(api.theme), { - install: createThemeInstaller(load.origin, load.theme_root, load.spec, plugin), + install: createThemeInstaller(load.origin, load.plugin_root, load.spec, plugin), }) const event: TuiPluginApi["event"] = { @@ -576,6 +610,7 @@ function pluginApi(runtime: RuntimeState, plugin: PluginEntry, scope: PluginScop return { app: api.app, + attention: createScopedAttention(api.attention, scope, load.plugin_root), // Keep deprecated `api.command` working for v1 plugins; remove in v2. command: createCommandShim(keymap, api.ui.dialog, api.tuiConfig.keybinds), keys: api.keys, @@ -682,7 +717,7 @@ async function resolveExternalPlugins(list: ConfigPlugin.Origin[], wait: () => P id, module: mod, origin, - theme_root: loaded.pkg?.dir ?? resolveRoot(loaded.target), + plugin_root: loaded.pkg?.dir ?? resolveRoot(loaded.target), theme_files, } }, @@ -709,7 +744,7 @@ async function resolveExternalPlugins(list: ConfigPlugin.Origin[], wait: () => P id, module: EMPTY_TUI, origin, - theme_root: loaded.pkg?.dir ?? resolveRoot(loaded.target), + plugin_root: loaded.pkg?.dir ?? resolveRoot(loaded.target), theme_files, } }, @@ -967,7 +1002,7 @@ let loaded: Promise | undefined let runtime: RuntimeState | undefined export const Slot = View -export async function init(input: { api: HostPluginApi; config: TuiConfig.Resolved }) { +export async function init(input: { api: HostPluginApi; config: TuiConfig.Resolved; dispose?: () => void }) { const cwd = process.cwd() if (loaded) { if (dir !== cwd) { @@ -1014,15 +1049,17 @@ export async function dispose() { for (const plugin of queue) { await deactivatePluginEntry(state, plugin, false) } + state.dispose?.() } -async function load(input: { api: Api; config: TuiConfig.Resolved }) { +async function load(input: { api: Api; config: TuiConfig.Resolved; dispose?: () => void }) { const { api, config } = input const cwd = process.cwd() const slots = setupSlots(api) const next: RuntimeState = { directory: cwd, api, + dispose: input.dispose, slots, plugins: [], plugins_by_id: new Map(), @@ -1035,7 +1072,10 @@ async function load(input: { api: Api; config: TuiConfig.Resolved }) { log.info("skipping external tui plugins in pure mode", { count: config.plugin_origins.length }) } - for (const item of INTERNAL_TUI_PLUGINS) { + const flags = await Effect.runPromise( + RuntimeFlags.Service.use((flags) => Effect.succeed(flags)).pipe(Effect.provide(RuntimeFlags.defaultLayer)), + ) + for (const item of internalTuiPlugins(flags)) { log.info("loading internal tui plugin", { id: item.id }) const entry = loadInternalPlugin(item) const meta = createMeta(entry.source, entry.spec, entry.target, undefined, entry.id) 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 95d1b072f1..b5e8e10283 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -64,7 +64,6 @@ import { DialogForkFromTimeline } from "./dialog-fork-from-timeline" import { DialogSessionRename } from "../../component/dialog-session-rename" import { Sidebar } from "./sidebar" import { SubagentFooter } from "./subagent-footer.tsx" -import { Flag } from "@opencode-ai/core/flag/flag" import { LANGUAGE_EXTENSIONS } from "@/lsp/language" import parsers from "../../../../../../parsers-config.ts" import * as Clipboard from "../../util/clipboard" @@ -1529,29 +1528,15 @@ function TextPart(props: { last: boolean; part: TextPart; message: AssistantMess return ( - - - - - - - - + ) diff --git a/packages/opencode/src/cli/cmd/tui/util/audio.ts b/packages/opencode/src/cli/cmd/tui/util/audio.ts new file mode 100644 index 0000000000..7d7c3d5a42 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/util/audio.ts @@ -0,0 +1,58 @@ +import { Audio, type AudioErrorContext, type AudioPlayOptions, type AudioSound, type AudioVoice } from "@opentui/core" +import * as Log from "@opencode-ai/core/util/log" + +const log = Log.create({ service: "tui.audio" }) + +let audio: Audio | null | undefined +const sounds = new Map>() + +function getAudio() { + if (audio !== undefined) return audio + try { + const next = Audio.create({ autoStart: false }) + next.on("error", (error: Error, context: AudioErrorContext) => { + log.debug("tui audio error", { error, context }) + }) + audio = next + return next + } catch (error) { + log.debug("failed to create tui audio", { error }) + audio = null + return null + } +} + +export function loadSoundFile(file: string) { + const current = getAudio() + if (!current) return Promise.resolve(null) + const cached = sounds.get(file) + if (cached) return cached + const task = Bun.file(file) + .bytes() + .then((bytes) => current.loadSound(bytes)) + .catch((error) => { + log.debug("failed to load tui sound", { file, error }) + return null + }) + sounds.set(file, task) + return task +} + +export function play(sound: AudioSound, options?: AudioPlayOptions) { + const current = getAudio() + if (!current) return null + if (!current.isStarted() && !current.start()) return null + return current.play(sound, options) +} + +export function stopVoice(voice: AudioVoice) { + return audio?.stopVoice(voice) ?? false +} + +export function dispose() { + audio?.dispose() + audio = undefined + sounds.clear() +} + +export * as TuiAudio from "./audio" diff --git a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts index 3a9996902d..be3cec14c6 100644 --- a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts +++ b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts @@ -3,9 +3,21 @@ import { lazy } from "../../../../util/lazy.js" import { tmpdir } from "os" import path from "path" import fs from "fs/promises" +import { Effect } from "effect" +import { ChildProcess } from "effect/unstable/process" +import { AppProcess } from "@opencode-ai/core/process" import * as Filesystem from "../../../../util/filesystem" import * as Process from "../../../../util/process" +const writeWithStdin = (cmd: string[], text: string): Promise => + Effect.runPromise( + AppProcess.Service.use((svc) => svc.run(ChildProcess.make(cmd[0]!, cmd.slice(1)), { stdin: text })).pipe( + Effect.provide(AppProcess.defaultLayer), + Effect.catch(() => Effect.void), + Effect.asVoid, + ), + ).catch(() => undefined) + // Lazy load which and clipboardy to avoid expensive execa/which/isexe chain at startup const getWhich = lazy(async () => { const { which } = await import("../../../../util/which") @@ -125,49 +137,23 @@ const getCopyMethod = lazy(async () => { if (os === "linux") { if (process.env["WAYLAND_DISPLAY"] && which("wl-copy")) { console.log("clipboard: using wl-copy") - return async (text: string) => { - const proc = Process.spawn(["wl-copy"], { stdin: "pipe", stdout: "ignore", stderr: "ignore" }) - if (!proc.stdin) return - proc.stdin.write(text) - proc.stdin.end() - await proc.exited.catch(() => {}) - } + return (text: string) => writeWithStdin(["wl-copy"], text) } if (which("xclip")) { console.log("clipboard: using xclip") - return async (text: string) => { - const proc = Process.spawn(["xclip", "-selection", "clipboard"], { - stdin: "pipe", - stdout: "ignore", - stderr: "ignore", - }) - if (!proc.stdin) return - proc.stdin.write(text) - proc.stdin.end() - await proc.exited.catch(() => {}) - } + return (text: string) => writeWithStdin(["xclip", "-selection", "clipboard"], text) } if (which("xsel")) { console.log("clipboard: using xsel") - return async (text: string) => { - const proc = Process.spawn(["xsel", "--clipboard", "--input"], { - stdin: "pipe", - stdout: "ignore", - stderr: "ignore", - }) - if (!proc.stdin) return - proc.stdin.write(text) - proc.stdin.end() - await proc.exited.catch(() => {}) - } + return (text: string) => writeWithStdin(["xsel", "--clipboard", "--input"], text) } } if (os === "win32") { console.log("clipboard: using powershell") - return async (text: string) => { + return (text: string) => // Pipe via stdin to avoid PowerShell string interpolation ($env:FOO, $(), etc.) - const proc = Process.spawn( + writeWithStdin( [ "powershell.exe", "-NonInteractive", @@ -175,18 +161,8 @@ const getCopyMethod = lazy(async () => { "-Command", "[Console]::InputEncoding = [System.Text.Encoding]::UTF8; Set-Clipboard -Value ([Console]::In.ReadToEnd())", ], - { - stdin: "pipe", - stdout: "ignore", - stderr: "ignore", - }, + text, ) - - if (!proc.stdin) return - proc.stdin.write(text) - proc.stdin.end() - await proc.exited.catch(() => {}) - } } console.log("clipboard: no native support") diff --git a/packages/opencode/src/cli/cmd/tui/util/sound.ts b/packages/opencode/src/cli/cmd/tui/util/sound.ts deleted file mode 100644 index df8b4dc2d6..0000000000 --- a/packages/opencode/src/cli/cmd/tui/util/sound.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { Player } from "cli-sound" -import { mkdirSync } from "node:fs" -import { tmpdir } from "node:os" -import { basename, join } from "node:path" -import { Process } from "@/util/process" -import { which } from "@/util/which" -import pulseA from "../asset/pulse-a.wav" with { type: "file" } -import pulseB from "../asset/pulse-b.wav" with { type: "file" } -import pulseC from "../asset/pulse-c.wav" with { type: "file" } -import charge from "../asset/charge.wav" with { type: "file" } - -const FILE = [pulseA, pulseB, pulseC] - -const HUM = charge -const DIR = join(tmpdir(), "opencode-sfx") - -const LIST = [ - "ffplay", - "mpv", - "mpg123", - "mpg321", - "mplayer", - "afplay", - "play", - "omxplayer", - "aplay", - "cmdmp3", - "cvlc", - "powershell.exe", -] as const - -type Kind = (typeof LIST)[number] - -function args(kind: Kind, file: string, volume: number) { - if (kind === "ffplay") return [kind, "-autoexit", "-nodisp", "-af", `volume=${volume}`, file] - if (kind === "mpv") - return [kind, "--no-video", "--audio-display=no", "--volume", String(Math.round(volume * 100)), file] - if (kind === "mpg123" || kind === "mpg321") return [kind, "-g", String(Math.round(volume * 100)), file] - if (kind === "mplayer") return [kind, "-vo", "null", "-volume", String(Math.round(volume * 100)), file] - if (kind === "afplay" || kind === "omxplayer" || kind === "aplay" || kind === "cmdmp3") return [kind, file] - if (kind === "play") return [kind, "-v", String(volume), file] - if (kind === "cvlc") return [kind, `--gain=${volume}`, "--play-and-exit", file] - return [kind, "-c", `(New-Object Media.SoundPlayer '${file.replace(/'/g, "''")}').PlaySync()`] -} - -let item: Player | null | undefined -let kind: Kind | null | undefined -let proc: Process.Child | undefined -let tail: ReturnType | undefined -let cache: Promise<{ hum: string; pulse: string[] }> | undefined -let seq = 0 -let shot = 0 - -function load() { - if (item !== undefined) return item - try { - item = new Player({ volume: 0.35 }) - } catch { - item = null - } - return item -} - -async function file(path: string) { - mkdirSync(DIR, { recursive: true }) - const next = join(DIR, basename(path)) - const out = Bun.file(next) - if (await out.exists()) return next - await Bun.write(out, Bun.file(path)) - return next -} - -function asset() { - cache ??= Promise.all([file(HUM), Promise.all(FILE.map(file))]).then(([hum, pulse]) => ({ hum, pulse })) - return cache -} - -function pick() { - if (kind !== undefined) return kind - kind = LIST.find((item) => which(item)) ?? null - return kind -} - -function run(file: string, volume: number) { - const kind = pick() - if (!kind) return - return Process.spawn(args(kind, file, volume), { - stdin: "ignore", - stdout: "ignore", - stderr: "ignore", - }) -} - -function clear() { - if (!tail) return - clearTimeout(tail) - tail = undefined -} - -function play(file: string, volume: number) { - const item = load() - if (!item) return run(file, volume)?.exited - return item.play(file, { volume }).catch(() => run(file, volume)?.exited) -} - -export function start() { - stop() - const id = ++seq - void asset().then(({ hum }) => { - if (id !== seq) return - const next = run(hum, 0.24) - if (!next) return - proc = next - void next.exited.then( - () => { - if (id !== seq) return - if (proc === next) proc = undefined - }, - () => { - if (id !== seq) return - if (proc === next) proc = undefined - }, - ) - }) -} - -export function stop(delay = 0) { - seq++ - clear() - if (!proc) return - const next = proc - if (delay <= 0) { - proc = undefined - void Process.stop(next).catch(() => undefined) - return - } - tail = setTimeout(() => { - tail = undefined - if (proc === next) proc = undefined - void Process.stop(next).catch(() => undefined) - }, delay) -} - -export function pulse(scale = 1) { - stop(140) - const index = shot++ % FILE.length - void asset() - .then(({ pulse }) => play(pulse[index], 0.26 + 0.14 * scale)) - .catch(() => undefined) -} - -export function dispose() { - stop() -} - -export * as Sound from "./sound" diff --git a/packages/opencode/src/cli/error.ts b/packages/opencode/src/cli/error.ts index 628aa95696..2bb0cb51fd 100644 --- a/packages/opencode/src/cli/error.ts +++ b/packages/opencode/src/cli/error.ts @@ -5,13 +5,41 @@ interface ErrorLike { name?: string _tag?: string message?: string - data?: Record + data?: Record +} + +type ConfigIssue = { message: string; path: string[] } + +function isRecord(input: unknown): input is Record { + return typeof input === "object" && input !== null } function isTaggedError(error: unknown, tag: string): boolean { - return ( - typeof error === "object" && error !== null && "_tag" in error && (error as Record)._tag === tag - ) + return isRecord(error) && error._tag === tag +} + +function configData(input: unknown, tag: string): Record | undefined { + if (!isRecord(input)) return undefined + if (input.name === tag && isRecord(input.data)) return input.data + if (input._tag === tag) return input + return undefined +} + +function stringField(input: Record, key: string): string | undefined { + return typeof input[key] === "string" ? input[key] : undefined +} + +function configIssues(input: Record): ConfigIssue[] { + return Array.isArray(input.issues) + ? input.issues.filter((issue): issue is ConfigIssue => { + if (!isRecord(issue)) return false + return ( + typeof issue.message === "string" && + Array.isArray(issue.path) && + issue.path.every((x) => typeof x === "string") + ) + }) + : [] } export function FormatError(input: unknown) { @@ -35,7 +63,7 @@ export function FormatError(input: unknown) { // ProviderModelNotFoundError: { providerID: string, modelID: string, suggestions?: string[] } if (NamedError.hasName(input, "ProviderModelNotFoundError")) { const data = (input as ErrorLike).data - const suggestions: string[] = Array.isArray(data?.suggestions) ? data.suggestions : [] + const suggestions = Array.isArray(data?.suggestions) ? data.suggestions.filter((x) => typeof x === "string") : [] return [ `Model not found: ${data?.providerID}/${data?.modelID}`, ...(suggestions.length ? ["Did you mean: " + suggestions.join(", ")] : []), @@ -50,36 +78,38 @@ export function FormatError(input: unknown) { } // ConfigJsonError: { path: string, message?: string } - if (NamedError.hasName(input, "ConfigJsonError")) { - const data = (input as ErrorLike).data - return `Config file at ${data?.path} is not valid JSON(C)` + (data?.message ? `: ${data.message}` : "") + const configJson = configData(input, "ConfigJsonError") + if (configJson) { + const message = stringField(configJson, "message") + return `Config file at ${stringField(configJson, "path")} is not valid JSON(C)` + (message ? `: ${message}` : "") } // ConfigDirectoryTypoError: { dir: string, path: string, suggestion: string } - if (NamedError.hasName(input, "ConfigDirectoryTypoError")) { - const data = (input as ErrorLike).data - return `Directory "${data?.dir}" in ${data?.path} is not valid. Rename the directory to "${data?.suggestion}" or remove it. This is a common typo.` + const configDirectoryTypo = configData(input, "ConfigDirectoryTypoError") + if (configDirectoryTypo) { + return `Directory "${stringField(configDirectoryTypo, "dir")}" in ${stringField(configDirectoryTypo, "path")} is not valid. Rename the directory to "${stringField(configDirectoryTypo, "suggestion")}" or remove it. This is a common typo.` } // ConfigFrontmatterError: { message: string } - if (NamedError.hasName(input, "ConfigFrontmatterError")) { - return (input as ErrorLike).data?.message ?? "" + const configFrontmatter = configData(input, "ConfigFrontmatterError") + if (configFrontmatter) { + return stringField(configFrontmatter, "message") ?? "" } // ConfigInvalidError: { path?: string, message?: string, issues?: Array<{ message: string, path: string[] }> } - if (NamedError.hasName(input, "ConfigInvalidError")) { - const data = (input as ErrorLike).data - const path = data?.path - const message = data?.message - const issues: Array<{ message: string; path: string[] }> = Array.isArray(data?.issues) ? data.issues : [] + const configInvalid = configData(input, "ConfigInvalidError") + if (configInvalid) { + const path = stringField(configInvalid, "path") + const message = stringField(configInvalid, "message") + const issues = configIssues(configInvalid) return [ `Configuration is invalid${path && path !== "config" ? ` at ${path}` : ""}` + (message ? `: ${message}` : ""), ...issues.map((issue) => "↳ " + issue.message + " " + issue.path.join(".")), ].join("\n") } - // UICancelledError: void (no data) - if (NamedError.hasName(input, "UICancelledError")) { + // UICancelledError: user cancelled an interactive CLI prompt + if (isTaggedError(input, "UICancelledError") || NamedError.hasName(input, "UICancelledError")) { return "" } } diff --git a/packages/opencode/src/cli/ui.ts b/packages/opencode/src/cli/ui.ts index 7b4cf7f345..6ad6495cf1 100644 --- a/packages/opencode/src/cli/ui.ts +++ b/packages/opencode/src/cli/ui.ts @@ -1,6 +1,5 @@ -import z from "zod" import { EOL } from "os" -import { NamedError } from "@opencode-ai/core/util/error" +import { Schema } from "effect" import { logo as glyphs } from "./logo" const wordmark = [ @@ -10,7 +9,7 @@ const wordmark = [ `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`, ] -export const CancelledError = NamedError.create("UICancelledError", z.void()) +export class CancelledError extends Schema.TaggedErrorClass()("UICancelledError", {}) {} export const Style = { TEXT_HIGHLIGHT: "\x1b[96m", diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index e44405f42e..545e48e64d 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -2,7 +2,6 @@ import * as Log from "@opencode-ai/core/util/log" import path from "path" import { pathToFileURL } from "url" import os from "os" -import z from "zod" import { mergeDeep } from "remeda" import { Global } from "@opencode-ai/core/global" import fsNode from "fs/promises" @@ -262,10 +261,10 @@ export const Info = Schema.Struct({ }), tail_turns: Schema.optional(NonNegativeInt).annotate({ description: - "Number of recent user turns, including their following assistant/tool responses, to serialize into the compaction summary (default: 2)", + "Number of recent user turns, including their following assistant/tool responses, to keep verbatim during compaction (default: 2)", }), preserve_recent_tokens: Schema.optional(NonNegativeInt).annotate({ - description: "Maximum number of tokens from recent turns to serialize into the compaction summary", + description: "Maximum number of tokens from recent turns to preserve verbatim after compaction", }), reserved: Schema.optional(NonNegativeInt).annotate({ description: "Token buffer for compaction. Leaves enough window to avoid overflow during compaction.", @@ -357,14 +356,11 @@ function writableGlobal(info: Info) { return next } -export const ConfigDirectoryTypoError = NamedError.create( - "ConfigDirectoryTypoError", - z.object({ - path: z.string(), - dir: z.string(), - suggestion: z.string(), - }), -) +export const ConfigDirectoryTypoError = NamedError.create("ConfigDirectoryTypoError", { + path: Schema.String, + dir: Schema.String, + suggestion: Schema.String, +}) export const layer = Layer.effect( Service, diff --git a/packages/opencode/src/config/error.ts b/packages/opencode/src/config/error.ts index c43598048a..17d74fc1c3 100644 --- a/packages/opencode/src/config/error.ts +++ b/packages/opencode/src/config/error.ts @@ -1,21 +1,23 @@ export * as ConfigError from "./error" -import z from "zod" import { NamedError } from "@opencode-ai/core/util/error" +import { Schema } from "effect" -export const JsonError = NamedError.create( - "ConfigJsonError", - z.object({ - path: z.string(), - message: z.string().optional(), +const Issue = Schema.StructWithRest( + Schema.Struct({ + message: Schema.String, + path: Schema.Array(Schema.String), }), + [Schema.Record(Schema.String, Schema.Unknown)], ) -export const InvalidError = NamedError.create( - "ConfigInvalidError", - z.object({ - path: z.string(), - issues: z.custom().optional(), - message: z.string().optional(), - }), -) +export const JsonError = NamedError.create("ConfigJsonError", { + path: Schema.String, + message: Schema.optional(Schema.String), +}) + +export const InvalidError = NamedError.create("ConfigInvalidError", { + path: Schema.String, + issues: Schema.optional(Schema.Array(Issue)), + message: Schema.optional(Schema.String), +}) diff --git a/packages/opencode/src/config/markdown.ts b/packages/opencode/src/config/markdown.ts index 390f7f8b06..820f4bf642 100644 --- a/packages/opencode/src/config/markdown.ts +++ b/packages/opencode/src/config/markdown.ts @@ -1,6 +1,6 @@ import { NamedError } from "@opencode-ai/core/util/error" import matter from "gray-matter" -import { z } from "zod" +import { Schema } from "effect" import { Filesystem } from "@/util/filesystem" export const FILE_REGEX = /(?>( keys: extra, path: [], message: `Unrecognized key${extra.length === 1 ? "" : "s"}: ${extra.join(", ")}`, - } as z.core.$ZodIssue, + }, ], }) } @@ -61,8 +60,12 @@ export function schema>( { path: source, issues: EffectSchema.isSchemaError(error) - ? (SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues as z.core.$ZodIssue[]) - : ([{ code: "custom", message: String(error), path: [] }] as z.core.$ZodIssue[]), + ? SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues.map((issue) => ({ + ...issue, + message: issue.message, + path: issue.path?.map(String) ?? [], + })) + : [{ message: String(error), path: [] }], }, { cause: error }, ) diff --git a/packages/opencode/src/control-plane/workspace.ts b/packages/opencode/src/control-plane/workspace.ts index e7e65f8901..4a21e2e65e 100644 --- a/packages/opencode/src/control-plane/workspace.ts +++ b/packages/opencode/src/control-plane/workspace.ts @@ -10,8 +10,8 @@ import { GlobalBus } from "@/bus/global" import { Auth } from "@/auth" import { SyncEvent } from "@/sync" import { EventSequenceTable, EventTable } from "@/sync/event.sql" -import { Flag } from "@opencode-ai/core/flag/flag" import * as Log from "@opencode-ai/core/util/log" +import { RuntimeFlags } from "@/effect/runtime-flags" import { Filesystem } from "@/util/filesystem" import { ProjectID } from "@/project/schema" import { Slug } from "@opencode-ai/core/util/slug" @@ -175,6 +175,7 @@ export const layer = Layer.effect( const http = yield* HttpClient.HttpClient const sync = yield* SyncEvent.Service const vcs = yield* Vcs.Service + const flags = yield* RuntimeFlags.Service const connections = new Map() const syncFibers = yield* FiberMap.make() @@ -482,7 +483,7 @@ export const layer = Layer.effect( }) const startSync = Effect.fn("Workspace.startSync")(function* (space: Info) { - if (!Flag.OPENCODE_EXPERIMENTAL_WORKSPACES) return + if (!flags.experimentalWorkspaces) return const adapter = getAdapter(space.projectID, space.type) const target = yield* EffectBridge.fromPromise(() => adapter.target(space)).pipe( @@ -1040,6 +1041,7 @@ export const defaultLayer = layer.pipe( Layer.provide(Project.defaultLayer), Layer.provide(Vcs.defaultLayer), Layer.provide(FetchHttpClient.layer), + Layer.provide(RuntimeFlags.defaultLayer), ) const TIMEOUT = 5000 diff --git a/packages/opencode/src/data-migration.ts b/packages/opencode/src/data-migration.ts index 53e3196b7a..b6956032a4 100644 --- a/packages/opencode/src/data-migration.ts +++ b/packages/opencode/src/data-migration.ts @@ -94,6 +94,7 @@ export const layer = Layer.effect( tokens_reasoning: value.tokens.reasoning, tokens_cache_read: value.tokens.cache.read, tokens_cache_write: value.tokens.cache.write, + time_updated: sql`${SessionTable.time_updated}`, }) .where(eq(SessionTable.id, sessionID)) .run() @@ -145,7 +146,9 @@ export const layer = Layer.effect( ) } }).pipe( - Effect.tapCause((cause) => Effect.logError("failed to run data migrations", { cause })), + Effect.tapCause((cause) => + Effect.logError("failed to run data migrations").pipe(Effect.annotateLogs("cause", cause)), + ), Effect.ignore, Effect.forkScoped, ) diff --git a/packages/opencode/src/effect/runner.ts b/packages/opencode/src/effect/runner.ts index 1e7d4c2966..5d7e8778d7 100644 --- a/packages/opencode/src/effect/runner.ts +++ b/packages/opencode/src/effect/runner.ts @@ -181,7 +181,7 @@ export const make = ( return [ Effect.gen(function* () { yield* Fiber.interrupt(st.run.fiber) - yield* Deferred.await(st.run.done).pipe(Effect.exit, Effect.asVoid) + yield* Deferred.fail(st.run.done, new Cancelled()).pipe(Effect.asVoid) yield* idleIfCurrent() }), { _tag: "Idle" } as const, diff --git a/packages/opencode/src/effect/runtime-flags.ts b/packages/opencode/src/effect/runtime-flags.ts new file mode 100644 index 0000000000..4d184c43b3 --- /dev/null +++ b/packages/opencode/src/effect/runtime-flags.ts @@ -0,0 +1,48 @@ +import { Config, ConfigProvider, Context, Effect, Layer } from "effect" +import { ConfigService } from "@/effect/config-service" + +const bool = (name: string) => Config.boolean(name).pipe(Config.withDefault(false)) +const experimental = bool("OPENCODE_EXPERIMENTAL") +const enabledByExperimental = (name: string) => + Config.all({ experimental, enabled: bool(name) }).pipe(Config.map((flags) => flags.experimental || flags.enabled)) + +export class Service extends ConfigService.Service()("@opencode/RuntimeFlags", { + pure: bool("OPENCODE_PURE"), + disableDefaultPlugins: bool("OPENCODE_DISABLE_DEFAULT_PLUGINS"), + enableExa: Config.all({ + experimental, + enabled: bool("OPENCODE_ENABLE_EXA"), + legacy: bool("OPENCODE_EXPERIMENTAL_EXA"), + }).pipe(Config.map((flags) => flags.experimental || flags.enabled || flags.legacy)), + enableParallel: Config.all({ + enabled: bool("OPENCODE_ENABLE_PARALLEL"), + legacy: bool("OPENCODE_EXPERIMENTAL_PARALLEL"), + }).pipe(Config.map((flags) => flags.enabled || flags.legacy)), + enableQuestionTool: bool("OPENCODE_ENABLE_QUESTION_TOOL"), + experimentalScout: enabledByExperimental("OPENCODE_EXPERIMENTAL_SCOUT"), + experimentalLspTool: enabledByExperimental("OPENCODE_EXPERIMENTAL_LSP_TOOL"), + experimentalPlanMode: enabledByExperimental("OPENCODE_EXPERIMENTAL_PLAN_MODE"), + experimentalEventSystem: enabledByExperimental("OPENCODE_EXPERIMENTAL_EVENT_SYSTEM"), + experimentalWorkspaces: enabledByExperimental("OPENCODE_EXPERIMENTAL_WORKSPACES"), + client: Config.string("OPENCODE_CLIENT").pipe(Config.withDefault("cli")), +}) {} + +export type Info = Context.Service.Shape + +const emptyConfigLayer = Service.defaultLayer.pipe( + Layer.provide(ConfigProvider.layer(ConfigProvider.fromUnknown({}))), + Layer.orDie, +) + +export const layer = (overrides: Partial = {}) => + Layer.effect( + Service, + Effect.gen(function* () { + const flags = yield* Service + return Service.of({ ...flags, ...overrides }) + }), + ).pipe(Layer.provide(emptyConfigLayer)) + +export const defaultLayer = Service.defaultLayer.pipe(Layer.orDie) + +export * as RuntimeFlags from "./runtime-flags" diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts index b6eb9dfd0e..d8365e0fa7 100644 --- a/packages/opencode/src/format/index.ts +++ b/packages/opencode/src/format/index.ts @@ -1,6 +1,6 @@ import { Effect, Layer, Context, Schema } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" -import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { ChildProcess } from "effect/unstable/process" +import { AppProcess } from "@opencode-ai/core/process" import { InstanceState } from "@/effect/instance-state" import path from "path" import { mergeDeep } from "remeda" @@ -29,7 +29,7 @@ export const layer = Layer.effect( Service, Effect.gen(function* () { const config = yield* Config.Service - const spawner = yield* ChildProcessSpawner.ChildProcessSpawner + const appProcess = yield* AppProcess.Service const state = yield* InstanceState.make( Effect.fn("Format.state")(function* (ctx) { @@ -81,8 +81,8 @@ export const layer = Layer.effect( log.info("running", { command: cmd }) const replaced = cmd.map((x) => x.replace("$FILE", filepath)) const dir = yield* InstanceState.directory - const code = yield* spawner - .spawn( + const result = yield* appProcess + .run( ChildProcess.make(replaced[0]!, replaced.slice(1), { cwd: dir, env: item.environment, @@ -93,21 +93,20 @@ export const layer = Layer.effect( }), ) .pipe( - Effect.flatMap((handle) => handle.exitCode), - Effect.scoped, - Effect.catch(() => + Effect.catch((error) => Effect.sync(() => { log.error("failed to format file", { error: "spawn failed", command: cmd, ...item.environment, file: filepath, + cause: error.message, }) - return ChildProcessSpawner.ExitCode(1) + return undefined }), ), ) - if (code !== 0) { + if (result && result.exitCode !== 0) { log.error("failed", { command: cmd, ...item.environment, @@ -198,9 +197,6 @@ export const layer = Layer.effect( }), ) -export const defaultLayer = layer.pipe( - Layer.provide(Config.defaultLayer), - Layer.provide(CrossSpawnSpawner.defaultLayer), -) +export const defaultLayer = layer.pipe(Layer.provide(Config.defaultLayer), Layer.provide(AppProcess.defaultLayer)) export * as Format from "." diff --git a/packages/opencode/src/git/index.ts b/packages/opencode/src/git/index.ts index 349bbad466..4c88edaea3 100644 --- a/packages/opencode/src/git/index.ts +++ b/packages/opencode/src/git/index.ts @@ -1,6 +1,6 @@ -import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { AppProcess } from "@opencode-ai/core/process" import { Effect, Layer, Context, Stream } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcess } from "effect/unstable/process" const cfg = [ "--no-optional-locks", @@ -102,49 +102,31 @@ export class Service extends Context.Service()("@opencode/Gi export const layer = Layer.effect( Service, Effect.gen(function* () { - const spawner = yield* ChildProcessSpawner.ChildProcessSpawner + const appProcess = yield* AppProcess.Service const encoder = new TextEncoder() const stdin = (text: string) => Stream.make(encoder.encode(text)) const run = Effect.fn("Git.run")( function* (args: string[], opts: Options) { - const proc = ChildProcess.make("git", [...cfg, ...args], { - cwd: opts.cwd, - env: opts.env, - extendEnv: true, - stdin: opts.stdin ?? "ignore", - stdout: "pipe", - stderr: "pipe", - }) - const handle = yield* spawner.spawn(proc) - const collect = (stream: typeof handle.stdout) => - Stream.runFold( - stream, - () => ({ chunks: [] as Uint8Array[], bytes: 0, truncated: false }), - (acc, chunk) => { - if (opts.maxOutputBytes === undefined) { - acc.chunks.push(chunk) - acc.bytes += chunk.length - return acc - } - - const remaining = opts.maxOutputBytes - acc.bytes - if (remaining > 0) acc.chunks.push(remaining >= chunk.length ? chunk : chunk.slice(0, remaining)) - acc.bytes += chunk.length - acc.truncated = acc.truncated || acc.bytes > opts.maxOutputBytes - return acc - }, - ).pipe(Effect.map((x) => ({ buffer: Buffer.concat(x.chunks), truncated: x.truncated }))) - const [stdout, stderr] = yield* Effect.all([collect(handle.stdout), collect(handle.stderr)], { concurrency: 2 }) + const result = yield* appProcess.run( + ChildProcess.make("git", [...cfg, ...args], { + cwd: opts.cwd, + env: opts.env, + extendEnv: true, + stdin: opts.stdin ?? "ignore", + stdout: "pipe", + stderr: "pipe", + }), + { maxOutputBytes: opts.maxOutputBytes }, + ) return { - exitCode: yield* handle.exitCode, - text: () => stdout.buffer.toString("utf8"), - stdout: stdout.buffer, - stderr: stderr.buffer, - truncated: stdout.truncated || stderr.truncated, + exitCode: result.exitCode, + text: () => result.stdout.toString("utf8"), + stdout: result.stdout, + stderr: result.stderr, + truncated: result.truncated, } satisfies Result }, - Effect.scoped, Effect.catch((err) => Effect.succeed(fail(err))), ) @@ -360,6 +342,6 @@ export const layer = Layer.effect( }), ) -export const defaultLayer = layer.pipe(Layer.provide(CrossSpawnSpawner.defaultLayer)) +export const defaultLayer = layer.pipe(Layer.provide(AppProcess.defaultLayer)) export * as Git from "." diff --git a/packages/opencode/src/ide/index.ts b/packages/opencode/src/ide/index.ts index 2df293f163..a31c5bd057 100644 --- a/packages/opencode/src/ide/index.ts +++ b/packages/opencode/src/ide/index.ts @@ -1,5 +1,4 @@ import { BusEvent } from "@/bus/bus-event" -import z from "zod" import { Schema } from "effect" import { NamedError } from "@opencode-ai/core/util/error" import * as Log from "@opencode-ai/core/util/log" @@ -24,14 +23,11 @@ export const Event = { ), } -export const AlreadyInstalledError = NamedError.create("AlreadyInstalledError", z.object({})) +export const AlreadyInstalledError = NamedError.create("AlreadyInstalledError", {}) -export const InstallFailedError = NamedError.create( - "InstallFailedError", - z.object({ - stderr: z.string(), - }), -) +export const InstallFailedError = NamedError.create("InstallFailedError", { + stderr: Schema.String, +}) export function ide() { if (process.env["TERM_PROGRAM"] === "vscode") { diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index 4c8e447041..d20f29dd4d 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -39,6 +39,7 @@ import { PluginCommand } from "./cli/cmd/plug" import { Heap } from "./cli/heap" import { drizzle } from "drizzle-orm/bun-sqlite" import { ensureProcessMetadata } from "@opencode-ai/core/util/opencode-process" +import { isRecord } from "@/util/record" const processMetadata = ensureProcessMetadata("main") @@ -203,13 +204,6 @@ try { } } catch (e) { let data: Record = {} - if (e instanceof NamedError) { - const obj = e.toObject() - Object.assign(data, { - ...obj.data, - }) - } - if (e instanceof Error) { Object.assign(data, { name: e.name, @@ -219,6 +213,16 @@ try { }) } + if (e instanceof NamedError) { + const obj = e.toObject() + if (isRecord(obj.data)) { + for (const [key, value] of Object.entries(obj.data)) { + if (key === "name" || key === "stack" || key === "cause") continue + data[key] = value + } + } + } + if (e instanceof ResolveMessage) { Object.assign(data, { name: e.name, diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index e8c4342768..cc0b06e8e4 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -1,8 +1,8 @@ import { Effect, Layer, Schema, Context, Stream } from "effect" import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" -import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { withTransientReadRetry } from "@/util/effect-http-client" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcess } from "effect/unstable/process" +import { AppProcess } from "@opencode-ai/core/process" import path from "path" import { BusEvent } from "@/bus/bus-event" import { Flag } from "@opencode-ai/core/flag/flag" @@ -85,246 +85,235 @@ export interface Interface { export class Service extends Context.Service()("@opencode/Installation") {} -export const layer: Layer.Layer = - Layer.effect( - Service, - Effect.gen(function* () { - const http = yield* HttpClient.HttpClient - const httpOk = HttpClient.filterStatusOk(withTransientReadRetry(http)) - const spawner = yield* ChildProcessSpawner.ChildProcessSpawner +export const layer: Layer.Layer = Layer.effect( + Service, + Effect.gen(function* () { + const http = yield* HttpClient.HttpClient + const httpOk = HttpClient.filterStatusOk(withTransientReadRetry(http)) + const appProcess = yield* AppProcess.Service - const text = Effect.fnUntraced( - function* (cmd: string[], opts?: { cwd?: string; env?: Record }) { - const proc = ChildProcess.make(cmd[0], cmd.slice(1), { + const text = Effect.fnUntraced( + function* (cmd: string[], opts?: { cwd?: string; env?: Record }) { + const result = yield* appProcess.run( + ChildProcess.make(cmd[0], cmd.slice(1), { cwd: opts?.cwd, env: opts?.env, extendEnv: true, - }) - const handle = yield* spawner.spawn(proc) - const out = yield* Stream.mkString(Stream.decodeText(handle.stdout)) - yield* handle.exitCode - return out - }, - Effect.scoped, - Effect.catch(() => Effect.succeed("")), - ) + }), + ) + return result.stdout.toString("utf8") + }, + Effect.catch(() => Effect.succeed("")), + ) - const run = Effect.fnUntraced( - function* (cmd: string[], opts?: { cwd?: string; env?: Record }) { - const proc = ChildProcess.make(cmd[0], cmd.slice(1), { + const run = Effect.fnUntraced( + function* (cmd: string[], opts?: { cwd?: string; env?: Record }) { + const result = yield* appProcess.run( + ChildProcess.make(cmd[0], cmd.slice(1), { cwd: opts?.cwd, env: opts?.env, extendEnv: true, - }) - const handle = yield* spawner.spawn(proc) - const [stdout, stderr] = yield* Effect.all( - [Stream.mkString(Stream.decodeText(handle.stdout)), Stream.mkString(Stream.decodeText(handle.stderr))], - { concurrency: 2 }, - ) - const code = yield* handle.exitCode - return { code, stdout, stderr } - }, - Effect.scoped, - Effect.catch(() => Effect.succeed({ code: ChildProcessSpawner.ExitCode(1), stdout: "", stderr: "" })), - ) + }), + ) + return { + code: result.exitCode, + stdout: result.stdout.toString("utf8"), + stderr: result.stderr.toString("utf8"), + } + }, + Effect.catch(() => Effect.succeed({ code: 1, stdout: "", stderr: "" })), + ) - const getBrewFormula = Effect.fnUntraced(function* () { - const tapFormula = yield* text(["brew", "list", "--formula", "anomalyco/tap/opencode"]) - if (tapFormula.includes("opencode")) return "anomalyco/tap/opencode" - const coreFormula = yield* text(["brew", "list", "--formula", "opencode"]) - if (coreFormula.includes("opencode")) return "opencode" - return "opencode" - }) + const getBrewFormula = Effect.fnUntraced(function* () { + const tapFormula = yield* text(["brew", "list", "--formula", "anomalyco/tap/opencode"]) + if (tapFormula.includes("opencode")) return "anomalyco/tap/opencode" + const coreFormula = yield* text(["brew", "list", "--formula", "opencode"]) + if (coreFormula.includes("opencode")) return "opencode" + return "opencode" + }) - const upgradeCurl = Effect.fnUntraced( - function* (target: string) { - const response = yield* httpOk.execute(HttpClientRequest.get("https://opencode.ai/install")) - const body = yield* response.text - const bodyBytes = new TextEncoder().encode(body) - const proc = ChildProcess.make("bash", [], { - stdin: Stream.make(bodyBytes), - env: { VERSION: target }, - extendEnv: true, - }) - const handle = yield* spawner.spawn(proc) - const [stdout, stderr] = yield* Effect.all( - [Stream.mkString(Stream.decodeText(handle.stdout)), Stream.mkString(Stream.decodeText(handle.stderr))], - { concurrency: 2 }, - ) - const code = yield* handle.exitCode - return { code, stdout, stderr } - }, - Effect.scoped, - Effect.orDie, - ) - - const result: Interface = { - info: Effect.fn("Installation.info")(function* () { - return { - version: InstallationVersion, - latest: yield* result.latest(), - } + const upgradeCurl = Effect.fnUntraced(function* (target: string) { + const response = yield* httpOk.execute(HttpClientRequest.get("https://opencode.ai/install")) + const body = yield* response.text + const bodyBytes = new TextEncoder().encode(body) + const result = yield* appProcess.run( + ChildProcess.make("bash", [], { + stdin: Stream.make(bodyBytes), + env: { VERSION: target }, + extendEnv: true, }), - method: Effect.fn("Installation.method")(function* () { - if (process.execPath.includes(path.join(".opencode", "bin"))) return "curl" as Method - if (process.execPath.includes(path.join(".local", "bin"))) return "curl" as Method - const exec = process.execPath.toLowerCase() + ) + return { + code: result.exitCode, + stdout: result.stdout.toString("utf8"), + stderr: result.stderr.toString("utf8"), + } + }, Effect.orDie) - const checks: Array<{ name: Method; command: () => Effect.Effect }> = [ - { name: "npm", command: () => text(["npm", "list", "-g", "--depth=0"]) }, - { name: "yarn", command: () => text(["yarn", "global", "list"]) }, - { name: "pnpm", command: () => text(["pnpm", "list", "-g", "--depth=0"]) }, - { name: "bun", command: () => text(["bun", "pm", "ls", "-g"]) }, - { name: "brew", command: () => text(["brew", "list", "--formula", "opencode"]) }, - { name: "scoop", command: () => text(["scoop", "list", "opencode"]) }, - { name: "choco", command: () => text(["choco", "list", "--limit-output", "opencode"]) }, - ] + const result: Interface = { + info: Effect.fn("Installation.info")(function* () { + return { + version: InstallationVersion, + latest: yield* result.latest(), + } + }), + method: Effect.fn("Installation.method")(function* () { + if (process.execPath.includes(path.join(".opencode", "bin"))) return "curl" as Method + if (process.execPath.includes(path.join(".local", "bin"))) return "curl" as Method + const exec = process.execPath.toLowerCase() - checks.sort((a, b) => { - const aMatches = exec.includes(a.name) - const bMatches = exec.includes(b.name) - if (aMatches && !bMatches) return -1 - if (!aMatches && bMatches) return 1 - return 0 - }) + const checks: Array<{ name: Method; command: () => Effect.Effect }> = [ + { name: "npm", command: () => text(["npm", "list", "-g", "--depth=0"]) }, + { name: "yarn", command: () => text(["yarn", "global", "list"]) }, + { name: "pnpm", command: () => text(["pnpm", "list", "-g", "--depth=0"]) }, + { name: "bun", command: () => text(["bun", "pm", "ls", "-g"]) }, + { name: "brew", command: () => text(["brew", "list", "--formula", "opencode"]) }, + { name: "scoop", command: () => text(["scoop", "list", "opencode"]) }, + { name: "choco", command: () => text(["choco", "list", "--limit-output", "opencode"]) }, + ] - for (const check of checks) { - const output = yield* check.command() - const installedName = - check.name === "brew" || check.name === "choco" || check.name === "scoop" ? "opencode" : "opencode-ai" - if (output.includes(installedName)) { - return check.name - } + checks.sort((a, b) => { + const aMatches = exec.includes(a.name) + const bMatches = exec.includes(b.name) + if (aMatches && !bMatches) return -1 + if (!aMatches && bMatches) return 1 + return 0 + }) + + for (const check of checks) { + const output = yield* check.command() + const installedName = + check.name === "brew" || check.name === "choco" || check.name === "scoop" ? "opencode" : "opencode-ai" + if (output.includes(installedName)) { + return check.name } + } - return "unknown" as Method - }), - latest: Effect.fn("Installation.latest")(function* (installMethod?: Method) { - const detectedMethod = installMethod || (yield* result.method()) + return "unknown" as Method + }), + latest: Effect.fn("Installation.latest")(function* (installMethod?: Method) { + const detectedMethod = installMethod || (yield* result.method()) - if (detectedMethod === "brew") { - const formula = yield* getBrewFormula() - if (formula.includes("/")) { - const infoJson = yield* text(["brew", "info", "--json=v2", formula]) - const info = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(BrewInfoV2))(infoJson) - return info.formulae[0].versions.stable - } - const response = yield* httpOk.execute( - HttpClientRequest.get("https://formulae.brew.sh/api/formula/opencode.json").pipe( - HttpClientRequest.acceptJson, - ), - ) - const data = yield* HttpClientResponse.schemaBodyJson(BrewFormula)(response) - return data.versions.stable + if (detectedMethod === "brew") { + const formula = yield* getBrewFormula() + if (formula.includes("/")) { + const infoJson = yield* text(["brew", "info", "--json=v2", formula]) + const info = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(BrewInfoV2))(infoJson) + return info.formulae[0].versions.stable } - - if (detectedMethod === "npm" || detectedMethod === "bun" || detectedMethod === "pnpm") { - const response = yield* httpOk.execute( - HttpClientRequest.get( - `${yield* NpmConfig.registry(process.cwd())}/opencode-ai/${InstallationChannel}`, - ).pipe(HttpClientRequest.acceptJson), - ) - const data = yield* HttpClientResponse.schemaBodyJson(NpmPackage)(response) - return data.version - } - - if (detectedMethod === "choco") { - const response = yield* httpOk.execute( - HttpClientRequest.get( - "https://community.chocolatey.org/api/v2/Packages?$filter=Id%20eq%20%27opencode%27%20and%20IsLatestVersion&$select=Version", - ).pipe(HttpClientRequest.setHeaders({ Accept: "application/json;odata=verbose" })), - ) - const data = yield* HttpClientResponse.schemaBodyJson(ChocoPackage)(response) - return data.d.results[0].Version - } - - if (detectedMethod === "scoop") { - const response = yield* httpOk.execute( - HttpClientRequest.get( - "https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/opencode.json", - ).pipe(HttpClientRequest.setHeaders({ Accept: "application/json" })), - ) - const data = yield* HttpClientResponse.schemaBodyJson(ScoopManifest)(response) - return data.version - } - const response = yield* httpOk.execute( - HttpClientRequest.get("https://api.github.com/repos/anomalyco/opencode/releases/latest").pipe( + HttpClientRequest.get("https://formulae.brew.sh/api/formula/opencode.json").pipe( HttpClientRequest.acceptJson, ), ) - const data = yield* HttpClientResponse.schemaBodyJson(GitHubRelease)(response) - return data.tag_name.replace(/^v/, "") - }, Effect.orDie), - upgrade: Effect.fn("Installation.upgrade")(function* (m: Method, target: string) { - let upgradeResult: { code: ChildProcessSpawner.ExitCode; stdout: string; stderr: string } | undefined - switch (m) { - case "curl": - upgradeResult = yield* upgradeCurl(target) - break - case "npm": - upgradeResult = yield* run(["npm", "install", "-g", `opencode-ai@${target}`]) - break - case "pnpm": - upgradeResult = yield* run(["pnpm", "install", "-g", `opencode-ai@${target}`]) - break - case "bun": - upgradeResult = yield* run(["bun", "install", "-g", `opencode-ai@${target}`]) - break - case "brew": { - const formula = yield* getBrewFormula() - const env = { HOMEBREW_NO_AUTO_UPDATE: "1" } - if (formula.includes("/")) { - const tap = yield* run(["brew", "tap", "anomalyco/tap"], { env }) - if (tap.code !== 0) { - upgradeResult = tap + const data = yield* HttpClientResponse.schemaBodyJson(BrewFormula)(response) + return data.versions.stable + } + + if (detectedMethod === "npm" || detectedMethod === "bun" || detectedMethod === "pnpm") { + const response = yield* httpOk.execute( + HttpClientRequest.get( + `${yield* NpmConfig.registry(process.cwd())}/opencode-ai/${InstallationChannel}`, + ).pipe(HttpClientRequest.acceptJson), + ) + const data = yield* HttpClientResponse.schemaBodyJson(NpmPackage)(response) + return data.version + } + + if (detectedMethod === "choco") { + const response = yield* httpOk.execute( + HttpClientRequest.get( + "https://community.chocolatey.org/api/v2/Packages?$filter=Id%20eq%20%27opencode%27%20and%20IsLatestVersion&$select=Version", + ).pipe(HttpClientRequest.setHeaders({ Accept: "application/json;odata=verbose" })), + ) + const data = yield* HttpClientResponse.schemaBodyJson(ChocoPackage)(response) + return data.d.results[0].Version + } + + if (detectedMethod === "scoop") { + const response = yield* httpOk.execute( + HttpClientRequest.get( + "https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/opencode.json", + ).pipe(HttpClientRequest.setHeaders({ Accept: "application/json" })), + ) + const data = yield* HttpClientResponse.schemaBodyJson(ScoopManifest)(response) + return data.version + } + + const response = yield* httpOk.execute( + HttpClientRequest.get("https://api.github.com/repos/anomalyco/opencode/releases/latest").pipe( + HttpClientRequest.acceptJson, + ), + ) + const data = yield* HttpClientResponse.schemaBodyJson(GitHubRelease)(response) + return data.tag_name.replace(/^v/, "") + }, Effect.orDie), + upgrade: Effect.fn("Installation.upgrade")(function* (m: Method, target: string) { + let upgradeResult: { code: number; stdout: string; stderr: string } | undefined + switch (m) { + case "curl": + upgradeResult = yield* upgradeCurl(target) + break + case "npm": + upgradeResult = yield* run(["npm", "install", "-g", `opencode-ai@${target}`]) + break + case "pnpm": + upgradeResult = yield* run(["pnpm", "install", "-g", `opencode-ai@${target}`]) + break + case "bun": + upgradeResult = yield* run(["bun", "install", "-g", `opencode-ai@${target}`]) + break + case "brew": { + const formula = yield* getBrewFormula() + const env = { HOMEBREW_NO_AUTO_UPDATE: "1" } + if (formula.includes("/")) { + const tap = yield* run(["brew", "tap", "anomalyco/tap"], { env }) + if (tap.code !== 0) { + upgradeResult = tap + break + } + const repo = yield* text(["brew", "--repo", "anomalyco/tap"]) + const dir = repo.trim() + if (dir) { + const pull = yield* run(["git", "pull", "--ff-only"], { cwd: dir, env }) + if (pull.code !== 0) { + upgradeResult = pull break } - const repo = yield* text(["brew", "--repo", "anomalyco/tap"]) - const dir = repo.trim() - if (dir) { - const pull = yield* run(["git", "pull", "--ff-only"], { cwd: dir, env }) - if (pull.code !== 0) { - upgradeResult = pull - break - } - } } - upgradeResult = yield* run(["brew", "upgrade", formula], { env }) - break } - case "choco": - upgradeResult = yield* run(["choco", "upgrade", "opencode", `--version=${target}`, "-y"]) - break - case "scoop": - upgradeResult = yield* run(["scoop", "install", `opencode@${target}`]) - break - default: - return yield* new UpgradeFailedError({ stderr: `Unknown method: ${m}` }) + upgradeResult = yield* run(["brew", "upgrade", formula], { env }) + break } - if (!upgradeResult || upgradeResult.code !== 0) { - const stderr = m === "choco" ? "not running from an elevated command shell" : upgradeResult?.stderr || "" - return yield* new UpgradeFailedError({ stderr }) - } - log.info("upgraded", { - method: m, - target, - stdout: upgradeResult.stdout, - stderr: upgradeResult.stderr, - }) - yield* text([process.execPath, "--version"]) - }), - } + case "choco": + upgradeResult = yield* run(["choco", "upgrade", "opencode", `--version=${target}`, "-y"]) + break + case "scoop": + upgradeResult = yield* run(["scoop", "install", `opencode@${target}`]) + break + default: + return yield* new UpgradeFailedError({ stderr: `Unknown method: ${m}` }) + } + if (!upgradeResult || upgradeResult.code !== 0) { + const stderr = m === "choco" ? "not running from an elevated command shell" : upgradeResult?.stderr || "" + return yield* new UpgradeFailedError({ stderr }) + } + log.info("upgraded", { + method: m, + target, + stdout: upgradeResult.stdout, + stderr: upgradeResult.stderr, + }) + yield* text([process.execPath, "--version"]) + }), + } - return Service.of(result) - }), - ) - -export const defaultLayer = layer.pipe( - Layer.provide(FetchHttpClient.layer), - Layer.provide(CrossSpawnSpawner.defaultLayer), + return Service.of(result) + }), ) +export const defaultLayer = layer.pipe(Layer.provide(FetchHttpClient.layer), Layer.provide(AppProcess.defaultLayer)) + const { runPromise } = makeRuntime(Service, defaultLayer) export const latest = (...args: Parameters) => runPromise((s) => s.latest(...args)) diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index 809ea95091..ac9706fc36 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -7,7 +7,6 @@ import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types import * as Log from "@opencode-ai/core/util/log" import { Process } from "@/util/process" import { LANGUAGE_EXTENSIONS } from "./language" -import z from "zod" import { Schema } from "effect" import type * as LSPServer from "./server" import { NamedError } from "@opencode-ai/core/util/error" @@ -32,12 +31,9 @@ export type Info = NonNullable>> export type Diagnostic = VSCodeDiagnostic -export const InitializeError = NamedError.create( - "LSPInitializeError", - z.object({ - serverID: z.string(), - }), -) +export const InitializeError = NamedError.create("LSPInitializeError", { + serverID: Schema.String, +}) export const Event = { Diagnostics: BusEvent.define( diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index db43412f73..832811b281 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -6,6 +6,7 @@ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js" import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js" import { CallToolResultSchema, + ListToolsResultSchema, ToolSchema, type Tool as MCPToolDef, ToolListChangedNotificationSchema, @@ -14,7 +15,6 @@ import { Config } from "@/config/config" import { ConfigMCP } from "../config/mcp" import * as Log from "@opencode-ai/core/util/log" import { NamedError } from "@opencode-ai/core/util/error" -import z from "zod/v4" import { Installation } from "../installation" import { InstallationVersion } from "@opencode-ai/core/installation/version" import { withTimeout } from "@/util/timeout" @@ -35,13 +35,8 @@ import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" const log = Log.create({ service: "mcp" }) const DEFAULT_TIMEOUT = 30_000 -const TolerantToolSchema = ToolSchema.extend({ - outputSchema: z.unknown().optional(), -}) - -const TolerantListToolsResultSchema = z.looseObject({ - tools: z.array(TolerantToolSchema), - nextCursor: z.string().optional(), +const TolerantListToolsResultSchema = ListToolsResultSchema.extend({ + tools: ToolSchema.omit({ outputSchema: true }).array(), }) export const Resource = Schema.Struct({ @@ -68,12 +63,9 @@ export const BrowserOpenFailed = BusEvent.define( }), ) -export const Failed = NamedError.create( - "MCPFailed", - z.object({ - name: z.string(), - }), -) +export const Failed = NamedError.create("MCPFailed", { + name: Schema.String, +}) type MCPClient = Client @@ -140,7 +132,10 @@ function listTools(key: string, client: MCPClient, timeout: number) { log.warn("failed to validate MCP tool output schemas, retrying without output schema validation", { key, error }) return Effect.tryPromise({ - try: () => client.request({ method: "tools/list" }, TolerantListToolsResultSchema, { timeout }), + try: () => + client.request({ method: "tools/list" }, TolerantListToolsResultSchema, { + timeout, + }), catch: (err) => (err instanceof Error ? err : new Error(String(err))), }).pipe( Effect.map((result) => diff --git a/packages/opencode/src/plugin/digitalocean.ts b/packages/opencode/src/plugin/digitalocean.ts new file mode 100644 index 0000000000..fa4adf6331 --- /dev/null +++ b/packages/opencode/src/plugin/digitalocean.ts @@ -0,0 +1,411 @@ +import type { Hooks, PluginInput } from "@opencode-ai/plugin" +import type { Model } from "@opencode-ai/sdk/v2" +import * as Log from "@opencode-ai/core/util/log" +import { InstallationVersion } from "@opencode-ai/core/installation/version" +import { createServer } from "http" + +const log = Log.create({ service: "plugin.digitalocean" }) + +const DO_OAUTH_CLIENT_ID = "b1a6c5158156caac821fd1b30253ca8acb52454a48fa744420e41889cb589f82" +const DO_AUTHORIZE_URL = "https://cloud.digitalocean.com/v1/oauth/authorize" +const DO_API_BASE = "https://api.digitalocean.com" +const DO_INFERENCE_BASE = "https://inference.do-ai.run/v1" +const OAUTH_PORT = 1456 +const OAUTH_REDIRECT_PATH = "/auth/callback" +const OAUTH_TOKEN_PATH = "/auth/token" +const ROUTER_REFRESH_INTERVAL_MS = 5 * 60 * 1000 +const MAK_NAME_PREFIX = "opencode-oauth" + +interface ImplicitTokenPayload { + access_token: string + expires_in: number + state: string +} + +interface PendingOAuth { + state: string + resolve: (tokens: ImplicitTokenPayload) => void + reject: (error: Error) => void +} + +interface ApiKeyInfo { + uuid: string + name: string + secret_key: string +} + +interface RouterEntry { + name: string + uuid?: string + description?: string +} + +let oauthServer: ReturnType | undefined +let pendingOAuth: PendingOAuth | undefined + +function generateState(): string { + const bytes = crypto.getRandomValues(new Uint8Array(32)) + return Array.from(bytes) + .map((b) => b.toString(16).padStart(2, "0")) + .join("") +} + +function redirectUri(): string { + return `http://localhost:${OAUTH_PORT}${OAUTH_REDIRECT_PATH}` +} + +function buildAuthorizeUrl(state: string): string { + const params = new URLSearchParams({ + response_type: "token", + client_id: DO_OAUTH_CLIENT_ID, + redirect_uri: redirectUri(), + scope: "read write", + state, + }) + return `${DO_AUTHORIZE_URL}?${params.toString()}` +} + +const HTML_CALLBACK = ` + + + + OpenCode - DigitalOcean Authorization + + + +
+

Finishing sign-in...

+

You can close this window once it says you're signed in.

+
+ + +` + +async function startOAuthServer(): Promise { + if (oauthServer) return + oauthServer = createServer((req, res) => { + const url = new URL(req.url || "/", `http://localhost:${OAUTH_PORT}`) + + if (req.method === "GET" && url.pathname === OAUTH_REDIRECT_PATH) { + res.writeHead(200, { "Content-Type": "text/html" }) + res.end(HTML_CALLBACK) + return + } + + if (req.method === "POST" && url.pathname === OAUTH_TOKEN_PATH) { + const chunks: Buffer[] = [] + req.on("data", (chunk: Buffer) => chunks.push(chunk)) + req.on("end", () => { + const raw = Buffer.concat(chunks).toString("utf8") + let body: Record = {} + try { + body = raw ? JSON.parse(raw) : {} + } catch { + body = {} + } + if (!pendingOAuth) { + res.writeHead(409, { "Content-Type": "application/json" }) + res.end(JSON.stringify({ error: "no_pending_oauth" })) + return + } + if (body.error) { + const message = body.error_description || body.error || "OAuth error" + pendingOAuth.reject(new Error(String(message))) + pendingOAuth = undefined + res.writeHead(200, { "Content-Type": "application/json" }) + res.end(JSON.stringify({ ok: true })) + return + } + if (!body.access_token) { + pendingOAuth.reject(new Error("Missing access_token in callback")) + pendingOAuth = undefined + res.writeHead(400, { "Content-Type": "application/json" }) + res.end(JSON.stringify({ error: "missing_access_token" })) + return + } + if (body.state !== pendingOAuth.state) { + pendingOAuth.reject(new Error("Invalid state - potential CSRF attack")) + pendingOAuth = undefined + res.writeHead(400, { "Content-Type": "application/json" }) + res.end(JSON.stringify({ error: "invalid_state" })) + return + } + const expires = parseInt(body.expires_in || "0", 10) + pendingOAuth.resolve({ + access_token: body.access_token, + expires_in: Number.isFinite(expires) && expires > 0 ? expires : 60 * 60 * 24 * 30, + state: body.state, + }) + pendingOAuth = undefined + res.writeHead(200, { "Content-Type": "application/json" }) + res.end(JSON.stringify({ ok: true })) + }) + return + } + + res.writeHead(404) + res.end("Not found") + }) + + await new Promise((resolve, reject) => { + oauthServer!.listen(OAUTH_PORT, () => { + log.info("digitalocean oauth server started", { port: OAUTH_PORT }) + resolve() + }) + oauthServer!.on("error", reject) + }) +} + +function stopOAuthServer() { + if (!oauthServer) return + oauthServer.close(() => log.info("digitalocean oauth server stopped")) + oauthServer = undefined +} + +function waitForOAuthCallback(state: string): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout( + () => { + if (pendingOAuth) { + pendingOAuth = undefined + reject(new Error("OAuth callback timeout - authorization took too long")) + } + }, + 5 * 60 * 1000, + ) + pendingOAuth = { + state, + resolve: (tokens) => { + clearTimeout(timeout) + resolve(tokens) + }, + reject: (error) => { + clearTimeout(timeout) + reject(error) + }, + } + }) +} + +async function createModelAccessKey(bearer: string): Promise { + // Suffix-on-collision strategy keeps re-`/connect` non-destructive. + const name = `${MAK_NAME_PREFIX}-${Math.floor(Date.now() / 1000)}` + const res = await fetch(`${DO_API_BASE}/v2/gen-ai/models/api_keys`, { + method: "POST", + headers: { + Authorization: `Bearer ${bearer}`, + "Content-Type": "application/json", + "User-Agent": `opencode/${InstallationVersion}`, + }, + body: JSON.stringify({ name }), + }) + if (!res.ok) { + const body = await res.text().catch(() => "") + throw new Error(`Failed to create Model Access Key (${res.status}): ${body}`) + } + const data = (await res.json()) as { api_key_info?: ApiKeyInfo } + if (!data.api_key_info?.secret_key) throw new Error("Model Access Key response missing secret_key") + return data.api_key_info +} + +async function listRouters( + bearer: string, +): Promise<{ ok: true; routers: RouterEntry[] } | { ok: false; status: number }> { + const res = await fetch(`${DO_API_BASE}/v2/gen-ai/models/routers`, { + headers: { + Authorization: `Bearer ${bearer}`, + Accept: "application/json", + "User-Agent": `opencode/${InstallationVersion}`, + }, + signal: AbortSignal.timeout(10_000), + }).catch(() => undefined) + if (!res) return { ok: false, status: 0 } + if (!res.ok) return { ok: false, status: res.status } + const body = (await res.json().catch(() => undefined)) as { model_routers?: RouterEntry[] } | undefined + return { ok: true, routers: body?.model_routers ?? [] } +} + +function routerModel(router: RouterEntry, providerID: string): Model { + const id = `router:${router.name}` + return { + id, + providerID, + name: router.name, + family: "digitalocean-inference-routers", + api: { id, url: DO_INFERENCE_BASE, npm: "@ai-sdk/openai-compatible" }, + status: "active", + headers: {}, + options: {}, + cost: { input: 0, output: 0, cache: { read: 0, write: 0 } }, + limit: { context: 128_000, output: 8_192 }, + capabilities: { + temperature: true, + reasoning: false, + attachment: false, + toolcall: true, + input: { text: true, audio: false, image: false, video: false, pdf: false }, + output: { text: true, audio: false, image: false, video: false, pdf: false }, + interleaved: false, + }, + release_date: "", + variants: {}, + } +} + +function parseRoutersJSON(raw: string | undefined): RouterEntry[] { + if (!raw) return [] + try { + const parsed = JSON.parse(raw) + if (!Array.isArray(parsed)) return [] + return parsed.flatMap((r) => + r && typeof r.name === "string" ? [{ name: r.name, uuid: r.uuid, description: r.description }] : [], + ) + } catch { + return [] + } +} + +export async function DigitalOceanAuthPlugin(input: PluginInput): Promise { + return { + provider: { + id: "digitalocean", + async models(provider, ctx) { + const baseModels = provider.models + if (ctx.auth?.type !== "api") return baseModels + + const metadata = ctx.auth.metadata ?? {} + const oauthAccess = metadata["oauth_access"] + const oauthExpires = parseInt(metadata["oauth_expires"] || "0", 10) + const fetchedAt = parseInt(metadata["routers_fetched_at"] || "0", 10) + const cached = parseRoutersJSON(metadata["routers"]) + + let routers = cached + const stale = Date.now() - fetchedAt > ROUTER_REFRESH_INTERVAL_MS + const bearerValid = oauthAccess && oauthExpires > Date.now() + + if (bearerValid && stale) { + const result = await listRouters(oauthAccess) + if (result.ok) { + routers = result.routers + const updated: Record = { + ...metadata, + routers: JSON.stringify(routers.map((r) => ({ name: r.name, uuid: r.uuid, description: r.description }))), + routers_fetched_at: String(Date.now()), + } + await input.client.auth + .set({ + path: { id: "digitalocean" }, + body: { type: "api", key: ctx.auth.key, metadata: updated }, + }) + .catch((err) => log.warn("failed to persist refreshed routers", { error: err })) + } else if (result.status === 401 || result.status === 403) { + log.warn("digitalocean oauth bearer rejected; using cached routers", { status: result.status }) + } else if (result.status !== 0) { + log.warn("digitalocean router refresh failed", { status: result.status }) + } + } + + const merged: Record = { ...baseModels } + for (const router of routers) { + const id = `router:${router.name}` + if (merged[id]) continue + merged[id] = routerModel(router, "digitalocean") + } + return merged + }, + }, + auth: { + provider: "digitalocean", + methods: [ + { + type: "oauth", + label: "Login with DigitalOcean", + async authorize() { + await startOAuthServer() + const state = generateState() + const callbackPromise = waitForOAuthCallback(state) + return { + url: buildAuthorizeUrl(state), + instructions: + "Sign in to DigitalOcean in your browser. OpenCode will create a Model Access Key named opencode-oauth-* and load your Inference Routers. Re-run /connect to refresh routers later.", + method: "auto" as const, + async callback() { + try { + const tokens = await callbackPromise + const apiKeyInfo = await createModelAccessKey(tokens.access_token) + const routerResult = await listRouters(tokens.access_token) + const routers = routerResult.ok ? routerResult.routers : [] + if (!routerResult.ok) { + log.warn("digitalocean initial router fetch failed", { status: routerResult.status }) + } + return { + type: "success" as const, + provider: "digitalocean", + key: apiKeyInfo.secret_key, + metadata: { + mak_uuid: apiKeyInfo.uuid, + mak_name: apiKeyInfo.name, + oauth_access: tokens.access_token, + oauth_expires: String(Date.now() + tokens.expires_in * 1000), + routers: JSON.stringify( + routers.map((r) => ({ name: r.name, uuid: r.uuid, description: r.description })), + ), + routers_fetched_at: String(Date.now()), + }, + } + } catch (err) { + log.error("digitalocean oauth callback failed", { error: err }) + return { type: "failed" as const } + } finally { + stopOAuthServer() + } + }, + } + }, + }, + { + type: "api", + label: "Paste Model Access Key", + }, + ], + }, + } +} diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts index 7a7f260df8..e87f6db238 100644 --- a/packages/opencode/src/plugin/index.ts +++ b/packages/opencode/src/plugin/index.ts @@ -9,7 +9,6 @@ import { Config } from "@/config/config" import { Bus } from "../bus" import * as Log from "@opencode-ai/core/util/log" import { createOpencodeClient } from "@opencode-ai/sdk" -import { Flag } from "@opencode-ai/core/flag/flag" import { ServerAuth } from "@/server/auth" import { CodexAuthPlugin } from "./codex" import { Session } from "@/session/session" @@ -19,6 +18,7 @@ import { gitlabAuthPlugin as GitlabAuthPlugin } from "opencode-gitlab-auth" import { PoeAuthPlugin } from "opencode-poe-auth" import { CloudflareAIGatewayAuthPlugin, CloudflareWorkersAuthPlugin } from "./cloudflare" import { AzureAuthPlugin } from "./azure" +import { DigitalOceanAuthPlugin } from "./digitalocean" import { Effect, Layer, Context, Stream } from "effect" import { EffectBridge } from "@/effect/bridge" import { InstanceState } from "@/effect/instance-state" @@ -27,6 +27,7 @@ import { PluginLoader } from "./loader" import { parsePluginSpecifier, readPluginId, readV1Plugin, resolvePluginId } from "./shared" import { registerAdapter } from "@/control-plane/adapters" import type { WorkspaceAdapter } from "@/control-plane/types" +import { RuntimeFlags } from "@/effect/runtime-flags" const log = Log.create({ service: "plugin" }) @@ -64,6 +65,7 @@ const INTERNAL_PLUGINS: PluginInstance[] = [ CloudflareWorkersAuthPlugin, CloudflareAIGatewayAuthPlugin, AzureAuthPlugin, + DigitalOceanAuthPlugin, ] function isServerPlugin(value: unknown): value is PluginInstance { @@ -110,6 +112,7 @@ export const layer = Layer.effect( Effect.gen(function* () { const bus = yield* Bus.Service const config = yield* Config.Service + const flags = yield* RuntimeFlags.Service const state = yield* InstanceState.make( Effect.fn("Plugin.state")(function* (ctx) { @@ -146,7 +149,7 @@ export const layer = Layer.effect( $: typeof Bun === "undefined" ? undefined : Bun.$, } - for (const plugin of INTERNAL_PLUGINS) { + for (const plugin of flags.disableDefaultPlugins ? [] : INTERNAL_PLUGINS) { log.info("loading internal plugin", { name: plugin.name }) const init = yield* Effect.tryPromise({ try: () => plugin(input), @@ -157,8 +160,8 @@ export const layer = Layer.effect( if (init._tag === "Some") hooks.push(init.value) } - const plugins = Flag.OPENCODE_PURE ? [] : (cfg.plugin_origins ?? []) - if (Flag.OPENCODE_PURE && cfg.plugin_origins?.length) { + const plugins = flags.pure ? [] : (cfg.plugin_origins ?? []) + if (flags.pure && cfg.plugin_origins?.length) { log.info("skipping external plugins in pure mode", { count: cfg.plugin_origins.length }) } if (plugins.length) yield* config.waitForDependencies() @@ -283,6 +286,10 @@ export const layer = Layer.effect( }), ) -export const defaultLayer = layer.pipe(Layer.provide(Bus.layer), Layer.provide(Config.defaultLayer)) +export const defaultLayer = layer.pipe( + Layer.provide(Bus.layer), + Layer.provide(Config.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), +) export * as Plugin from "." diff --git a/packages/opencode/src/project/bootstrap.ts b/packages/opencode/src/project/bootstrap.ts index 6103a9efb4..a7e67d45e9 100644 --- a/packages/opencode/src/project/bootstrap.ts +++ b/packages/opencode/src/project/bootstrap.ts @@ -37,7 +37,7 @@ export const layer = Layer.effect( const run = Effect.gen(function* () { const ctx = yield* InstanceState.context - yield* Effect.logInfo("bootstrapping", { directory: ctx.directory }) + yield* Effect.logInfo("bootstrapping").pipe(Effect.annotateLogs("directory", ctx.directory)) // everything depends on config so eager load it for nice traces yield* config.get() // Plugin can mutate config so it has to be initialized before anything else. diff --git a/packages/opencode/src/project/instance-store.ts b/packages/opencode/src/project/instance-store.ts index 9707305f93..faa56668a7 100644 --- a/packages/opencode/src/project/instance-store.ts +++ b/packages/opencode/src/project/instance-store.ts @@ -156,7 +156,9 @@ export const layer: Layer.Layer -export const OauthMissing = namedSchemaError("ProviderAuthOauthMissing", { providerID: ProviderID }) +export class OauthMissing extends Schema.TaggedErrorClass()("ProviderAuthOauthMissing", { + providerID: ProviderID, +}) {} -export const OauthCodeMissing = namedSchemaError("ProviderAuthOauthCodeMissing", { providerID: ProviderID }) +export class OauthCodeMissing extends Schema.TaggedErrorClass()("ProviderAuthOauthCodeMissing", { + providerID: ProviderID, +}) {} -export const OauthCallbackFailed = namedSchemaError("ProviderAuthOauthCallbackFailed", {}) +export class OauthCallbackFailed extends Schema.TaggedErrorClass()( + "ProviderAuthOauthCallbackFailed", + {}, +) {} -export const ValidationFailed = namedSchemaError("ProviderAuthValidationFailed", { +export class ValidationFailed extends Schema.TaggedErrorClass()("ProviderAuthValidationFailed", { field: Schema.String, message: Schema.String, -}) +}) {} -export type Error = - | Auth.AuthError - | InstanceType - | InstanceType - | InstanceType - | InstanceType +export type Error = Auth.AuthError | OauthMissing | OauthCodeMissing | OauthCallbackFailed | ValidationFailed type Hook = NonNullable @@ -166,7 +167,7 @@ export const layer: Layer.Layer = for (const prompt of method.prompts) { if (prompt.type === "text" && prompt.validate && input.inputs[prompt.key] !== undefined) { const error = prompt.validate(input.inputs[prompt.key]) - if (error) return yield* Effect.fail(new ValidationFailed({ field: prompt.key, message: error })) + if (error) return yield* new ValidationFailed({ field: prompt.key, message: error }) } } } @@ -183,20 +184,21 @@ export const layer: Layer.Layer = const callback = Effect.fn("ProviderAuth.callback")(function* (input: { providerID: ProviderID } & CallbackInput) { const pending = (yield* InstanceState.get(state)).pending const match = pending.get(input.providerID) - if (!match) return yield* Effect.fail(new OauthMissing({ providerID: input.providerID })) + if (!match) return yield* new OauthMissing({ providerID: input.providerID }) if (match.method === "code" && !input.code) { - return yield* Effect.fail(new OauthCodeMissing({ providerID: input.providerID })) + return yield* new OauthCodeMissing({ providerID: input.providerID }) } const result = yield* Effect.promise(() => match.method === "code" ? match.callback(input.code!) : match.callback(), ) - if (!result || result.type !== "success") return yield* Effect.fail(new OauthCallbackFailed({})) + if (!result || result.type !== "success") return yield* new OauthCallbackFailed({}) if ("key" in result) { yield* auth.set(input.providerID, { type: "api", key: result.key, + ...(result.metadata ? { metadata: result.metadata } : {}), }) } diff --git a/packages/opencode/src/provider/models.ts b/packages/opencode/src/provider/models.ts index fb240e4cf1..9f88f9db17 100644 --- a/packages/opencode/src/provider/models.ts +++ b/packages/opencode/src/provider/models.ts @@ -10,11 +10,23 @@ import { AppFileSystem } from "@opencode-ai/core/filesystem" import { withTransientReadRetry } from "@/util/effect-http-client" import { CatalogModelStatus } from "./model-status" +const CostTier = Schema.Struct({ + input: Schema.Finite, + output: Schema.Finite, + cache_read: Schema.optional(Schema.Finite), + cache_write: Schema.optional(Schema.Finite), + tier: Schema.Struct({ + type: Schema.Literal("context"), + size: Schema.Finite, + }), +}) + const Cost = Schema.Struct({ input: Schema.Finite, output: Schema.Finite, cache_read: Schema.optional(Schema.Finite), cache_write: Schema.optional(Schema.Finite), + tiers: Schema.optional(Schema.Array(CostTier)), context_over_200k: Schema.optional( Schema.Struct({ input: Schema.Finite, @@ -177,7 +189,9 @@ export const layer: Layer.Layer Effect.logError("Failed to fetch models.dev", { cause })), + Effect.tapCause((cause) => + Effect.logError("Failed to fetch models.dev").pipe(Effect.annotateLogs("cause", cause)), + ), Effect.ignore, ) }) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 236f14de75..ca87c40b7d 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -13,7 +13,7 @@ import { Auth } from "../auth" import { Env } from "../env" import { InstallationVersion } from "@opencode-ai/core/installation/version" import { Flag } from "@opencode-ai/core/flag/flag" -import { namedSchemaError } from "@/util/named-schema-error" +import { NamedError } from "@opencode-ai/core/util/error" import { iife } from "@/util/iife" import { Global } from "@opencode-ai/core/global" import path from "path" @@ -24,7 +24,6 @@ import { InstanceState } from "@/effect/instance-state" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { isRecord } from "@/util/record" import { optionalOmitUndefined } from "@opencode-ai/core/schema" - import * as ProviderTransform from "./transform" import { ModelID, ProviderID } from "./schema" import { ModelStatus } from "./model-status" @@ -112,7 +111,8 @@ const BUNDLED_PROVIDERS: Record Promise<(opts: any) => BundledSDK> "@ai-sdk/vercel": () => import("@ai-sdk/vercel").then((m) => m.createVercel), "@ai-sdk/alibaba": () => import("@ai-sdk/alibaba").then((m) => m.createAlibaba), "gitlab-ai-provider": () => import("gitlab-ai-provider").then((m) => m.createGitLab), - "@ai-sdk/github-copilot": () => import("./sdk/copilot/copilot-provider").then((m) => m.createOpenaiCompatible), + "@ai-sdk/github-copilot": () => + import("@opencode-ai/core/github-copilot/copilot-provider").then((m) => m.createOpenaiCompatible), "venice-ai-sdk-provider": () => import("venice-ai-sdk-provider").then((m) => m.createVenice), } @@ -449,8 +449,14 @@ function custom(dep: CustomDep): Record { }), "google-vertex": Effect.fnUntraced(function* (provider: Info) { const env = yield* dep.env() + // models.dev advertises GOOGLE_VERTEX_PROJECT for Vertex; keep the wider + // Google Cloud project env names as fallbacks for existing ADC setups. const project = - provider.options?.project ?? env["GOOGLE_CLOUD_PROJECT"] ?? env["GCP_PROJECT"] ?? env["GCLOUD_PROJECT"] + provider.options?.project ?? + env["GOOGLE_VERTEX_PROJECT"] ?? + env["GOOGLE_CLOUD_PROJECT"] ?? + env["GCP_PROJECT"] ?? + env["GCLOUD_PROJECT"] const location = String( provider.options?.location ?? @@ -739,6 +745,7 @@ function custom(dep: CustomDep): Record { const auth = yield* dep.auth(input.id) const env = yield* dep.env() const accountId = env["CLOUDFLARE_ACCOUNT_ID"] || (auth?.type === "api" ? auth.metadata?.accountId : undefined) + // The Cloudflare auth prompt stores this value as gatewayId metadata. const gateway = env["CLOUDFLARE_GATEWAY_ID"] || (auth?.type === "api" ? auth.metadata?.gatewayId : undefined) if (!accountId || !gateway) { @@ -869,10 +876,21 @@ const ProviderCacheCost = Schema.Struct({ write: Schema.Finite, }) +const ProviderCostTier = Schema.Struct({ + input: Schema.Finite, + output: Schema.Finite, + cache: ProviderCacheCost, + tier: Schema.Struct({ + type: Schema.Literal("context"), + size: Schema.Finite, + }), +}) + const ProviderCost = Schema.Struct({ input: Schema.Finite, output: Schema.Finite, cache: ProviderCacheCost, + tiers: optionalOmitUndefined(Schema.Array(ProviderCostTier)), experimentalOver200K: optionalOmitUndefined( Schema.Struct({ input: Schema.Finite, @@ -977,6 +995,17 @@ function cost(c: ModelsDev.Model["cost"]): Model["cost"] { write: c?.cache_write ?? 0, }, } + if (c?.tiers) { + result.tiers = c.tiers.map((item) => ({ + input: item.input, + output: item.output, + cache: { + read: item.cache_read ?? 0, + write: item.cache_write ?? 0, + }, + tier: item.tier, + })) + } if (c?.context_over_200k) { result.experimentalOver200K = { cache: { @@ -1075,11 +1104,7 @@ export function fromModelsDevProvider(provider: ModelsDev.Provider): Info { } } -const layer: Layer.Layer< - Service, - never, - Config.Service | Auth.Service | Plugin.Service | AppFileSystem.Service | Env.Service | ModelsDev.Service -> = Layer.effect( +const layer = Layer.effect( Service, Effect.gen(function* () { const fs = yield* AppFileSystem.Service @@ -1370,7 +1395,12 @@ const layer: Layer.Layer< for (const [modelID, model] of Object.entries(provider.models)) { model.api.id = model.api.id ?? model.id ?? modelID if ( - modelID === "gpt-5-chat-latest" || + // These chat aliases are invalid for the special handling in the + // built-in providers below, but custom providers may support them. + (modelID === "gpt-5-chat-latest" && + (providerID === ProviderID.openai || + providerID === ProviderID.githubCopilot || + providerID === ProviderID.openrouter)) || (providerID === ProviderID.openrouter && modelID === "openai/gpt-5-chat") ) delete provider.models[modelID] @@ -1749,13 +1779,13 @@ export function parseModel(model: string) { } } -export const ModelNotFoundError = namedSchemaError("ProviderModelNotFoundError", { +export const ModelNotFoundError = NamedError.create("ProviderModelNotFoundError", { providerID: ProviderID, modelID: ModelID, suggestions: Schema.optional(Schema.Array(Schema.String)), }) -export const InitError = namedSchemaError("ProviderInitError", { +export const InitError = NamedError.create("ProviderInitError", { providerID: ProviderID, }) diff --git a/packages/opencode/src/reference/reference.ts b/packages/opencode/src/reference/reference.ts index 09e0a825d8..3109c37492 100644 --- a/packages/opencode/src/reference/reference.ts +++ b/packages/opencode/src/reference/reference.ts @@ -1,10 +1,10 @@ import path from "path" import { Effect, Context, Layer, Scope } from "effect" import { AppFileSystem } from "@opencode-ai/core/filesystem" -import { Flag } from "@opencode-ai/core/flag/flag" import { Global } from "@opencode-ai/core/global" import { Config } from "@/config/config" import { InstanceState } from "@/effect/instance-state" +import { RuntimeFlags } from "@/effect/runtime-flags" import { Git } from "@/git" import { parseRepositoryReference, repositoryCachePath, type Reference as RepositoryReference } from "@/util/repository" import { RepositoryCache } from "./repository-cache" @@ -143,6 +143,7 @@ export const layer = Layer.effect( const fs = yield* AppFileSystem.Service const git = yield* Git.Service const scope = yield* Scope.Scope + const flags = yield* RuntimeFlags.Service const state = yield* InstanceState.make( Effect.fn("Reference.state")(function* (ctx) { @@ -169,7 +170,9 @@ export const layer = Layer.effect( ).pipe( Effect.asVoid, Effect.catchCause((cause) => - Effect.logWarning("failed to materialize reference repository", { name: reference.name, cause }), + Effect.logWarning("failed to materialize reference repository").pipe( + Effect.annotateLogs({ name: reference.name, cause }), + ), ), ), ) @@ -179,7 +182,7 @@ export const layer = Layer.effect( ) const materializeAll = yield* Effect.cached( - Flag.OPENCODE_EXPERIMENTAL_SCOUT + flags.experimentalScout ? Effect.gen(function* () { yield* Effect.forEach( materializeByPath, @@ -198,7 +201,7 @@ export const layer = Layer.effect( return Service.of({ init: Effect.fn("Reference.init")(function* () { - if (!Flag.OPENCODE_EXPERIMENTAL_SCOUT) return + if (!flags.experimentalScout) return yield* InstanceState.useEffect(state, (s) => s.materializeAll).pipe(Effect.forkIn(scope), Effect.asVoid) }), list: Effect.fn("Reference.list")(function* () { @@ -208,7 +211,7 @@ export const layer = Layer.effect( return yield* InstanceState.use(state, (s) => s.references.find((reference) => reference.name === name)) }), ensure: Effect.fn("Reference.ensure")(function* (target?: string) { - if (!Flag.OPENCODE_EXPERIMENTAL_SCOUT) return + if (!flags.experimentalScout) return const full = normalizedTarget(target) if (!full) return yield* InstanceState.useEffect(state, (s) => s.materializeAll) return yield* InstanceState.useEffect( @@ -217,7 +220,7 @@ export const layer = Layer.effect( ) }), contains: Effect.fn("Reference.contains")(function* (target?: string) { - if (!Flag.OPENCODE_EXPERIMENTAL_SCOUT) return false + if (!flags.experimentalScout) return false const full = normalizedTarget(target) if (!full) return false return yield* InstanceState.use(state, (s) => @@ -232,6 +235,7 @@ export const defaultLayer = layer.pipe( Layer.provide(Config.defaultLayer), Layer.provide(AppFileSystem.defaultLayer), Layer.provide(Git.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), ) export * as Reference from "./reference" diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts index 99a8a21a9e..160bafb1e3 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/experimental.ts @@ -54,6 +54,22 @@ export const ToolListQuery = Schema.Struct({ }) const WorktreeList = Schema.Array(Schema.String) +const WorktreeErrorName = Schema.Union([ + Schema.Literal("WorktreeNotGitError"), + Schema.Literal("WorktreeNameGenerationFailedError"), + Schema.Literal("WorktreeCreateFailedError"), + Schema.Literal("WorktreeStartCommandFailedError"), + Schema.Literal("WorktreeRemoveFailedError"), + Schema.Literal("WorktreeResetFailedError"), + Schema.Literal("WorktreeListFailedError"), +]) +export class WorktreeApiError extends Schema.ErrorClass("WorktreeError")( + { + name: WorktreeErrorName, + data: Schema.Struct({ message: Schema.String }), + }, + { httpApiStatus: 400 }, +) {} export const SessionListQuery = Schema.Struct({ ...WorkspaceRoutingQueryFields, roots: Schema.optional(QueryBoolean), @@ -141,6 +157,7 @@ export const ExperimentalApi = HttpApi.make("experimental") HttpApiEndpoint.get("worktree", ExperimentalPaths.worktree, { query: WorkspaceRoutingQuery, success: described(WorktreeList, "List of worktree directories"), + error: WorktreeApiError, }).annotateMerge( OpenApi.annotations({ identifier: "worktree.list", @@ -152,7 +169,7 @@ export const ExperimentalApi = HttpApi.make("experimental") query: WorkspaceRoutingQuery, payload: Schema.optional(Worktree.CreateInput), success: described(Worktree.Info, "Worktree created"), - error: HttpApiError.BadRequest, + error: WorktreeApiError, }).annotateMerge( OpenApi.annotations({ identifier: "worktree.create", @@ -164,7 +181,7 @@ export const ExperimentalApi = HttpApi.make("experimental") query: WorkspaceRoutingQuery, payload: Worktree.RemoveInput, success: described(Schema.Boolean, "Worktree removed"), - error: HttpApiError.BadRequest, + error: WorktreeApiError, }).annotateMerge( OpenApi.annotations({ identifier: "worktree.remove", @@ -176,7 +193,7 @@ export const ExperimentalApi = HttpApi.make("experimental") query: WorkspaceRoutingQuery, payload: Worktree.ResetInput, success: described(Schema.Boolean, "Worktree reset"), - error: HttpApiError.BadRequest, + error: WorktreeApiError, }).annotateMerge( OpenApi.annotations({ identifier: "worktree.reset", diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/provider.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/provider.ts index 49792898df..b6eecff4c0 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/provider.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/provider.ts @@ -10,6 +10,26 @@ import { described } from "./metadata" const root = "/provider" +const ProviderAuthErrorName = Schema.Union([ + Schema.Literal("BadRequest"), + Schema.Literal("ProviderAuthOauthMissing"), + Schema.Literal("ProviderAuthOauthCodeMissing"), + Schema.Literal("ProviderAuthOauthCallbackFailed"), + Schema.Literal("ProviderAuthValidationFailed"), +]) +export class ProviderAuthApiError extends Schema.ErrorClass("ProviderAuthError")( + { + name: ProviderAuthErrorName, + data: Schema.Struct({ + providerID: Schema.optional(ProviderID), + field: Schema.optional(Schema.String), + message: Schema.optional(Schema.String), + kind: Schema.optional(Schema.String), + }), + }, + { httpApiStatus: 400 }, +) {} + export const ProviderApi = HttpApi.make("provider") .add( HttpApiGroup.make("provider") @@ -39,7 +59,7 @@ export const ProviderApi = HttpApi.make("provider") query: WorkspaceRoutingQuery, payload: ProviderAuth.AuthorizeInput, success: described(Schema.UndefinedOr(ProviderAuth.Authorization), "Authorization URL and method"), - error: HttpApiError.BadRequest, + error: ProviderAuthApiError, }).annotateMerge( OpenApi.annotations({ identifier: "provider.oauth.authorize", @@ -52,7 +72,7 @@ export const ProviderApi = HttpApi.make("provider") query: WorkspaceRoutingQuery, payload: ProviderAuth.CallbackInput, success: described(Schema.Boolean, "OAuth callback processed successfully"), - error: HttpApiError.BadRequest, + error: ProviderAuthApiError, }).annotateMerge( OpenApi.annotations({ identifier: "provider.oauth.callback", diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts index 2053aba3b4..b8c8a142be 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts @@ -141,7 +141,7 @@ export const SessionApi = HttpApi.make("session") params: { sessionID: SessionID }, query: WorkspaceRoutingQuery, success: described(Schema.Array(Session.Info), "List of children"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.children", @@ -153,7 +153,7 @@ export const SessionApi = HttpApi.make("session") params: { sessionID: SessionID }, query: WorkspaceRoutingQuery, success: described(Schema.Array(Todo.Info), "Todo list"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.todo", @@ -250,7 +250,7 @@ export const SessionApi = HttpApi.make("session") params: { sessionID: SessionID }, query: WorkspaceRoutingQuery, success: described(Schema.Boolean, "Aborted session"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: HttpApiError.BadRequest, }).annotateMerge( OpenApi.annotations({ identifier: "session.abort", @@ -263,7 +263,7 @@ export const SessionApi = HttpApi.make("session") query: WorkspaceRoutingQuery, payload: InitPayload, success: described(Schema.Boolean, "200"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.init", @@ -314,7 +314,7 @@ export const SessionApi = HttpApi.make("session") query: WorkspaceRoutingQuery, payload: PromptPayload, success: described(MessageV2.WithParts, "Created message"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.prompt", @@ -327,7 +327,7 @@ export const SessionApi = HttpApi.make("session") query: WorkspaceRoutingQuery, payload: PromptPayload, success: described(HttpApiSchema.NoContent, "Prompt accepted"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.prompt_async", @@ -341,7 +341,7 @@ export const SessionApi = HttpApi.make("session") query: WorkspaceRoutingQuery, payload: CommandPayload, success: described(MessageV2.WithParts, "Created message"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.command", @@ -354,7 +354,7 @@ export const SessionApi = HttpApi.make("session") query: WorkspaceRoutingQuery, payload: ShellPayload, success: described(MessageV2.WithParts, "Created message"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.shell", @@ -367,7 +367,7 @@ export const SessionApi = HttpApi.make("session") query: WorkspaceRoutingQuery, payload: RevertPayload, success: described(Session.Info, "Updated session"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.revert", @@ -380,7 +380,7 @@ export const SessionApi = HttpApi.make("session") params: { sessionID: SessionID }, query: WorkspaceRoutingQuery, success: described(Session.Info, "Updated session"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.unrevert", @@ -393,7 +393,7 @@ export const SessionApi = HttpApi.make("session") query: WorkspaceRoutingQuery, payload: PermissionResponsePayload, success: described(Schema.Boolean, "Permission processed successfully"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "permission.respond", @@ -406,7 +406,7 @@ export const SessionApi = HttpApi.make("session") params: { sessionID: SessionID, messageID: MessageID }, query: WorkspaceRoutingQuery, success: described(Schema.Boolean, "Successfully deleted message"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.deleteMessage", @@ -419,7 +419,7 @@ export const SessionApi = HttpApi.make("session") params: { sessionID: SessionID, messageID: MessageID, partID: PartID }, query: WorkspaceRoutingQuery, success: described(Schema.Boolean, "Successfully deleted part"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "part.delete", @@ -431,7 +431,7 @@ export const SessionApi = HttpApi.make("session") query: WorkspaceRoutingQuery, payload: MessageV2.Part, success: described(MessageV2.Part, "Successfully updated part"), - error: [HttpApiError.BadRequest, HttpApiError.NotFound], + error: [HttpApiError.BadRequest, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "part.update", diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/v2.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/v2.ts index 05da5b720d..532ccce51d 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/v2.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/v2.ts @@ -1,10 +1,14 @@ import { HttpApi, OpenApi } from "effect/unstable/httpapi" import { MessageGroup } from "./v2/message" +import { ModelGroup } from "./v2/model" +import { ProviderGroup } from "./v2/provider" import { SessionGroup } from "./v2/session" export const V2Api = HttpApi.make("v2") .add(SessionGroup) .add(MessageGroup) + .add(ModelGroup) + .add(ProviderGroup) .annotateMerge( OpenApi.annotations({ title: "opencode experimental HttpApi", diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/v2/model.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/model.ts new file mode 100644 index 0000000000..35e7aeb850 --- /dev/null +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/model.ts @@ -0,0 +1,24 @@ +import { ModelV2 } from "@opencode-ai/core/model" +import { Schema } from "effect" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { Authorization } from "../../middleware/authorization" + +export const ModelGroup = HttpApiGroup.make("v2.model") + .add( + HttpApiEndpoint.get("models", "/api/model", { + success: Schema.Array(ModelV2.Info), + }).annotateMerge( + OpenApi.annotations({ + identifier: "v2.model.list", + summary: "List v2 models", + description: "Retrieve available v2 models ordered by release date.", + }), + ), + ) + .annotateMerge( + OpenApi.annotations({ + title: "v2 models", + description: "Experimental v2 model routes.", + }), + ) + .middleware(Authorization) diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/v2/provider.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/provider.ts new file mode 100644 index 0000000000..6d92100886 --- /dev/null +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/provider.ts @@ -0,0 +1,38 @@ +import { ProviderV2 } from "@opencode-ai/core/provider" +import { Schema } from "effect" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { ApiNotFoundError } from "../../errors" +import { Authorization } from "../../middleware/authorization" + +export const ProviderGroup = HttpApiGroup.make("v2.provider") + .add( + HttpApiEndpoint.get("providers", "/api/provider", { + success: Schema.Array(ProviderV2.Info), + }).annotateMerge( + OpenApi.annotations({ + identifier: "v2.provider.list", + summary: "List v2 providers", + description: "Retrieve active v2 AI providers so clients can show provider availability and configuration.", + }), + ), + ) + .add( + HttpApiEndpoint.get("provider", "/api/provider/:providerID", { + params: { providerID: ProviderV2.ID }, + success: ProviderV2.Info, + error: ApiNotFoundError, + }).annotateMerge( + OpenApi.annotations({ + identifier: "v2.provider.get", + summary: "Get v2 provider", + description: "Retrieve a single v2 AI provider so clients can inspect its availability and endpoint settings.", + }), + ), + ) + .annotateMerge( + OpenApi.annotations({ + title: "v2 providers", + description: "Experimental v2 provider routes.", + }), + ) + .middleware(Authorization) diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/v2/session.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/session.ts index 231f1915bb..3776f5c72a 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/v2/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/v2/session.ts @@ -1,6 +1,6 @@ import { SessionID } from "@/session/schema" import { SessionMessage } from "@/v2/session-message" -import { Prompt } from "@/v2/session-prompt" +import { Prompt } from "@opencode-ai/core/session-prompt" import { SessionV2 } from "@/v2/session" import { Schema } from "effect" import { HttpApiEndpoint, HttpApiError, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts index 360daf54a5..56a8de3ffa 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/experimental.ts @@ -12,7 +12,13 @@ import { Effect, Option } from "effect" import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse" import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi" import { InstanceHttpApi } from "../api" -import { ConsoleSwitchPayload, SessionListQuery, ToolListQuery } from "../groups/experimental" +import { ConsoleSwitchPayload, SessionListQuery, ToolListQuery, WorktreeApiError } from "../groups/experimental" + +function mapWorktreeError(self: Effect.Effect) { + return self.pipe( + Effect.mapError((error) => new WorktreeApiError({ name: error._tag, data: { message: error.message } })), + ) +} export const experimentalHandlers = HttpApiBuilder.group(InstanceHttpApi, "experimental", (handlers) => Effect.gen(function* () { @@ -79,7 +85,7 @@ export const experimentalHandlers = HttpApiBuilder.group(InstanceHttpApi, "exper const list = yield* registry.tools({ providerID: ctx.query.provider, modelID: ctx.query.model, - agent: yield* agents.get(yield* agents.defaultAgent()), + agent: yield* agents.defaultInfo(), }) return list.map((item) => ({ id: item.id, @@ -100,14 +106,14 @@ export const experimentalHandlers = HttpApiBuilder.group(InstanceHttpApi, "exper const worktreeCreate = Effect.fn("ExperimentalHttpApi.worktreeCreate")(function* (ctx: { payload: Worktree.CreateInput | undefined }) { - return yield* worktreeSvc.create(ctx.payload) + return yield* mapWorktreeError(worktreeSvc.create(ctx.payload)) }) const worktreeRemove = Effect.fn("ExperimentalHttpApi.worktreeRemove")(function* (input: { payload: Worktree.RemoveInput }) { const ctx = yield* InstanceState.context - yield* worktreeSvc.remove(input.payload) + yield* mapWorktreeError(worktreeSvc.remove(input.payload)) yield* project.removeSandbox(ctx.project.id, input.payload.directory) return true }) @@ -115,7 +121,7 @@ export const experimentalHandlers = HttpApiBuilder.group(InstanceHttpApi, "exper const worktreeReset = Effect.fn("ExperimentalHttpApi.worktreeReset")(function* (ctx: { payload: Worktree.ResetInput }) { - yield* worktreeSvc.reset(ctx.payload) + yield* mapWorktreeError(worktreeSvc.reset(ctx.payload)) return true }) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts index b9d5b5af15..9da31582a3 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts @@ -6,8 +6,29 @@ import { ProviderID } from "@/provider/schema" import { mapValues } from "remeda" import { Effect, Schema } from "effect" import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http" -import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/unstable/httpapi" import { InstanceHttpApi } from "../api" +import { ProviderAuthApiError } from "../groups/provider" + +function mapProviderAuthError(self: Effect.Effect) { + return self.pipe( + Effect.mapError((error) => { + if (error instanceof ProviderAuth.OauthMissing) { + return new ProviderAuthApiError({ name: error._tag, data: { providerID: error.providerID } }) + } + if (error instanceof ProviderAuth.OauthCodeMissing) { + return new ProviderAuthApiError({ name: error._tag, data: { providerID: error.providerID } }) + } + if (error instanceof ProviderAuth.OauthCallbackFailed) { + return new ProviderAuthApiError({ name: error._tag, data: {} }) + } + if (error instanceof ProviderAuth.ValidationFailed) { + return new ProviderAuthApiError({ name: error._tag, data: { field: error.field, message: error.message } }) + } + return new ProviderAuthApiError({ name: "BadRequest", data: {} }) + }), + ) +} export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider", (handlers) => Effect.gen(function* () { @@ -44,13 +65,13 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider" params: { providerID: ProviderID } payload: ProviderAuth.AuthorizeInput }) { - return yield* svc - .authorize({ + return yield* mapProviderAuthError( + svc.authorize({ providerID: ctx.params.providerID, method: ctx.payload.method, inputs: ctx.payload.inputs, - }) - .pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({})))) + }), + ) }) const authorizeRaw = Effect.fn("ProviderHttpApi.authorizeRaw")(function* (ctx: { @@ -59,7 +80,7 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider" }) { const body = yield* Effect.orDie(ctx.request.text) const payload = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ProviderAuth.AuthorizeInput))(body).pipe( - Effect.mapError(() => new HttpApiError.BadRequest({})), + Effect.mapError(() => new ProviderAuthApiError({ name: "BadRequest", data: {} })), ) // Match legacy route behavior: when authorize() resolves without a // result (e.g. no further redirect), serialize as JSON `null` instead @@ -72,13 +93,13 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider" params: { providerID: ProviderID } payload: ProviderAuth.CallbackInput }) { - yield* svc - .callback({ + yield* mapProviderAuthError( + svc.callback({ providerID: ctx.params.providerID, method: ctx.payload.method, code: ctx.payload.code, - }) - .pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({})))) + }), + ) return true }) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/session-errors.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/session-errors.ts index 98ac2b9ad6..0fef2e7763 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/session-errors.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/session-errors.ts @@ -2,8 +2,6 @@ import type { NotFoundError as StorageNotFoundError } from "@/storage/storage" import { Effect } from "effect" import * as ApiError from "../errors" -type StorageNotFound = InstanceType - -export function mapStorageNotFound(self: Effect.Effect) { - return self.pipe(Effect.mapError((error) => ApiError.notFound(error.data.message))) +export function mapStorageNotFound(self: Effect.Effect) { + return self.pipe(Effect.mapError((error) => ApiError.notFound(error.message))) } diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts index 99645f3da3..b12be2cfc2 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts @@ -1,5 +1,3 @@ -import * as InstanceState from "@/effect/instance-state" -import { InstanceRef, WorkspaceRef } from "@/effect/instance-ref" import { Agent } from "@/agent/agent" import { Bus } from "@/bus" import { Command } from "@/command" @@ -16,7 +14,6 @@ import { SessionStatus } from "@/session/status" import { SessionSummary } from "@/session/summary" import { Todo } from "@/session/todo" import { MessageID, PartID, SessionID } from "@/session/schema" -import { NotFoundError } from "@/storage/storage" import { NamedError } from "@opencode-ai/core/util/error" import { Cause, Effect, Option, Schema, Scope } from "effect" import * as Stream from "effect/Stream" @@ -71,15 +68,21 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", return Object.fromEntries(yield* statusSvc.list()) }) + const requireSession = Effect.fn("SessionHttpApi.requireSession")(function* (sessionID: SessionID) { + return yield* SessionError.mapStorageNotFound(session.get(sessionID)) + }) + const get = Effect.fn("SessionHttpApi.get")(function* (ctx: { params: { sessionID: SessionID } }) { - return yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID)) + return yield* requireSession(ctx.params.sessionID) }) const children = Effect.fn("SessionHttpApi.children")(function* (ctx: { params: { sessionID: SessionID } }) { + yield* requireSession(ctx.params.sessionID) return yield* session.children(ctx.params.sessionID) }) const todo = Effect.fn("SessionHttpApi.todo")(function* (ctx: { params: { sessionID: SessionID } }) { + yield* requireSession(ctx.params.sessionID) return yield* todoSvc.get(ctx.params.sessionID) }) @@ -102,16 +105,18 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", catch: () => new HttpApiError.BadRequest({}), }) } - yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID)) + yield* requireSession(ctx.params.sessionID) if (ctx.query.limit === undefined || ctx.query.limit === 0) { - return yield* session.messages({ sessionID: ctx.params.sessionID }) + return yield* SessionError.mapStorageNotFound(session.messages({ sessionID: ctx.params.sessionID })) } - const page = MessageV2.page({ - sessionID: ctx.params.sessionID, - limit: ctx.query.limit, - before: ctx.query.before, - }) + const page = yield* SessionError.mapStorageNotFound( + MessageV2.page({ + sessionID: ctx.params.sessionID, + limit: ctx.query.limit, + before: ctx.query.before, + }), + ) if (!page.cursor) return page.items const request = yield* HttpServerRequest.HttpServerRequest @@ -133,10 +138,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID; messageID: MessageID } }) { return yield* SessionError.mapStorageNotFound( - Effect.try({ - try: () => MessageV2.get({ sessionID: ctx.params.sessionID, messageID: ctx.params.messageID }), - catch: (error) => error, - }).pipe(Effect.catch((error) => (NotFoundError.isInstance(error) ? Effect.fail(error) : Effect.die(error)))), + MessageV2.get({ sessionID: ctx.params.sessionID, messageID: ctx.params.messageID }), ) }) @@ -169,7 +171,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID } payload: typeof UpdatePayload.Type }) { - const current = yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID)) + const current = yield* requireSession(ctx.params.sessionID) if (ctx.payload.title !== undefined) { yield* session.setTitle({ sessionID: ctx.params.sessionID, title: ctx.payload.title }) } @@ -182,7 +184,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", if (ctx.payload.time?.archived !== undefined) { yield* session.setArchived({ sessionID: ctx.params.sessionID, time: ctx.payload.time.archived }) } - return yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID)) + return yield* requireSession(ctx.params.sessionID) }) const fork = Effect.fn("SessionHttpApi.fork")(function* (ctx: { @@ -220,6 +222,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID } payload: typeof InitPayload.Type }) { + yield* requireSession(ctx.params.sessionID) yield* promptSvc .command({ sessionID: ctx.params.sessionID, @@ -238,23 +241,25 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", // ErrorMiddleware → NamedError.Unknown 500) instead of blanket-mapping // every failure to a 400 BadRequest. const share = Effect.fn("SessionHttpApi.share")(function* (ctx: { params: { sessionID: SessionID } }) { + yield* requireSession(ctx.params.sessionID) yield* shareSvc.share(ctx.params.sessionID).pipe(Effect.mapError(() => new HttpApiError.InternalServerError({}))) - return yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID)) + return yield* requireSession(ctx.params.sessionID) }) const unshare = Effect.fn("SessionHttpApi.unshare")(function* (ctx: { params: { sessionID: SessionID } }) { + yield* requireSession(ctx.params.sessionID) yield* shareSvc .unshare(ctx.params.sessionID) .pipe(Effect.mapError(() => new HttpApiError.InternalServerError({}))) - return yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID)) + return yield* requireSession(ctx.params.sessionID) }) const summarize = Effect.fn("SessionHttpApi.summarize")(function* (ctx: { params: { sessionID: SessionID } payload: typeof SummarizePayload.Type }) { - yield* revertSvc.cleanup(yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID))) - const messages = yield* session.messages({ sessionID: ctx.params.sessionID }) + yield* revertSvc.cleanup(yield* requireSession(ctx.params.sessionID)) + const messages = yield* SessionError.mapStorageNotFound(session.messages({ sessionID: ctx.params.sessionID })) const defaultAgent = yield* agentSvc.defaultAgent() const currentAgent = messages.findLast((message) => message.info.role === "user")?.info.agent ?? defaultAgent @@ -275,18 +280,13 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID } payload: typeof PromptPayload.Type }) { - const instance = yield* InstanceState.context - const workspace = yield* InstanceState.workspaceID + yield* requireSession(ctx.params.sessionID) const message = yield* promptSvc .prompt({ ...ctx.payload, sessionID: ctx.params.sessionID, }) - .pipe( - Effect.provideService(InstanceRef, instance), - Effect.provideService(WorkspaceRef, workspace), - Effect.mapError(() => new HttpApiError.BadRequest({})), - ) + .pipe(Effect.mapError(() => new HttpApiError.BadRequest({}))) return HttpServerResponse.stream(Stream.make(JSON.stringify(message)).pipe(Stream.encodeText), { contentType: "application/json", }) @@ -296,10 +296,13 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID } payload: typeof PromptPayload.Type }) { + yield* requireSession(ctx.params.sessionID) yield* promptSvc.prompt({ ...ctx.payload, sessionID: ctx.params.sessionID }).pipe( Effect.catchCause((cause) => Effect.gen(function* () { - yield* Effect.logError("prompt_async failed", { sessionID: ctx.params.sessionID, cause }) + yield* Effect.logError("prompt_async failed").pipe( + Effect.annotateLogs({ sessionID: ctx.params.sessionID, cause }), + ) yield* bus.publish(Session.Event.Error, { sessionID: ctx.params.sessionID, error: new NamedError.Unknown({ message: Cause.pretty(cause) }).toObject(), @@ -315,6 +318,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID } payload: typeof CommandPayload.Type }) { + yield* requireSession(ctx.params.sessionID) return yield* promptSvc .command({ ...ctx.payload, sessionID: ctx.params.sessionID }) .pipe(Effect.mapError(() => new HttpApiError.BadRequest({}))) @@ -324,6 +328,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID } payload: typeof ShellPayload.Type }) { + yield* requireSession(ctx.params.sessionID) return yield* promptSvc.shell({ ...ctx.payload, sessionID: ctx.params.sessionID }) }) @@ -331,17 +336,20 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID } payload: typeof RevertPayload.Type }) { + yield* requireSession(ctx.params.sessionID) return yield* revertSvc.revert({ sessionID: ctx.params.sessionID, ...ctx.payload }) }) const unrevert = Effect.fn("SessionHttpApi.unrevert")(function* (ctx: { params: { sessionID: SessionID } }) { + yield* requireSession(ctx.params.sessionID) return yield* revertSvc.unrevert({ sessionID: ctx.params.sessionID }) }) const permissionRespond = Effect.fn("SessionHttpApi.permissionRespond")(function* (ctx: { - params: { permissionID: PermissionID } + params: { sessionID: SessionID; permissionID: PermissionID } payload: typeof PermissionResponsePayload.Type }) { + yield* requireSession(ctx.params.sessionID) yield* permissionSvc.reply({ requestID: ctx.params.permissionID, reply: ctx.payload.response }) return true }) @@ -349,6 +357,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", const deleteMessage = Effect.fn("SessionHttpApi.deleteMessage")(function* (ctx: { params: { sessionID: SessionID; messageID: MessageID } }) { + yield* requireSession(ctx.params.sessionID) yield* runState.assertNotBusy(ctx.params.sessionID) yield* session.removeMessage(ctx.params) return true @@ -357,6 +366,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", const deletePart = Effect.fn("SessionHttpApi.deletePart")(function* (ctx: { params: { sessionID: SessionID; messageID: MessageID; partID: PartID } }) { + yield* requireSession(ctx.params.sessionID) yield* session.removePart(ctx.params) return true }) @@ -365,15 +375,14 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", params: { sessionID: SessionID; messageID: MessageID; partID: PartID } payload: typeof MessageV2.Part.Type }) { + yield* requireSession(ctx.params.sessionID) const payload = ctx.payload as MessageV2.Part if ( payload.id !== ctx.params.partID || payload.messageID !== ctx.params.messageID || payload.sessionID !== ctx.params.sessionID ) { - throw new Error( - `Part mismatch: body.id='${payload.id}' vs partID='${ctx.params.partID}', body.messageID='${payload.messageID}' vs messageID='${ctx.params.messageID}', body.sessionID='${payload.sessionID}' vs sessionID='${ctx.params.sessionID}'`, - ) + return yield* new HttpApiError.BadRequest({}) } return yield* session.updatePart(payload) }) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/v2.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2.ts index 55cb534581..b277e77016 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/v2.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2.ts @@ -1,6 +1,12 @@ +import { Catalog } from "@opencode-ai/core/catalog" import { SessionV2 } from "@/v2/session" import { Layer } from "effect" import { messageHandlers } from "./v2/message" +import { modelHandlers } from "./v2/model" +import { providerHandlers } from "./v2/provider" import { sessionHandlers } from "./v2/session" -export const v2Handlers = Layer.mergeAll(sessionHandlers, messageHandlers).pipe(Layer.provide(SessionV2.defaultLayer)) +export const v2Handlers = Layer.mergeAll(sessionHandlers, messageHandlers, modelHandlers, providerHandlers).pipe( + Layer.provide(Catalog.defaultLayer), + Layer.provide(SessionV2.defaultLayer), +) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/model.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/model.ts new file mode 100644 index 0000000000..7eb1b310b3 --- /dev/null +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/model.ts @@ -0,0 +1,12 @@ +import { Catalog } from "@opencode-ai/core/catalog" +import { Effect } from "effect" +import { HttpApiBuilder } from "effect/unstable/httpapi" +import { InstanceHttpApi } from "../../api" + +export const modelHandlers = HttpApiBuilder.group(InstanceHttpApi, "v2.model", (handlers) => + Effect.gen(function* () { + const catalog = yield* Catalog.Service + + return handlers.handle("models", () => catalog.model.available()) + }), +) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/provider.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/provider.ts new file mode 100644 index 0000000000..c19213f5bc --- /dev/null +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/v2/provider.ts @@ -0,0 +1,22 @@ +import { Catalog } from "@opencode-ai/core/catalog" +import { Effect } from "effect" +import { HttpApiBuilder } from "effect/unstable/httpapi" +import { InstanceHttpApi } from "../../api" +import { notFound } from "../../errors" + +export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "v2.provider", (handlers) => + Effect.gen(function* () { + const catalog = yield* Catalog.Service + + return handlers + .handle("providers", () => catalog.provider.available()) + .handle( + "provider", + Effect.fn(function* (ctx) { + return yield* catalog.provider + .get(ctx.params.providerID) + .pipe(Effect.catchTag("CatalogV2.ProviderNotFound", () => Effect.fail(notFound("Provider not found")))) + }), + ) + }), +) diff --git a/packages/opencode/src/server/routes/instance/httpapi/middleware/error.ts b/packages/opencode/src/server/routes/instance/httpapi/middleware/error.ts index 6f3c33a647..bb75f6602c 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/middleware/error.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/middleware/error.ts @@ -1,6 +1,5 @@ import { Provider } from "@/provider/provider" import { Session } from "@/session/session" -import { NotFoundError } from "@/storage/storage" import { iife } from "@/util/iife" import { NamedError } from "@opencode-ai/core/util/error" import * as Log from "@opencode-ai/core/util/log" @@ -28,10 +27,7 @@ export const errorLayer = HttpRouter.middleware<{ handles: unknown }>()((effect) return Effect.succeed( HttpServerResponse.jsonUnsafe(error.toObject(), { status: iife(() => { - if (error instanceof NotFoundError) return 404 if (error instanceof Provider.ModelNotFoundError) return 400 - if (error.name === "ProviderAuthValidationFailed") return 400 - if (error.name.startsWith("Worktree")) return 400 return 500 }), }), @@ -48,7 +44,7 @@ export const errorLayer = HttpRouter.middleware<{ handles: unknown }>()((effect) return Effect.succeed( HttpServerResponse.jsonUnsafe( new NamedError.Unknown({ - message: error instanceof Error && error.stack ? error.stack : String(error), + message: "Unexpected server error. Check server logs for details.", }).toObject(), { status: 500 }, ), diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 3ca4f074f9..3340e0fbe9 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -18,9 +18,9 @@ import { InstanceState } from "@/effect/instance-state" import { isOverflow as overflow, usable } from "./overflow" import { makeRuntime } from "@/effect/run-service" import { serviceUse } from "@/effect/service-use" +import { RuntimeFlags } from "@/effect/runtime-flags" import { SyncEvent } from "@/sync" import { SessionEvent } from "@/v2/session-event" -import { Flag } from "@opencode-ai/core/flag/flag" const log = Log.create({ service: "session.compaction" }) @@ -79,10 +79,12 @@ Rules: type Turn = { start: number end: number + id: MessageID } type Tail = { start: number + id: MessageID } type CompletedCompaction = { @@ -119,41 +121,19 @@ function completedCompactions(messages: MessageV2.WithParts[]) { }) } -function buildPrompt(input: { previousSummary?: string; context: string[]; tail?: string }) { - const source = input.tail - ? "the conversation history above and the serialized recent conversation tail below" - : "the conversation history above" +function buildPrompt(input: { previousSummary?: string; context: string[] }) { const anchor = input.previousSummary ? [ - `Update the anchored summary below using ${source}.`, + "Update the anchored summary below using the conversation history above.", "Preserve still-true details, remove stale details, and merge in the new facts.", "", input.previousSummary, "", ].join("\n") - : `Create a new anchored summary from ${source}.` - const tail = input.tail - ? [ - "Fold this serialized recent conversation tail into the summary; it is not provider message history.", - "", - input.tail, - "", - ].join("\n") - : undefined - return [anchor, ...(tail ? [tail] : []), SUMMARY_TEMPLATE, ...input.context].join("\n\n") + : "Create a new anchored summary from the conversation history above." + return [anchor, SUMMARY_TEMPLATE, ...input.context].join("\n\n") } -const serialize = Effect.fn("SessionCompaction.serialize")(function* (input: { - messages: MessageV2.WithParts[] - model: Provider.Model -}) { - const messages = yield* MessageV2.toModelMessagesEffect(input.messages, input.model, { - stripMedia: true, - toolOutputMaxChars: TOOL_OUTPUT_MAX_CHARS, - }) - return messages.length ? JSON.stringify(messages, null, 2) : undefined -}) - function preserveRecentBudget(input: { cfg: Config.Info; model: Provider.Model }) { return ( input.cfg.compaction?.preserve_recent_tokens ?? @@ -170,6 +150,7 @@ function turns(messages: MessageV2.WithParts[]) { result.push({ start: i, end: messages.length, + id: msg.info.id, }) } for (let i = 0; i < result.length - 1; i++) { @@ -196,6 +177,7 @@ function splitTurn(input: { if (size > input.budget) continue return { start, + id: input.messages[start]!.info.id, } satisfies Tail } return undefined @@ -239,6 +221,7 @@ export const layer: Layer.Layer< | SessionProcessor.Service | Provider.Service | SyncEvent.Service + | RuntimeFlags.Service > = Layer.effect( Service, Effect.gen(function* () { @@ -250,6 +233,7 @@ export const layer: Layer.Layer< const processors = yield* SessionProcessor.Service const provider = yield* Provider.Service const sync = yield* SyncEvent.Service + const flags = yield* RuntimeFlags.Service const isOverflow = Effect.fn("SessionCompaction.isOverflow")(function* (input: { tokens: MessageV2.Assistant["tokens"] @@ -262,7 +246,8 @@ export const layer: Layer.Layer< messages: MessageV2.WithParts[] model: Provider.Model }) { - return Token.estimate((yield* serialize(input)) ?? "") + const msgs = yield* MessageV2.toModelMessagesEffect(input.messages, input.model) + return Token.estimate(JSON.stringify(msgs)) }) const select = Effect.fn("SessionCompaction.select")(function* (input: { @@ -271,10 +256,10 @@ export const layer: Layer.Layer< model: Provider.Model }) { const limit = input.cfg.compaction?.tail_turns ?? DEFAULT_TAIL_TURNS - if (limit <= 0) return { head: input.messages, tail: [] } + if (limit <= 0) return { head: input.messages, tail_start_id: undefined } const budget = preserveRecentBudget({ cfg: input.cfg, model: input.model }) const all = turns(input.messages) - if (!all.length) return { head: input.messages, tail: [] } + if (!all.length) return { head: input.messages, tail_start_id: undefined } const recent = all.slice(-limit) const sizes = yield* Effect.forEach( recent, @@ -293,7 +278,7 @@ export const layer: Layer.Layer< const size = sizes[i] if (total + size <= budget) { total += size - keep = { start: turn.start } + keep = { start: turn.start, id: turn.id } continue } const remaining = budget - total @@ -309,10 +294,10 @@ export const layer: Layer.Layer< break } - if (!keep) return { head: input.messages, tail: [] } + if (!keep || keep.start === 0) return { head: input.messages, tail_start_id: undefined } return { head: input.messages.slice(0, keep.start), - tail: input.messages.slice(keep.start), + tail_start_id: keep.id, } }) @@ -423,10 +408,7 @@ export const layer: Layer.Layer< { sessionID: input.sessionID }, { context: [], prompt: undefined }, ) - const tailMessages = structuredClone(selected.tail) - yield* plugin.trigger("experimental.chat.messages.transform", {}, { messages: tailMessages }) - const tail = yield* serialize({ messages: tailMessages, model }) - const nextPrompt = compacting.prompt ?? buildPrompt({ previousSummary, context: compacting.context, tail }) + const nextPrompt = compacting.prompt ?? buildPrompt({ previousSummary, context: compacting.context }) const msgs = structuredClone(selected.head) yield* plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs }) const modelMessages = yield* MessageV2.toModelMessagesEffect(msgs, model, { @@ -493,6 +475,13 @@ export const layer: Layer.Layer< return "stop" } + if (compactionPart && selected.tail_start_id && compactionPart.tail_start_id !== selected.tail_start_id) { + yield* session.updatePart({ + ...compactionPart, + tail_start_id: selected.tail_start_id, + }) + } + if (result === "continue" && input.auto) { if (replay) { const original = replay.info @@ -578,16 +567,19 @@ export const layer: Layer.Layer< if (processor.message.error) return "stop" if (result === "continue") { const summary = summaryText( - (yield* session.messages({ sessionID: input.sessionID })).find((item) => item.info.id === msg.id) ?? { + (yield* session.messages({ sessionID: input.sessionID }).pipe(Effect.orDie)).find( + (item) => item.info.id === msg.id, + ) ?? { info: msg, parts: [], }, ) - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Compaction.Ended.Sync, { sessionID: input.sessionID, timestamp: DateTime.makeUnsafe(Date.now()), text: summary ?? "", + include: selected.tail_start_id, }) } yield* bus.publish(Event.Compacted, { sessionID: input.sessionID }) @@ -618,7 +610,7 @@ export const layer: Layer.Layer< auto: input.auto, overflow: input.overflow, }) - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Compaction.Started.Sync, { sessionID: input.sessionID, timestamp: DateTime.makeUnsafe(Date.now()), @@ -646,6 +638,7 @@ export const defaultLayer = Layer.suspend(() => Layer.provide(Bus.layer), Layer.provide(Config.defaultLayer), Layer.provide(SyncEvent.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), ), ) diff --git a/packages/opencode/src/session/llm.ts b/packages/opencode/src/session/llm.ts index c7990d1b35..c31545a3d6 100644 --- a/packages/opencode/src/session/llm.ts +++ b/packages/opencode/src/session/llm.ts @@ -19,7 +19,6 @@ import { Bus } from "@/bus" import { Wildcard } from "@/util/wildcard" import { SessionID } from "@/session/schema" import { Auth } from "@/auth" -import { Installation } from "@/installation" import { InstallationVersion } from "@opencode-ai/core/installation/version" import { EffectBridge } from "@/effect/bridge" import * as Option from "effect/Option" diff --git a/packages/opencode/src/session/message-error.ts b/packages/opencode/src/session/message-error.ts new file mode 100644 index 0000000000..bf40d45be0 --- /dev/null +++ b/packages/opencode/src/session/message-error.ts @@ -0,0 +1,14 @@ +import { Schema } from "effect" +import { NamedError } from "@opencode-ai/core/util/error" + +export const OutputLengthError = NamedError.create("MessageOutputLengthError", {}) + +export const AuthError = NamedError.create("ProviderAuthError", { + providerID: Schema.String, + message: Schema.String, +}) + +export const Shared = [AuthError.EffectSchema, NamedError.Unknown.EffectSchema, OutputLengthError.EffectSchema] as const +export const SharedSchema = Schema.Union(Shared) + +export * as MessageError from "./message-error" diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 4dae820382..869ef979f2 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -23,8 +23,10 @@ import type { Provider } from "@/provider/provider" import { ModelID, ProviderID } from "@/provider/schema" import { Effect, Schema, Types } from "effect" import { NonNegativeInt } from "@opencode-ai/core/schema" -import { namedSchemaError } from "@/util/named-schema-error" import * as EffectLogger from "@opencode-ai/core/effect/logger" +import { MessageError } from "./message-error" +import { AuthError, OutputLengthError } from "./message-error" +export { AuthError, OutputLengthError } from "./message-error" /** Error shape thrown by Bun's fetch() when gzip/br decompression fails mid-stream */ interface FetchDecompressionError extends Error { @@ -36,17 +38,12 @@ interface FetchDecompressionError extends Error { export const SYNTHETIC_ATTACHMENT_PROMPT = "Attached media from tool result:" export { isMedia } -export const OutputLengthError = namedSchemaError("MessageOutputLengthError", {}) -export const AbortedError = namedSchemaError("MessageAbortedError", { message: Schema.String }) -export const StructuredOutputError = namedSchemaError("StructuredOutputError", { +export const AbortedError = NamedError.create("MessageAbortedError", { message: Schema.String }) +export const StructuredOutputError = NamedError.create("StructuredOutputError", { message: Schema.String, retries: NonNegativeInt, }) -export const AuthError = namedSchemaError("ProviderAuthError", { - providerID: Schema.String, - message: Schema.String, -}) -export const APIError = namedSchemaError("APIError", { +export const APIError = NamedError.create("APIError", { message: Schema.String, statusCode: Schema.optional(NonNegativeInt), isRetryable: Schema.Boolean, @@ -55,7 +52,7 @@ export const APIError = namedSchemaError("APIError", { metadata: Schema.optional(Schema.Record(Schema.String, Schema.String)), }) export type APIError = Schema.Schema.Type -export const ContextOverflowError = namedSchemaError("ContextOverflowError", { +export const ContextOverflowError = NamedError.create("ContextOverflowError", { message: Schema.String, responseBody: Schema.optional(Schema.String), }) @@ -381,11 +378,7 @@ export type Part = | CompactionPart const AssistantErrorSchema = Schema.Union([ - AuthError.EffectSchema, - Schema.Struct({ name: Schema.Literal("UnknownError"), data: Schema.Struct({ message: Schema.String }) }).annotate({ - identifier: "UnknownError", - }), - OutputLengthError.EffectSchema, + ...MessageError.Shared, AbortedError.EffectSchema, StructuredOutputError.EffectSchema, ContextOverflowError.EffectSchema, @@ -779,13 +772,12 @@ export const toModelMessagesEffect = Effect.fnUntraced(function* ( return part.metadata?.anthropic?.signature != null }) for (const part of msg.parts) { - if (msg.info.summary && part.type !== "text") continue if (part.type === "text") { const text = part.text === "" && hasSignedReasoning ? " " : part.text assistantMessage.parts.push({ type: "text", text, - ...(differentModel || msg.info.summary ? {} : { providerMetadata: part.metadata }), + ...(differentModel ? {} : { providerMetadata: part.metadata }), }) } if (part.type === "step-start") @@ -927,7 +919,11 @@ export function toModelMessages( return Effect.runPromise(toModelMessagesEffect(input, model, options).pipe(Effect.provide(EffectLogger.layer))) } -export function page(input: { sessionID: SessionID; limit: number; before?: string }) { +export const page = Effect.fn("MessageV2.page")(function* (input: { + sessionID: SessionID + limit: number + before?: string +}) { const before = input.before ? cursor.decode(input.before) : undefined const where = before ? and(eq(MessageTable.session_id, input.sessionID), older(before)) @@ -945,7 +941,7 @@ export function page(input: { sessionID: SessionID; limit: number; before?: stri const row = Database.use((db) => db.select({ id: SessionTable.id }).from(SessionTable).where(eq(SessionTable.id, input.sessionID)).get(), ) - if (!row) throw new NotFoundError({ message: `Session not found: ${input.sessionID}` }) + if (!row) return yield* new NotFoundError({ message: `Session not found: ${input.sessionID}` }) return { items: [] as WithParts[], more: false, @@ -962,13 +958,19 @@ export function page(input: { sessionID: SessionID; limit: number; before?: stri more, cursor: more && tail ? cursor.encode({ id: tail.id, time: tail.time_created }) : undefined, } -} +}) export function* stream(sessionID: SessionID) { const size = 50 let before: string | undefined while (true) { - const next = page({ sessionID, limit: size, before }) + const next = Effect.runSync( + page({ sessionID, limit: size, before }).pipe( + Effect.catchIf(NotFoundError.isInstance, () => + Effect.succeed({ items: [] as WithParts[], more: false, cursor: undefined }), + ), + ), + ) if (next.items.length === 0) break for (let i = next.items.length - 1; i >= 0; i--) { yield next.items[i] @@ -993,7 +995,7 @@ export function parts(message_id: MessageID) { ) } -export function get(input: { sessionID: SessionID; messageID: MessageID }): WithParts { +export const get = Effect.fn("MessageV2.get")(function* (input: { sessionID: SessionID; messageID: MessageID }) { const row = Database.use((db) => db .select() @@ -1001,26 +1003,63 @@ export function get(input: { sessionID: SessionID; messageID: MessageID }): With .where(and(eq(MessageTable.id, input.messageID), eq(MessageTable.session_id, input.sessionID))) .get(), ) - if (!row) throw new NotFoundError({ message: `Message not found: ${input.messageID}` }) + if (!row) return yield* new NotFoundError({ message: `Message not found: ${input.messageID}` }) return { info: info(row), parts: parts(input.messageID), } -} +}) export function filterCompacted(msgs: Iterable) { const result = [] as WithParts[] const completed = new Set() + let retain: MessageID | undefined for (const msg of msgs) { result.push(msg) - if (msg.info.role === "user" && completed.has(msg.info.id)) { - if (msg.parts.some((item): item is CompactionPart => item.type === "compaction")) break + if (retain) { + if (msg.info.id === retain) break continue } + if (msg.info.role === "user" && completed.has(msg.info.id)) { + const part = msg.parts.find((item): item is CompactionPart => item.type === "compaction") + if (!part) continue + if (!part.tail_start_id) break + retain = part.tail_start_id + if (msg.info.id === retain) break + continue + } + if (msg.info.role === "user" && completed.has(msg.info.id) && msg.parts.some((part) => part.type === "compaction")) + break if (msg.info.role === "assistant" && msg.info.summary && msg.info.finish && !msg.info.error) completed.add(msg.info.parentID) } result.reverse() + const compactionIndex = result.findLastIndex( + (msg) => + msg.info.role === "user" && + msg.parts.some((item): item is CompactionPart => item.type === "compaction" && item.tail_start_id !== undefined), + ) + const compaction = result[compactionIndex] + const part = compaction?.parts.find( + (item): item is CompactionPart => item.type === "compaction" && item.tail_start_id !== undefined, + ) + const summaryIndex = compaction + ? result.findIndex( + (msg, index) => + index > compactionIndex && + msg.info.role === "assistant" && + msg.info.summary && + msg.info.parentID === compaction.info.id, + ) + : -1 + const tailIndex = part?.tail_start_id ? result.findIndex((msg) => msg.info.id === part.tail_start_id) : -1 + if (tailIndex >= 0 && tailIndex < compactionIndex && summaryIndex > compactionIndex) { + return [ + ...result.slice(compactionIndex, summaryIndex + 1), + ...result.slice(tailIndex, compactionIndex), + ...result.slice(summaryIndex + 1), + ] + } return result } diff --git a/packages/opencode/src/session/message.ts b/packages/opencode/src/session/message.ts index 16c010003a..39c842f94b 100644 --- a/packages/opencode/src/session/message.ts +++ b/packages/opencode/src/session/message.ts @@ -2,33 +2,9 @@ import { Schema } from "effect" import { SessionID } from "./schema" import { ModelID, ProviderID } from "../provider/schema" import { NonNegativeInt } from "@opencode-ai/core/schema" -import { namedSchemaError } from "@/util/named-schema-error" - -export const OutputLengthError = namedSchemaError("MessageOutputLengthError", {}) -export const AuthError = namedSchemaError("ProviderAuthError", { - providerID: Schema.String, - message: Schema.String, -}) - -const AuthErrorEffect = Schema.Struct({ - name: Schema.Literal("ProviderAuthError"), - data: Schema.Struct({ - providerID: Schema.String, - message: Schema.String, - }), -}) - -const OutputLengthErrorEffect = Schema.Struct({ - name: Schema.Literal("MessageOutputLengthError"), - data: Schema.Struct({}), -}) - -const UnknownErrorEffect = Schema.Struct({ - name: Schema.Literal("UnknownError"), - data: Schema.Struct({ - message: Schema.String, - }), -}) +import { MessageError } from "./message-error" +import { AuthError, OutputLengthError } from "./message-error" +export { AuthError, OutputLengthError } from "./message-error" export const ToolCall = Schema.Struct({ state: Schema.Literal("call"), @@ -124,7 +100,7 @@ export const Info = Schema.Struct({ created: NonNegativeInt, completed: Schema.optional(NonNegativeInt), }), - error: Schema.optional(Schema.Union([AuthErrorEffect, UnknownErrorEffect, OutputLengthErrorEffect])), + error: Schema.optional(MessageError.SharedSchema), sessionID: SessionID, tool: Schema.Record( Schema.String, diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index 579c4cc42c..9765175e9e 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -23,9 +23,10 @@ import * as Log from "@opencode-ai/core/util/log" import { isRecord } from "@/util/record" import { SyncEvent } from "@/sync" import { SessionEvent } from "@/v2/session-event" -import { Modelv2 } from "@/v2/model" +import { ModelV2 } from "@opencode-ai/core/model" +import { ProviderV2 } from "@opencode-ai/core/provider" import * as DateTime from "effect/DateTime" -import { Flag } from "@opencode-ai/core/flag/flag" +import { RuntimeFlags } from "@/effect/runtime-flags" const DOOM_LOOP_THRESHOLD = 3 const log = Log.create({ service: "session.processor" }) @@ -98,6 +99,7 @@ export const layer: Layer.Layer< | SessionSummary.Service | SessionStatus.Service | SyncEvent.Service + | RuntimeFlags.Service > = Layer.effect( Service, Effect.gen(function* () { @@ -114,6 +116,7 @@ export const layer: Layer.Layer< const status = yield* SessionStatus.Service const image = yield* Image.Service const sync = yield* SyncEvent.Service + const flags = yield* RuntimeFlags.Service const create = Effect.fn("SessionProcessor.create")(function* (input: Input) { // Pre-capture snapshot before the LLM stream starts. The AI SDK @@ -232,7 +235,7 @@ export const layer: Layer.Layer< case "reasoning-start": if (value.id in ctx.reasoningMap) return // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Reasoning.Started.Sync, { sessionID: ctx.sessionID, reasoningID: value.id, @@ -267,7 +270,7 @@ export const layer: Layer.Layer< case "reasoning-end": if (!(value.id in ctx.reasoningMap)) return // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Reasoning.Ended.Sync, { sessionID: ctx.sessionID, reasoningID: value.id, @@ -288,7 +291,7 @@ export const layer: Layer.Layer< throw new Error(`Tool call not allowed while generating summary: ${value.toolName}`) } // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Tool.Input.Started.Sync, { sessionID: ctx.sessionID, callID: value.id, @@ -319,7 +322,7 @@ export const layer: Layer.Layer< case "tool-input-end": { // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Tool.Input.Ended.Sync, { sessionID: ctx.sessionID, callID: value.id, @@ -336,7 +339,7 @@ export const layer: Layer.Layer< } const toolCall = yield* readToolCall(value.toolCallId) // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Tool.Called.Sync, { sessionID: ctx.sessionID, callID: value.toolCallId, @@ -402,10 +405,14 @@ export const layer: Layer.Layer< typeof attachment.mime === "string" && typeof attachment.url === "string", ) + // temporarily disabled + // const normalized = yield* Effect.forEach(toolAttachments, (attachment) => + // attachment.mime.startsWith("image/") + // ? image.normalize(attachment).pipe(Effect.exit) + // : Effect.succeed(Exit.succeed(attachment)), + // ) const normalized = yield* Effect.forEach(toolAttachments, (attachment) => - attachment.mime.startsWith("image/") - ? image.normalize(attachment).pipe(Effect.exit) - : Effect.succeed(Exit.succeed(attachment)), + Effect.succeed(Exit.succeed(attachment)), ) const omitted = normalized.filter(Exit.isFailure).length const attachments = normalized.filter(Exit.isSuccess).map((item) => item.value) @@ -414,11 +421,11 @@ export const layer: Layer.Layer< output: omitted === 0 ? value.output.output - : `${value.output.output}\n\n[${omitted} image${omitted === 1 ? "" : "s"} omitted: could not be resized below the inline image size limit.]`, + : `${value.output.output}\n\n[${omitted} image${omitted === 1 ? "" : "s"} omitted: could not be resized below the image size limit.]`, attachments: attachments?.length ? attachments : undefined, } // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Tool.Success.Sync, { sessionID: ctx.sessionID, callID: value.toolCallId, @@ -448,7 +455,7 @@ export const layer: Layer.Layer< case "tool-error": { const toolCall = yield* readToolCall(value.toolCallId) // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Tool.Failed.Sync, { sessionID: ctx.sessionID, callID: value.toolCallId, @@ -473,14 +480,14 @@ export const layer: Layer.Layer< if (!ctx.snapshot) ctx.snapshot = yield* snapshot.track() if (!ctx.assistantMessage.summary) { // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Step.Started.Sync, { sessionID: ctx.sessionID, agent: input.assistantMessage.agent, model: { - id: Modelv2.ID.make(ctx.model.id), - providerID: Modelv2.ProviderID.make(ctx.model.providerID), - variant: Modelv2.VariantID.make(input.assistantMessage.variant ?? "default"), + id: ModelV2.ID.make(ctx.model.id), + providerID: ProviderV2.ID.make(ctx.model.providerID), + variant: ModelV2.VariantID.make(input.assistantMessage.variant ?? "default"), }, snapshot: ctx.snapshot, timestamp: DateTime.makeUnsafe(Date.now()), @@ -505,7 +512,7 @@ export const layer: Layer.Layer< }) if (!ctx.assistantMessage.summary) { // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Step.Ended.Sync, { sessionID: ctx.sessionID, finish: value.finishReason, @@ -562,7 +569,7 @@ export const layer: Layer.Layer< case "text-start": if (!ctx.assistantMessage.summary) { // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Text.Started.Sync, { sessionID: ctx.sessionID, timestamp: DateTime.makeUnsafe(Date.now()), @@ -609,7 +616,7 @@ export const layer: Layer.Layer< )).text if (!ctx.assistantMessage.summary) { // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Text.Ended.Sync, { sessionID: ctx.sessionID, text: ctx.currentText.text, @@ -705,7 +712,7 @@ export const layer: Layer.Layer< } if (!ctx.assistantMessage.summary) { // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Step.Failed.Sync, { sessionID: ctx.sessionID, error: { @@ -759,7 +766,7 @@ export const layer: Layer.Layer< parse, set: (info) => { // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - const event = Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM + const event = flags.experimentalEventSystem ? sync.run(SessionEvent.Retried.Sync, { sessionID: ctx.sessionID, attempt: info.attempt, @@ -822,6 +829,7 @@ export const defaultLayer = Layer.suspend(() => Layer.provide(Bus.layer), Layer.provide(Config.defaultLayer), Layer.provide(SyncEvent.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), ), ) diff --git a/packages/opencode/src/session/projectors.ts b/packages/opencode/src/session/projectors.ts index 8b5cc2bdcc..3dd848c5bc 100644 --- a/packages/opencode/src/session/projectors.ts +++ b/packages/opencode/src/session/projectors.ts @@ -38,6 +38,7 @@ function applyUsage(db: TxOrDb, sessionID: Session.Info["id"], value: Usage, sig tokens_reasoning: sql`${SessionTable.tokens_reasoning} + ${value.tokens.reasoning * sign}`, tokens_cache_read: sql`${SessionTable.tokens_cache_read} + ${value.tokens.cache.read * sign}`, tokens_cache_write: sql`${SessionTable.tokens_cache_write} + ${value.tokens.cache.write * sign}`, + time_updated: sql`${SessionTable.time_updated}`, }) .where(eq(SessionTable.id, sessionID)) .run() @@ -110,7 +111,7 @@ export default [ const info = data.info const row = db .update(SessionTable) - .set(toPartialRow(info as Session.Patch)) + .set({ time_updated: sql`${SessionTable.time_updated}`, ...toPartialRow(info as Session.Patch) }) .where(eq(SessionTable.id, data.sessionID)) .returning() .get() diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 15246dac39..bc58fbdf35 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -23,7 +23,6 @@ import { ToolRegistry } from "@/tool/registry" import { ToolJsonSchema } from "@/tool/json-schema" import { MCP } from "../mcp" import { LSP } from "@/lsp/lsp" -import { Flag } from "@opencode-ai/core/flag/flag" import { ulid } from "ulid" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" @@ -51,10 +50,12 @@ import { InstanceState } from "@/effect/instance-state" import { TaskTool, type TaskPromptOps } from "@/tool/task" import { SessionRunState } from "./run-state" import { EffectBridge } from "@/effect/bridge" +import { RuntimeFlags } from "@/effect/runtime-flags" import { SyncEvent } from "@/sync" import { SessionEvent } from "@/v2/session-event" -import { Modelv2 } from "@/v2/model" -import { AgentAttachment, FileAttachment, ReferenceAttachment, Source } from "@/v2/session-prompt" +import { ModelV2 } from "@opencode-ai/core/model" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { AgentAttachment, FileAttachment, ReferenceAttachment, Source } from "@opencode-ai/core/session-prompt" import { Reference } from "@/reference/reference" import * as DateTime from "effect/DateTime" import { eq } from "@/storage/db" @@ -202,6 +203,7 @@ export const layer = Layer.effect( const llm = yield* LLM.Service const references = yield* Reference.Service const sync = yield* SyncEvent.Service + const flags = yield* RuntimeFlags.Service const runner = Effect.fn("SessionPrompt.runner")(function* () { return yield* EffectBridge.make() }) @@ -384,7 +386,7 @@ export const layer = Layer.effect( const userMessage = input.messages.findLast((msg) => msg.info.role === "user") if (!userMessage) return input.messages - if (!Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE) { + if (!flags.experimentalPlanMode) { if (input.agent.name === "plan") { userMessage.parts.push({ id: PartID.ascending(), @@ -955,7 +957,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the }, } yield* sessions.updatePart(part) - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Shell.Started.Sync, { sessionID: input.sessionID, timestamp: DateTime.makeUnsafe(started), @@ -978,7 +980,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the output += "\n\n" + ["", "User aborted the command", ""].join("\n") } const completed = Date.now() - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Shell.Ended.Sync, { sessionID: input.sessionID, timestamp: DateTime.makeUnsafe(completed), @@ -1077,14 +1079,16 @@ NOTE: At any point in time through this workflow you should feel free to ask the ...(current.model.variant && current.model.variant !== "default" ? { variant: current.model.variant } : {}), } } - const match = yield* sessions.findMessage(sessionID, (m) => m.info.role === "user" && !!m.info.model) + const match = yield* sessions + .findMessage(sessionID, (m) => m.info.role === "user" && !!m.info.model) + .pipe(Effect.orDie) if (Option.isSome(match) && match.value.info.role === "user") return match.value.info.model return yield* provider.defaultModel() }) const createUserMessage = Effect.fn("SessionPrompt.createUserMessage")(function* (input: PromptInput) { - const agentName = input.agent || (yield* agents.defaultAgent()) - const ag = yield* agents.get(agentName) + const agentName = input.agent + const ag = agentName ? yield* agents.get(agentName) : yield* agents.defaultInfo() if (!ag) { const available = (yield* agents.list()).filter((a) => !a.hidden).map((a) => a.name) const hint = available.length ? ` Available agents: ${available.join(", ")}` : "" @@ -1140,9 +1144,9 @@ NOTE: At any point in time through this workflow you should feel free to ask the sessionID: input.sessionID, timestamp: DateTime.makeUnsafe(info.time.created), model: { - id: Modelv2.ID.make(info.model.modelID), - providerID: Modelv2.ProviderID.make(info.model.providerID), - variant: Modelv2.VariantID.make(info.model.variant ?? "default"), + id: ModelV2.ID.make(info.model.modelID), + providerID: ProviderV2.ID.make(info.model.providerID), + variant: ModelV2.VariantID.make(info.model.variant ?? "default"), }, }) } @@ -1567,7 +1571,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the }, ) // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Prompted.Sync, { sessionID: input.sessionID, timestamp: DateTime.makeUnsafe(info.time.created), @@ -1581,7 +1585,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the } for (const text of nextPrompt.synthetic) { // TODO(v2): Temporary dual-write while migrating session messages to v2 events. - if (Flag.OPENCODE_EXPERIMENTAL_EVENT_SYSTEM) { + if (flags.experimentalEventSystem) { yield* sync.run(SessionEvent.Synthetic.Sync, { sessionID: input.sessionID, timestamp: DateTime.makeUnsafe(info.time.created), @@ -1615,9 +1619,9 @@ NOTE: At any point in time through this workflow you should feel free to ask the ) const lastAssistant = Effect.fnUntraced(function* (sessionID: SessionID) { - const match = yield* sessions.findMessage(sessionID, (m) => m.info.role !== "user") + const match = yield* sessions.findMessage(sessionID, (m) => m.info.role !== "user").pipe(Effect.orDie) if (Option.isSome(match)) return match.value - const msgs = yield* sessions.messages({ sessionID, limit: 1 }) + const msgs = yield* sessions.messages({ sessionID, limit: 1 }).pipe(Effect.orDie) if (msgs.length > 0) return msgs[0] throw new Error("Impossible") }) @@ -1875,7 +1879,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the yield* bus.publish(Session.Event.Error, { sessionID: input.sessionID, error: error.toObject() }) throw error } - const agentName = cmd.agent ?? input.agent ?? (yield* agents.defaultAgent()) + const agentName = cmd.agent ?? input.agent const raw = input.arguments.match(argsRegex) ?? [] const args = raw.map((arg) => arg.replace(quoteTrimRegex, "")) @@ -1928,7 +1932,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the yield* getModel(taskModel.providerID, taskModel.modelID, input.sessionID) - const agent = yield* agents.get(agentName) + const agent = agentName ? yield* agents.get(agentName) : yield* agents.defaultInfo() if (!agent) { const available = (yield* agents.list()).filter((a) => !a.hidden).map((a) => a.name) const hint = available.length ? ` Available agents: ${available.join(", ")}` : "" @@ -1952,7 +1956,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the ] : [...templateParts, ...(input.parts ?? [])] - const userAgent = isSubtask ? (input.agent ?? (yield* agents.defaultAgent())) : agentName + const userAgent = isSubtask ? (input.agent ?? (yield* agents.defaultInfo()).name) : agent.name const userModel = isSubtask ? input.model ? Provider.parseModel(input.model) @@ -2022,6 +2026,7 @@ export const defaultLayer = Layer.suspend(() => Bus.layer, CrossSpawnSpawner.defaultLayer, SyncEvent.defaultLayer, + RuntimeFlags.defaultLayer, ), ), ), diff --git a/packages/opencode/src/session/retry.ts b/packages/opencode/src/session/retry.ts index 1f73dee31f..463bc27a95 100644 --- a/packages/opencode/src/session/retry.ts +++ b/packages/opencode/src/session/retry.ts @@ -2,6 +2,7 @@ import type { NamedError } from "@opencode-ai/core/util/error" import { Cause, Clock, Duration, Effect, Schedule } from "effect" import { MessageV2 } from "./message-v2" import { iife } from "@/util/iife" +import { isRecord } from "@/util/record" export type Err = ReturnType @@ -121,7 +122,7 @@ export function retryable(error: Err, provider: string) { } // Check for rate limit patterns in plain text error messages - const msg = error.data?.message + const msg = isRecord(error.data) ? error.data.message : undefined if (typeof msg === "string") { const lower = msg.toLowerCase() if ( @@ -133,7 +134,7 @@ export function retryable(error: Err, provider: string) { } } - const json = parseJSON(error.data?.message) + const json = parseJSON(msg) if (!json || typeof json !== "object") return undefined const code = typeof json.code === "string" ? json.code : "" diff --git a/packages/opencode/src/session/revert.ts b/packages/opencode/src/session/revert.ts index ef9089c949..8ba7b265b9 100644 --- a/packages/opencode/src/session/revert.ts +++ b/packages/opencode/src/session/revert.ts @@ -40,7 +40,7 @@ export const layer = Layer.effect( const revert = Effect.fn("SessionRevert.revert")(function* (input: RevertInput) { yield* state.assertNotBusy(input.sessionID) - const all = yield* sessions.messages({ sessionID: input.sessionID }) + const all = yield* sessions.messages({ sessionID: input.sessionID }).pipe(Effect.orDie) let lastUser: MessageV2.User | undefined const session = yield* sessions.get(input.sessionID).pipe(Effect.orDie) @@ -103,7 +103,7 @@ export const layer = Layer.effect( const cleanup = Effect.fn("SessionRevert.cleanup")(function* (session: Session.Info) { if (!session.revert) return const sessionID = session.id - const msgs = yield* sessions.messages({ sessionID }) + const msgs = yield* sessions.messages({ sessionID }).pipe(Effect.orDie) const messageID = session.revert.messageID const remove = [] as MessageV2.WithParts[] let target: MessageV2.WithParts | undefined diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index eff027579a..85486480aa 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -4,7 +4,6 @@ import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" import { Decimal } from "decimal.js" import { type ProviderMetadata, type LanguageModelUsage } from "ai" -import { Flag } from "@opencode-ai/core/flag/flag" import { InstallationVersion } from "@opencode-ai/core/installation/version" import { Database } from "@/storage/db" @@ -38,6 +37,7 @@ import { Permission } from "@/permission" import { Global } from "@opencode-ai/core/global" import { Effect, Layer, Option, Context, Schema, Types } from "effect" import { NonNegativeInt, optionalOmitUndefined } from "@opencode-ai/core/schema" +import { RuntimeFlags } from "@/effect/runtime-flags" const log = Log.create({ service: "session" }) @@ -418,10 +418,14 @@ export const getUsage = (input: { model: Provider.Model; usage: LanguageModelUsa }, } + const contextTokens = inputTokens const costInfo = - input.model.cost?.experimentalOver200K && tokens.input + tokens.cache.read > 200_000 + input.model.cost?.tiers + ?.filter((item) => item.tier.type === "context" && contextTokens > item.tier.size) + .sort((a, b) => b.tier.size - a.tier.size)[0] ?? + (input.model.cost?.experimentalOver200K && contextTokens > 200_000 ? input.model.cost.experimentalOver200K - : input.model.cost + : input.model.cost) return { cost: safe( new Decimal(0) @@ -444,7 +448,7 @@ export class BusyError extends Error { } } -export type NotFound = InstanceType +export type NotFound = NotFoundError export interface Interface { readonly list: (input?: ListInput) => Effect.Effect @@ -470,7 +474,7 @@ export interface Interface { readonly clearRevert: (sessionID: SessionID) => Effect.Effect readonly setSummary: (input: { sessionID: SessionID; summary: Info["summary"] }) => Effect.Effect readonly diff: (sessionID: SessionID) => Effect.Effect - readonly messages: (input: { sessionID: SessionID; limit?: number }) => Effect.Effect + readonly messages: (input: { sessionID: SessionID; limit?: number }) => Effect.Effect readonly children: (parentID: SessionID) => Effect.Effect readonly remove: (sessionID: SessionID) => Effect.Effect readonly updateMessage: (msg: T) => Effect.Effect @@ -493,7 +497,7 @@ export interface Interface { readonly findMessage: ( sessionID: SessionID, predicate: (msg: MessageV2.WithParts) => boolean, - ) => Effect.Effect> + ) => Effect.Effect, NotFound> } export class Service extends Context.Service()("@opencode/Session") {} @@ -503,12 +507,17 @@ export type Patch = Types.DeepMutable["dat const db = (fn: (d: Parameters[0] extends (trx: infer D) => any ? D : never) => T) => Effect.sync(() => Database.use(fn)) -export const layer: Layer.Layer = Layer.effect( +export const layer: Layer.Layer< + Service, + never, + Bus.Service | Storage.Service | SyncEvent.Service | RuntimeFlags.Service +> = Layer.effect( Service, Effect.gen(function* () { const bus = yield* Bus.Service const storage = yield* Storage.Service const sync = yield* SyncEvent.Service + const flags = yield* RuntimeFlags.Service const createNext = Effect.fn("Session.createNext")(function* (input: { id?: SessionID @@ -546,7 +555,7 @@ export const layer: Layer.Layer [])) }) - const messages = Effect.fn("Session.messages")(function* (input: { sessionID: SessionID; limit?: number }) { + const messages: Interface["messages"] = Effect.fn("Session.messages")(function* (input) { if (input.limit) { - return MessageV2.page({ sessionID: input.sessionID, limit: input.limit }).items + return (yield* MessageV2.page({ sessionID: input.sessionID, limit: input.limit })).items } - return Array.from(MessageV2.stream(input.sessionID)).reverse() + + const size = 50 + const result = [] as MessageV2.WithParts[] + let before: string | undefined + while (true) { + const page = yield* MessageV2.page({ sessionID: input.sessionID, limit: size, before }) + if (page.items.length === 0) break + for (let i = page.items.length - 1; i >= 0; i--) { + const item = page.items[i] + if (item) result.push(item) + } + if (!page.more || !page.cursor) break + before = page.cursor + } + return result.reverse() }) const removeMessage = Effect.fn("Session.removeMessage")(function* (input: { @@ -795,12 +820,18 @@ export const layer: Layer.Layer boolean, - ) { - for (const item of MessageV2.stream(sessionID)) { - if (predicate(item)) return Option.some(item) + const findMessage: Interface["findMessage"] = Effect.fn("Session.findMessage")(function* (sessionID, predicate) { + const size = 50 + let before: string | undefined + while (true) { + const page = yield* MessageV2.page({ sessionID, limit: size, before }) + if (page.items.length === 0) break + for (let i = page.items.length - 1; i >= 0; i--) { + const item = page.items[i] + if (item && predicate(item)) return Option.some(item) + } + if (!page.more || !page.cursor) break + before = page.cursor } return Option.none() }) @@ -836,11 +867,13 @@ export const defaultLayer = layer.pipe( Layer.provide(Bus.layer), Layer.provide(Storage.defaultLayer), Layer.provide(SyncEvent.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), ) function* listByProject( input: ListInput & { projectID: ProjectID + experimentalWorkspaces: boolean }, ) { const conditions = [eq(SessionTable.project_id, input.projectID)] @@ -858,7 +891,7 @@ function* listByProject( : or(...conds)!, ) } - } else if (input.scope !== "project" && !Flag.OPENCODE_EXPERIMENTAL_WORKSPACES) { + } else if (input.scope !== "project" && !input.experimentalWorkspaces) { if (input.directory) { conditions.push(eq(SessionTable.directory, input.directory)) } diff --git a/packages/opencode/src/session/summary.ts b/packages/opencode/src/session/summary.ts index c03fc32695..aa4b8719bc 100644 --- a/packages/opencode/src/session/summary.ts +++ b/packages/opencode/src/session/summary.ts @@ -102,7 +102,7 @@ export const layer = Layer.effect( sessionID: SessionID messageID: MessageID }) { - const all = yield* sessions.messages({ sessionID: input.sessionID }) + const all = yield* sessions.messages({ sessionID: input.sessionID }).pipe(Effect.orDie) if (!all.length) return const diffs = yield* computeDiff({ messages: all }) diff --git a/packages/opencode/src/share/share-next.ts b/packages/opencode/src/share/share-next.ts index 384027436f..a386211dc6 100644 --- a/packages/opencode/src/share/share-next.ts +++ b/packages/opencode/src/share/share-next.ts @@ -272,7 +272,7 @@ export const layer = Layer.effect( log.info("full sync", { sessionID }) const info = yield* session.get(sessionID) const diffs = yield* session.diff(sessionID) - const messages = yield* Effect.sync(() => Array.from(MessageV2.stream(sessionID))) + const messages = yield* session.messages({ sessionID }) const models = yield* Effect.forEach( Array.from( new Map( diff --git a/packages/opencode/src/skill/index.ts b/packages/opencode/src/skill/index.ts index a0cc383d0f..59dfeb0804 100644 --- a/packages/opencode/src/skill/index.ts +++ b/packages/opencode/src/skill/index.ts @@ -1,6 +1,5 @@ import path from "path" import { pathToFileURL } from "url" -import z from "zod" import { Effect, Layer, Context, Schema } from "effect" import { NamedError } from "@opencode-ai/core/util/error" import type { Agent } from "@/agent/agent" @@ -16,6 +15,7 @@ import { Glob } from "@opencode-ai/core/util/glob" import * as Log from "@opencode-ai/core/util/log" import { Discovery } from "./discovery" import CUSTOMIZE_OPENCODE_SKILL_BODY from "./prompt/customize-opencode.md" with { type: "text" } +import { isRecord } from "@/util/record" const log = Log.create({ service: "skill" }) const CLAUDE_EXTERNAL_DIR = ".claude" @@ -41,23 +41,33 @@ export const Info = Schema.Struct({ }) export type Info = Schema.Schema.Type -export const InvalidError = NamedError.create( - "SkillInvalidError", - z.object({ - path: z.string(), - message: z.string().optional(), - issues: z.custom().optional(), +const Issue = Schema.StructWithRest( + Schema.Struct({ + message: Schema.String, + path: Schema.Array(Schema.String), }), + [Schema.Record(Schema.String, Schema.Unknown)], ) -export const NameMismatchError = NamedError.create( - "SkillNameMismatchError", - z.object({ - path: z.string(), - expected: z.string(), - actual: z.string(), - }), -) +function isSkillFrontmatter(data: unknown): data is { name: string; description?: string } { + return ( + isRecord(data) && + typeof data.name === "string" && + (data.description === undefined || typeof data.description === "string") + ) +} + +export const InvalidError = NamedError.create("SkillInvalidError", { + path: Schema.String, + message: Schema.optional(Schema.String), + issues: Schema.optional(Schema.Array(Issue)), +}) + +export const NameMismatchError = NamedError.create("SkillNameMismatchError", { + path: Schema.String, + expected: Schema.String, + actual: Schema.String, +}) type State = { skills: Record @@ -101,21 +111,20 @@ const add = Effect.fnUntraced(function* (state: State, match: string, bus: Bus.I if (!md) return - const parsed = z.object({ name: z.string(), description: z.string().optional() }).safeParse(md.data) - if (!parsed.success) return + if (!isSkillFrontmatter(md.data)) return - if (state.skills[parsed.data.name]) { + if (state.skills[md.data.name]) { log.warn("duplicate skill name", { - name: parsed.data.name, - existing: state.skills[parsed.data.name].location, + name: md.data.name, + existing: state.skills[md.data.name].location, duplicate: match, }) } state.dirs.add(path.dirname(match)) - state.skills[parsed.data.name] = { - name: parsed.data.name, - description: parsed.data.description, + state.skills[md.data.name] = { + name: md.data.name, + description: md.data.description, location: match, content: md.content, } diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts index 51fd267d54..f974a457ad 100644 --- a/packages/opencode/src/snapshot/index.ts +++ b/packages/opencode/src/snapshot/index.ts @@ -1,8 +1,8 @@ -import { Cause, Duration, Effect, Layer, Schedule, Schema, Semaphore, Context, Stream } from "effect" +import { Cause, Duration, Effect, Layer, Schedule, Schema, Semaphore, Context } from "effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { formatPatch, structuredPatch } from "diff" import path from "path" -import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { AppProcess } from "@opencode-ai/core/process" import { InstanceState } from "@/effect/instance-state" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { Hash } from "@opencode-ai/core/util/hash" @@ -55,417 +55,377 @@ export interface Interface { export class Service extends Context.Service()("@opencode/Snapshot") {} -export const layer: Layer.Layer< - Service, - never, - AppFileSystem.Service | ChildProcessSpawner.ChildProcessSpawner | Config.Service -> = Layer.effect( - Service, - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - const spawner = yield* ChildProcessSpawner.ChildProcessSpawner - const config = yield* Config.Service - const locks = new Map() +export const layer: Layer.Layer = + Layer.effect( + Service, + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const appProcess = yield* AppProcess.Service + const config = yield* Config.Service + const locks = new Map() - const lock = (key: string) => { - const hit = locks.get(key) - if (hit) return hit + const lock = (key: string) => { + const hit = locks.get(key) + if (hit) return hit - const next = Semaphore.makeUnsafe(1) - locks.set(key, next) - return next - } + const next = Semaphore.makeUnsafe(1) + locks.set(key, next) + return next + } - const state = yield* InstanceState.make( - Effect.fn("Snapshot.state")(function* (ctx) { - const state = { - directory: ctx.directory, - worktree: ctx.worktree, - gitdir: path.join(Global.Path.data, "snapshot", ctx.project.id, Hash.fast(ctx.worktree)), - vcs: ctx.project.vcs, - } + const state = yield* InstanceState.make( + Effect.fn("Snapshot.state")(function* (ctx) { + const state = { + directory: ctx.directory, + worktree: ctx.worktree, + gitdir: path.join(Global.Path.data, "snapshot", ctx.project.id, Hash.fast(ctx.worktree)), + vcs: ctx.project.vcs, + } - const args = (cmd: string[]) => ["--git-dir", state.gitdir, "--work-tree", state.worktree, ...cmd] + const args = (cmd: string[]) => ["--git-dir", state.gitdir, "--work-tree", state.worktree, ...cmd] - const enc = new TextEncoder() - const feed = (list: string[]) => Stream.make(enc.encode(list.join("\0") + "\0")) + const feed = (list: string[]) => list.join("\0") + "\0" - const git = Effect.fnUntraced( - function* ( - cmd: string[], - opts?: { cwd?: string; env?: Record; stdin?: ChildProcess.CommandInput }, - ) { - const proc = ChildProcess.make("git", cmd, { - cwd: opts?.cwd, - env: opts?.env, - extendEnv: true, - stdin: opts?.stdin, + const git = Effect.fnUntraced( + function* (cmd: string[], opts?: { cwd?: string; env?: Record; stdin?: string }) { + const result = yield* appProcess.run( + ChildProcess.make("git", cmd, { cwd: opts?.cwd, env: opts?.env, extendEnv: true }), + { stdin: opts?.stdin }, + ) + return { + code: ChildProcessSpawner.ExitCode(result.exitCode), + text: result.stdout.toString("utf8"), + stderr: result.stderr.toString("utf8"), + } satisfies GitResult + }, + Effect.catch((err) => + Effect.succeed({ + code: ChildProcessSpawner.ExitCode(1), + text: "", + stderr: err instanceof Error ? err.message : String(err), + }), + ), + ) + + const ignore = Effect.fnUntraced(function* (files: string[]) { + if (!files.length) return new Set() + const check = yield* git( + [ + ...quote, + "--git-dir", + path.join(state.worktree, ".git"), + "--work-tree", + state.worktree, + "check-ignore", + "--no-index", + "--stdin", + "-z", + ], + { + cwd: state.directory, + stdin: feed(files), + }, + ) + if (check.code !== 0 && check.code !== 1) return new Set() + return new Set(check.text.split("\0").filter(Boolean)) + }) + + const drop = Effect.fnUntraced(function* (files: string[]) { + if (!files.length) return + yield* git( + [ + ...cfg, + ...args(["rm", "--cached", "-f", "--ignore-unmatch", "--pathspec-from-file=-", "--pathspec-file-nul"]), + ], + { + cwd: state.directory, + stdin: feed(files), + }, + ) + }) + + const stage = Effect.fnUntraced(function* (files: string[]) { + if (!files.length) return + const result = yield* git( + [...cfg, ...args(["add", "--all", "--sparse", "--pathspec-from-file=-", "--pathspec-file-nul"])], + { + cwd: state.directory, + stdin: feed(files), + }, + ) + if (result.code === 0) return + log.warn("failed to add snapshot files", { + exitCode: result.code, + stderr: result.stderr, }) - const handle = yield* spawner.spawn(proc) - const [text, stderr] = yield* Effect.all( - [Stream.mkString(Stream.decodeText(handle.stdout)), Stream.mkString(Stream.decodeText(handle.stderr))], + }) + + const exists = (file: string) => fs.exists(file).pipe(Effect.orDie) + const read = (file: string) => fs.readFileString(file).pipe(Effect.catch(() => Effect.succeed(""))) + const remove = (file: string) => fs.remove(file).pipe(Effect.catch(() => Effect.void)) + const locked = (fx: Effect.Effect) => lock(state.gitdir).withPermits(1)(fx) + + const enabled = Effect.fnUntraced(function* () { + if (state.vcs !== "git") return false + return (yield* config.get()).snapshot !== false + }) + + const excludes = Effect.fnUntraced(function* () { + const result = yield* git(["rev-parse", "--path-format=absolute", "--git-path", "info/exclude"], { + cwd: state.worktree, + }) + const file = result.text.trim() + if (!file) return + if (!(yield* exists(file))) return + return file + }) + + const sync = Effect.fnUntraced(function* (list: string[] = []) { + const file = yield* excludes() + const target = path.join(state.gitdir, "info", "exclude") + const text = [ + file ? (yield* read(file)).trimEnd() : "", + ...list.map((item) => `/${item.replaceAll("\\", "/")}`), + ] + .filter(Boolean) + .join("\n") + yield* fs.ensureDir(path.join(state.gitdir, "info")).pipe(Effect.orDie) + yield* fs.writeFileString(target, text ? `${text}\n` : "").pipe(Effect.orDie) + }) + + const add = Effect.fnUntraced(function* () { + yield* sync() + const [diff, other] = yield* Effect.all( + [ + git([...quote, ...args(["diff-files", "--name-only", "-z", "--", "."])], { + cwd: state.directory, + }), + git([...quote, ...args(["ls-files", "--others", "--exclude-standard", "-z", "--", "."])], { + cwd: state.directory, + }), + ], { concurrency: 2 }, ) - const code = yield* handle.exitCode - return { code, text, stderr } satisfies GitResult - }, - Effect.scoped, - Effect.catch((err) => - Effect.succeed({ - code: ChildProcessSpawner.ExitCode(1), - text: "", - stderr: err instanceof Error ? err.message : String(err), - }), - ), - ) + if (diff.code !== 0 || other.code !== 0) { + log.warn("failed to list snapshot files", { + diffCode: diff.code, + diffStderr: diff.stderr, + otherCode: other.code, + otherStderr: other.stderr, + }) + return + } - const ignore = Effect.fnUntraced(function* (files: string[]) { - if (!files.length) return new Set() - const check = yield* git( - [ - ...quote, - "--git-dir", - path.join(state.worktree, ".git"), - "--work-tree", - state.worktree, - "check-ignore", - "--no-index", - "--stdin", - "-z", - ], - { - cwd: state.directory, - stdin: feed(files), - }, - ) - if (check.code !== 0 && check.code !== 1) return new Set() - return new Set(check.text.split("\0").filter(Boolean)) - }) + const tracked = diff.text.split("\0").filter(Boolean) + const untracked = other.text.split("\0").filter(Boolean) + const all = Array.from(new Set([...tracked, ...untracked])) + if (!all.length) return - const drop = Effect.fnUntraced(function* (files: string[]) { - if (!files.length) return - yield* git( - [ - ...cfg, - ...args(["rm", "--cached", "-f", "--ignore-unmatch", "--pathspec-from-file=-", "--pathspec-file-nul"]), - ], - { - cwd: state.directory, - stdin: feed(files), - }, - ) - }) + // Resolve source-repo ignore rules against the exact candidate set. + // --no-index keeps this pattern-based even when a path is already tracked. + const ignored = yield* ignore(all) - const stage = Effect.fnUntraced(function* (files: string[]) { - if (!files.length) return - const result = yield* git( - [...cfg, ...args(["add", "--all", "--sparse", "--pathspec-from-file=-", "--pathspec-file-nul"])], - { - cwd: state.directory, - stdin: feed(files), - }, - ) - if (result.code === 0) return - log.warn("failed to add snapshot files", { - exitCode: result.code, - stderr: result.stderr, + // Remove newly-ignored files from snapshot index to prevent re-adding + if (ignored.size > 0) { + const ignoredFiles = Array.from(ignored) + log.info("removing gitignored files from snapshot", { count: ignoredFiles.length }) + yield* drop(ignoredFiles) + } + + const allow = all.filter((item) => !ignored.has(item)) + if (!allow.length) return + + const large = new Set( + (yield* Effect.all( + allow.map((item) => + fs + .stat(path.join(state.directory, item)) + .pipe(Effect.catch(() => Effect.void)) + .pipe( + Effect.map((stat) => { + if (!stat || stat.type !== "File") return + const size = typeof stat.size === "bigint" ? Number(stat.size) : stat.size + return size > limit ? item : undefined + }), + ), + ), + { concurrency: 8 }, + )).filter((item): item is string => Boolean(item)), + ) + const block = new Set(untracked.filter((item) => large.has(item))) + yield* sync(Array.from(block)) + // Stage only the allowed candidate paths so snapshot updates stay scoped. + yield* stage(allow.filter((item) => !block.has(item))) }) - }) - const exists = (file: string) => fs.exists(file).pipe(Effect.orDie) - const read = (file: string) => fs.readFileString(file).pipe(Effect.catch(() => Effect.succeed(""))) - const remove = (file: string) => fs.remove(file).pipe(Effect.catch(() => Effect.void)) - const locked = (fx: Effect.Effect) => lock(state.gitdir).withPermits(1)(fx) - - const enabled = Effect.fnUntraced(function* () { - if (state.vcs !== "git") return false - return (yield* config.get()).snapshot !== false - }) - - const excludes = Effect.fnUntraced(function* () { - const result = yield* git(["rev-parse", "--path-format=absolute", "--git-path", "info/exclude"], { - cwd: state.worktree, + const cleanup = Effect.fnUntraced(function* () { + return yield* locked( + Effect.gen(function* () { + if (!(yield* enabled())) return + if (!(yield* exists(state.gitdir))) return + const result = yield* git(args(["gc", `--prune=${prune}`]), { cwd: state.directory }) + if (result.code !== 0) { + log.warn("cleanup failed", { + exitCode: result.code, + stderr: result.stderr, + }) + return + } + log.info("cleanup", { prune }) + }), + ) }) - const file = result.text.trim() - if (!file) return - if (!(yield* exists(file))) return - return file - }) - const sync = Effect.fnUntraced(function* (list: string[] = []) { - const file = yield* excludes() - const target = path.join(state.gitdir, "info", "exclude") - const text = [ - file ? (yield* read(file)).trimEnd() : "", - ...list.map((item) => `/${item.replaceAll("\\", "/")}`), - ] - .filter(Boolean) - .join("\n") - yield* fs.ensureDir(path.join(state.gitdir, "info")).pipe(Effect.orDie) - yield* fs.writeFileString(target, text ? `${text}\n` : "").pipe(Effect.orDie) - }) - - const add = Effect.fnUntraced(function* () { - yield* sync() - const [diff, other] = yield* Effect.all( - [ - git([...quote, ...args(["diff-files", "--name-only", "-z", "--", "."])], { - cwd: state.directory, + const track = Effect.fnUntraced(function* () { + return yield* locked( + Effect.gen(function* () { + if (!(yield* enabled())) return + const existed = yield* exists(state.gitdir) + yield* fs.ensureDir(state.gitdir).pipe(Effect.orDie) + if (!existed) { + yield* git(["init"], { + env: { GIT_DIR: state.gitdir, GIT_WORK_TREE: state.worktree }, + }) + yield* git(["--git-dir", state.gitdir, "config", "core.autocrlf", "false"]) + yield* git(["--git-dir", state.gitdir, "config", "core.longpaths", "true"]) + yield* git(["--git-dir", state.gitdir, "config", "core.symlinks", "true"]) + yield* git(["--git-dir", state.gitdir, "config", "core.fsmonitor", "false"]) + log.info("initialized") + } + yield* add() + const result = yield* git(args(["write-tree"]), { cwd: state.directory }) + const hash = result.text.trim() + log.info("tracking", { hash, cwd: state.directory, git: state.gitdir }) + return hash }), - git([...quote, ...args(["ls-files", "--others", "--exclude-standard", "-z", "--", "."])], { - cwd: state.directory, + ) + }) + + const patch = Effect.fnUntraced(function* (hash: string) { + return yield* locked( + Effect.gen(function* () { + yield* add() + const result = yield* git( + [...quote, ...args(["diff", "--cached", "--no-ext-diff", "--name-only", hash, "--", "."])], + { + cwd: state.directory, + }, + ) + if (result.code !== 0) { + log.warn("failed to get diff", { hash, exitCode: result.code }) + return { hash, files: [] } + } + const files = result.text + .trim() + .split("\n") + .map((x) => x.trim()) + .filter(Boolean) + + // Hide ignored-file removals from the user-facing patch output. + const ignored = yield* ignore(files) + + return { + hash, + files: files + .filter((item) => !ignored.has(item)) + .map((x) => path.join(state.worktree, x).replaceAll("\\", "/")), + } }), - ], - { concurrency: 2 }, - ) - if (diff.code !== 0 || other.code !== 0) { - log.warn("failed to list snapshot files", { - diffCode: diff.code, - diffStderr: diff.stderr, - otherCode: other.code, - otherStderr: other.stderr, - }) - return - } + ) + }) - const tracked = diff.text.split("\0").filter(Boolean) - const untracked = other.text.split("\0").filter(Boolean) - const all = Array.from(new Set([...tracked, ...untracked])) - if (!all.length) return - - // Resolve source-repo ignore rules against the exact candidate set. - // --no-index keeps this pattern-based even when a path is already tracked. - const ignored = yield* ignore(all) - - // Remove newly-ignored files from snapshot index to prevent re-adding - if (ignored.size > 0) { - const ignoredFiles = Array.from(ignored) - log.info("removing gitignored files from snapshot", { count: ignoredFiles.length }) - yield* drop(ignoredFiles) - } - - const allow = all.filter((item) => !ignored.has(item)) - if (!allow.length) return - - const large = new Set( - (yield* Effect.all( - allow.map((item) => - fs - .stat(path.join(state.directory, item)) - .pipe(Effect.catch(() => Effect.void)) - .pipe( - Effect.map((stat) => { - if (!stat || stat.type !== "File") return - const size = typeof stat.size === "bigint" ? Number(stat.size) : stat.size - return size > limit ? item : undefined - }), - ), - ), - { concurrency: 8 }, - )).filter((item): item is string => Boolean(item)), - ) - const block = new Set(untracked.filter((item) => large.has(item))) - yield* sync(Array.from(block)) - // Stage only the allowed candidate paths so snapshot updates stay scoped. - yield* stage(allow.filter((item) => !block.has(item))) - }) - - const cleanup = Effect.fnUntraced(function* () { - return yield* locked( - Effect.gen(function* () { - if (!(yield* enabled())) return - if (!(yield* exists(state.gitdir))) return - const result = yield* git(args(["gc", `--prune=${prune}`]), { cwd: state.directory }) - if (result.code !== 0) { - log.warn("cleanup failed", { + const restore = Effect.fnUntraced(function* (snapshot: string) { + return yield* locked( + Effect.gen(function* () { + log.info("restore", { commit: snapshot }) + const result = yield* git([...core, ...args(["read-tree", snapshot])], { cwd: state.worktree }) + if (result.code === 0) { + const checkout = yield* git([...core, ...args(["checkout-index", "-a", "-f"])], { + cwd: state.worktree, + }) + if (checkout.code === 0) return + log.error("failed to restore snapshot", { + snapshot, + exitCode: checkout.code, + stderr: checkout.stderr, + }) + return + } + log.error("failed to restore snapshot", { + snapshot, exitCode: result.code, stderr: result.stderr, }) - return - } - log.info("cleanup", { prune }) - }), - ) - }) + }), + ) + }) - const track = Effect.fnUntraced(function* () { - return yield* locked( - Effect.gen(function* () { - if (!(yield* enabled())) return - const existed = yield* exists(state.gitdir) - yield* fs.ensureDir(state.gitdir).pipe(Effect.orDie) - if (!existed) { - yield* git(["init"], { - env: { GIT_DIR: state.gitdir, GIT_WORK_TREE: state.worktree }, - }) - yield* git(["--git-dir", state.gitdir, "config", "core.autocrlf", "false"]) - yield* git(["--git-dir", state.gitdir, "config", "core.longpaths", "true"]) - yield* git(["--git-dir", state.gitdir, "config", "core.symlinks", "true"]) - yield* git(["--git-dir", state.gitdir, "config", "core.fsmonitor", "false"]) - log.info("initialized") - } - yield* add() - const result = yield* git(args(["write-tree"]), { cwd: state.directory }) - const hash = result.text.trim() - log.info("tracking", { hash, cwd: state.directory, git: state.gitdir }) - return hash - }), - ) - }) - - const patch = Effect.fnUntraced(function* (hash: string) { - return yield* locked( - Effect.gen(function* () { - yield* add() - const result = yield* git( - [...quote, ...args(["diff", "--cached", "--no-ext-diff", "--name-only", hash, "--", "."])], - { - cwd: state.directory, - }, - ) - if (result.code !== 0) { - log.warn("failed to get diff", { hash, exitCode: result.code }) - return { hash, files: [] } - } - const files = result.text - .trim() - .split("\n") - .map((x) => x.trim()) - .filter(Boolean) - - // Hide ignored-file removals from the user-facing patch output. - const ignored = yield* ignore(files) - - return { - hash, - files: files - .filter((item) => !ignored.has(item)) - .map((x) => path.join(state.worktree, x).replaceAll("\\", "/")), - } - }), - ) - }) - - const restore = Effect.fnUntraced(function* (snapshot: string) { - return yield* locked( - Effect.gen(function* () { - log.info("restore", { commit: snapshot }) - const result = yield* git([...core, ...args(["read-tree", snapshot])], { cwd: state.worktree }) - if (result.code === 0) { - const checkout = yield* git([...core, ...args(["checkout-index", "-a", "-f"])], { - cwd: state.worktree, - }) - if (checkout.code === 0) return - log.error("failed to restore snapshot", { - snapshot, - exitCode: checkout.code, - stderr: checkout.stderr, - }) - return - } - log.error("failed to restore snapshot", { - snapshot, - exitCode: result.code, - stderr: result.stderr, - }) - }), - ) - }) - - const revert = Effect.fnUntraced(function* (patches: Patch[]) { - return yield* locked( - Effect.gen(function* () { - const ops: { hash: string; file: string; rel: string }[] = [] - const seen = new Set() - for (const item of patches) { - for (const file of item.files) { - if (seen.has(file)) continue - seen.add(file) - ops.push({ - hash: item.hash, - file, - rel: path.relative(state.worktree, file).replaceAll("\\", "/"), - }) - } - } - - const single = Effect.fnUntraced(function* (op: (typeof ops)[number]) { - log.info("reverting", { file: op.file, hash: op.hash }) - const result = yield* git([...core, ...args(["checkout", op.hash, "--", op.file])], { - cwd: state.worktree, - }) - if (result.code === 0) return - const tree = yield* git([...core, ...args(["ls-tree", op.hash, "--", op.rel])], { - cwd: state.worktree, - }) - if (tree.code === 0 && tree.text.trim()) { - log.info("file existed in snapshot but checkout failed, keeping", { file: op.file, hash: op.hash }) - return - } - log.info("file did not exist in snapshot, deleting", { file: op.file, hash: op.hash }) - yield* remove(op.file) - }) - - const clash = (a: string, b: string) => a === b || a.startsWith(`${b}/`) || b.startsWith(`${a}/`) - - for (let i = 0; i < ops.length; ) { - const first = ops[i]! - const run = [first] - let j = i + 1 - // Only batch adjacent files when their paths cannot affect each other. - while (j < ops.length && run.length < 100) { - const next = ops[j]! - if (next.hash !== first.hash) break - if (run.some((item) => clash(item.rel, next.rel))) break - run.push(next) - j += 1 - } - - if (run.length === 1) { - yield* single(first) - i = j - continue - } - - const tree = yield* git( - [...core, ...args(["ls-tree", "--name-only", first.hash, "--", ...run.map((item) => item.rel)])], - { - cwd: state.worktree, - }, - ) - - if (tree.code !== 0) { - log.info("batched ls-tree failed, falling back to single-file revert", { - hash: first.hash, - files: run.length, - }) - for (const op of run) { - yield* single(op) + const revert = Effect.fnUntraced(function* (patches: Patch[]) { + return yield* locked( + Effect.gen(function* () { + const ops: { hash: string; file: string; rel: string }[] = [] + const seen = new Set() + for (const item of patches) { + for (const file of item.files) { + if (seen.has(file)) continue + seen.add(file) + ops.push({ + hash: item.hash, + file, + rel: path.relative(state.worktree, file).replaceAll("\\", "/"), + }) } - i = j - continue } - const have = new Set( - tree.text - .trim() - .split("\n") - .map((item) => item.trim()) - .filter(Boolean), - ) - const list = run.filter((item) => have.has(item.rel)) - if (list.length) { - log.info("reverting", { hash: first.hash, files: list.length }) - const result = yield* git( - [...core, ...args(["checkout", first.hash, "--", ...list.map((item) => item.file)])], + const single = Effect.fnUntraced(function* (op: (typeof ops)[number]) { + log.info("reverting", { file: op.file, hash: op.hash }) + const result = yield* git([...core, ...args(["checkout", op.hash, "--", op.file])], { + cwd: state.worktree, + }) + if (result.code === 0) return + const tree = yield* git([...core, ...args(["ls-tree", op.hash, "--", op.rel])], { + cwd: state.worktree, + }) + if (tree.code === 0 && tree.text.trim()) { + log.info("file existed in snapshot but checkout failed, keeping", { file: op.file, hash: op.hash }) + return + } + log.info("file did not exist in snapshot, deleting", { file: op.file, hash: op.hash }) + yield* remove(op.file) + }) + + const clash = (a: string, b: string) => a === b || a.startsWith(`${b}/`) || b.startsWith(`${a}/`) + + for (let i = 0; i < ops.length; ) { + const first = ops[i]! + const run = [first] + let j = i + 1 + // Only batch adjacent files when their paths cannot affect each other. + while (j < ops.length && run.length < 100) { + const next = ops[j]! + if (next.hash !== first.hash) break + if (run.some((item) => clash(item.rel, next.rel))) break + run.push(next) + j += 1 + } + + if (run.length === 1) { + yield* single(first) + i = j + continue + } + + const tree = yield* git( + [...core, ...args(["ls-tree", "--name-only", first.hash, "--", ...run.map((item) => item.rel)])], { cwd: state.worktree, }, ) - if (result.code !== 0) { - log.info("batched checkout failed, falling back to single-file revert", { + + if (tree.code !== 0) { + log.info("batched ls-tree failed, falling back to single-file revert", { hash: first.hash, - files: list.length, + files: run.length, }) for (const op of run) { yield* single(op) @@ -473,301 +433,328 @@ export const layer: Layer.Layer< i = j continue } - } - for (const op of run) { - if (have.has(op.rel)) continue - log.info("file did not exist in snapshot, deleting", { file: op.file, hash: op.hash }) - yield* remove(op.file) - } - - i = j - } - }), - ) - }) - - const diff = Effect.fnUntraced(function* (hash: string) { - return yield* locked( - Effect.gen(function* () { - yield* add() - const result = yield* git([...quote, ...args(["diff", "--cached", "--no-ext-diff", hash, "--", "."])], { - cwd: state.worktree, - }) - if (result.code !== 0) { - log.warn("failed to get diff", { - hash, - exitCode: result.code, - stderr: result.stderr, - }) - return "" - } - return result.text.trim() - }), - ) - }) - - const diffFull = Effect.fnUntraced(function* (from: string, to: string) { - return yield* locked( - Effect.gen(function* () { - type Row = { - file: string - status: "added" | "deleted" | "modified" - binary: boolean - additions: number - deletions: number - } - - type Ref = { - file: string - side: "before" | "after" - ref: string - } - - const show = Effect.fnUntraced(function* (row: Row) { - if (row.binary) return ["", ""] - if (row.status === "added") { - return [ - "", - yield* git([...cfg, ...args(["show", `${to}:${row.file}`])]).pipe(Effect.map((item) => item.text)), - ] - } - if (row.status === "deleted") { - return [ - yield* git([...cfg, ...args(["show", `${from}:${row.file}`])]).pipe( - Effect.map((item) => item.text), - ), - "", - ] - } - return yield* Effect.all( - [ - git([...cfg, ...args(["show", `${from}:${row.file}`])]).pipe(Effect.map((item) => item.text)), - git([...cfg, ...args(["show", `${to}:${row.file}`])]).pipe(Effect.map((item) => item.text)), - ], - { concurrency: 2 }, - ) - }) - - const load = Effect.fnUntraced( - function* (rows: Row[]) { - const refs = rows.flatMap((row) => { - if (row.binary) return [] - if (row.status === "added") - return [{ file: row.file, side: "after", ref: `${to}:${row.file}` } satisfies Ref] - if (row.status === "deleted") { - return [{ file: row.file, side: "before", ref: `${from}:${row.file}` } satisfies Ref] - } - return [ - { file: row.file, side: "before", ref: `${from}:${row.file}` } satisfies Ref, - { file: row.file, side: "after", ref: `${to}:${row.file}` } satisfies Ref, - ] - }) - if (!refs.length) return new Map() - - const proc = ChildProcess.make("git", [...cfg, ...args(["cat-file", "--batch"])], { - cwd: state.directory, - extendEnv: true, - stdin: Stream.make(new TextEncoder().encode(refs.map((item) => item.ref).join("\n") + "\n")), - }) - const handle = yield* spawner.spawn(proc) - const [out, err] = yield* Effect.all( - [Stream.mkUint8Array(handle.stdout), Stream.mkString(Stream.decodeText(handle.stderr))], - { concurrency: 2 }, + const have = new Set( + tree.text + .trim() + .split("\n") + .map((item) => item.trim()) + .filter(Boolean), ) - const code = yield* handle.exitCode - if (code !== 0) { - log.info("git cat-file --batch failed during snapshot diff, falling back to per-file git show", { - stderr: err, - refs: refs.length, - }) - return - } - - const fail = (msg: string, extra?: Record) => { - log.info(msg, { ...extra, refs: refs.length }) - return undefined - } - - const map = new Map() - const dec = new TextDecoder() - let i = 0 - for (const ref of refs) { - let end = i - while (end < out.length && out[end] !== 10) end += 1 - if (end >= out.length) { - return fail( - "git cat-file --batch returned a truncated header during snapshot diff, falling back to per-file git show", - ) - } - - const head = dec.decode(out.slice(i, end)) - i = end + 1 - const hit = map.get(ref.file) ?? { before: "", after: "" } - if (head.endsWith(" missing")) { - map.set(ref.file, hit) + const list = run.filter((item) => have.has(item.rel)) + if (list.length) { + log.info("reverting", { hash: first.hash, files: list.length }) + const result = yield* git( + [...core, ...args(["checkout", first.hash, "--", ...list.map((item) => item.file)])], + { + cwd: state.worktree, + }, + ) + if (result.code !== 0) { + log.info("batched checkout failed, falling back to single-file revert", { + hash: first.hash, + files: list.length, + }) + for (const op of run) { + yield* single(op) + } + i = j continue } - - const match = head.match(/^[0-9a-f]+ blob (\d+)$/) - if (!match) { - return fail( - "git cat-file --batch returned an unexpected header during snapshot diff, falling back to per-file git show", - { head }, - ) - } - - const size = Number(match[1]) - if (!Number.isInteger(size) || size < 0 || i + size >= out.length || out[i + size] !== 10) { - return fail( - "git cat-file --batch returned truncated content during snapshot diff, falling back to per-file git show", - { head }, - ) - } - - const text = dec.decode(out.slice(i, i + size)) - if (ref.side === "before") hit.before = text - if (ref.side === "after") hit.after = text - map.set(ref.file, hit) - i += size + 1 } - if (i !== out.length) { - return fail( - "git cat-file --batch returned trailing data during snapshot diff, falling back to per-file git show", - ) + for (const op of run) { + if (have.has(op.rel)) continue + log.info("file did not exist in snapshot, deleting", { file: op.file, hash: op.hash }) + yield* remove(op.file) } - return map - }, - Effect.scoped, - Effect.catch(() => - Effect.succeed | undefined>(undefined), - ), - ) + i = j + } + }), + ) + }) - const result: FileDiff[] = [] - const status = new Map() + const diff = Effect.fnUntraced(function* (hash: string) { + return yield* locked( + Effect.gen(function* () { + yield* add() + const result = yield* git([...quote, ...args(["diff", "--cached", "--no-ext-diff", hash, "--", "."])], { + cwd: state.worktree, + }) + if (result.code !== 0) { + log.warn("failed to get diff", { + hash, + exitCode: result.code, + stderr: result.stderr, + }) + return "" + } + return result.text.trim() + }), + ) + }) - const statuses = yield* git( - [...quote, ...args(["diff", "--no-ext-diff", "--name-status", "--no-renames", from, to, "--", "."])], - { cwd: state.directory }, - ) + const diffFull = Effect.fnUntraced(function* (from: string, to: string) { + return yield* locked( + Effect.gen(function* () { + type Row = { + file: string + status: "added" | "deleted" | "modified" + binary: boolean + additions: number + deletions: number + } - for (const line of statuses.text.trim().split("\n")) { - if (!line) continue - const [code, file] = line.split("\t") - if (!code || !file) continue - status.set(file, code.startsWith("A") ? "added" : code.startsWith("D") ? "deleted" : "modified") - } + type Ref = { + file: string + side: "before" | "after" + ref: string + } - const numstat = yield* git( - [...quote, ...args(["diff", "--no-ext-diff", "--no-renames", "--numstat", from, to, "--", "."])], - { - cwd: state.directory, - }, - ) - - const rows = numstat.text - .trim() - .split("\n") - .filter(Boolean) - .flatMap((line) => { - const [adds, dels, file] = line.split("\t") - if (!file) return [] - const binary = adds === "-" && dels === "-" - const additions = binary ? 0 : parseInt(adds) - const deletions = binary ? 0 : parseInt(dels) - return [ - { - file, - status: status.get(file) ?? "modified", - binary, - additions: Number.isFinite(additions) ? additions : 0, - deletions: Number.isFinite(deletions) ? deletions : 0, - } satisfies Row, - ] + const show = Effect.fnUntraced(function* (row: Row) { + if (row.binary) return ["", ""] + if (row.status === "added") { + return [ + "", + yield* git([...cfg, ...args(["show", `${to}:${row.file}`])]).pipe( + Effect.map((item) => item.text), + ), + ] + } + if (row.status === "deleted") { + return [ + yield* git([...cfg, ...args(["show", `${from}:${row.file}`])]).pipe( + Effect.map((item) => item.text), + ), + "", + ] + } + return yield* Effect.all( + [ + git([...cfg, ...args(["show", `${from}:${row.file}`])]).pipe(Effect.map((item) => item.text)), + git([...cfg, ...args(["show", `${to}:${row.file}`])]).pipe(Effect.map((item) => item.text)), + ], + { concurrency: 2 }, + ) }) - // Hide ignored-file removals from the user-facing diff output. - const ignored = yield* ignore(rows.map((r) => r.file)) - if (ignored.size > 0) { - const filtered = rows.filter((r) => !ignored.has(r.file)) - rows.length = 0 - rows.push(...filtered) - } + const load = Effect.fnUntraced( + function* (rows: Row[]) { + const refs = rows.flatMap((row) => { + if (row.binary) return [] + if (row.status === "added") + return [{ file: row.file, side: "after", ref: `${to}:${row.file}` } satisfies Ref] + if (row.status === "deleted") { + return [{ file: row.file, side: "before", ref: `${from}:${row.file}` } satisfies Ref] + } + return [ + { file: row.file, side: "before", ref: `${from}:${row.file}` } satisfies Ref, + { file: row.file, side: "after", ref: `${to}:${row.file}` } satisfies Ref, + ] + }) + if (!refs.length) return new Map() - const step = 100 - const patch = (file: string, before: string, after: string) => - formatPatch(structuredPatch(file, file, before, after, "", "", { context: Number.MAX_SAFE_INTEGER })) + const batch = yield* appProcess.run( + ChildProcess.make("git", [...cfg, ...args(["cat-file", "--batch"])], { + cwd: state.directory, + extendEnv: true, + }), + { stdin: refs.map((item) => item.ref).join("\n") + "\n" }, + ) + if (batch.exitCode !== 0) { + log.info("git cat-file --batch failed during snapshot diff, falling back to per-file git show", { + stderr: batch.stderr.toString("utf8"), + refs: refs.length, + }) + return + } + const out = batch.stdout - for (let i = 0; i < rows.length; i += step) { - const run = rows.slice(i, i + step) - const text = yield* load(run) + const fail = (msg: string, extra?: Record) => { + log.info(msg, { ...extra, refs: refs.length }) + return undefined + } - for (const row of run) { - const hit = text?.get(row.file) ?? { before: "", after: "" } - const [before, after] = row.binary ? ["", ""] : text ? [hit.before, hit.after] : yield* show(row) - result.push({ - file: row.file, - patch: row.binary ? "" : patch(row.file, before, after), - additions: row.additions, - deletions: row.deletions, - status: row.status, - }) + const map = new Map() + const dec = new TextDecoder() + let i = 0 + for (const ref of refs) { + let end = i + while (end < out.length && out[end] !== 10) end += 1 + if (end >= out.length) { + return fail( + "git cat-file --batch returned a truncated header during snapshot diff, falling back to per-file git show", + ) + } + + const head = dec.decode(out.slice(i, end)) + i = end + 1 + const hit = map.get(ref.file) ?? { before: "", after: "" } + if (head.endsWith(" missing")) { + map.set(ref.file, hit) + continue + } + + const match = head.match(/^[0-9a-f]+ blob (\d+)$/) + if (!match) { + return fail( + "git cat-file --batch returned an unexpected header during snapshot diff, falling back to per-file git show", + { head }, + ) + } + + const size = Number(match[1]) + if (!Number.isInteger(size) || size < 0 || i + size >= out.length || out[i + size] !== 10) { + return fail( + "git cat-file --batch returned truncated content during snapshot diff, falling back to per-file git show", + { head }, + ) + } + + const text = dec.decode(out.slice(i, i + size)) + if (ref.side === "before") hit.before = text + if (ref.side === "after") hit.after = text + map.set(ref.file, hit) + i += size + 1 + } + + if (i !== out.length) { + return fail( + "git cat-file --batch returned trailing data during snapshot diff, falling back to per-file git show", + ) + } + + return map + }, + Effect.scoped, + Effect.catch(() => + Effect.succeed | undefined>(undefined), + ), + ) + + const result: FileDiff[] = [] + const status = new Map() + + const statuses = yield* git( + [...quote, ...args(["diff", "--no-ext-diff", "--name-status", "--no-renames", from, to, "--", "."])], + { cwd: state.directory }, + ) + + for (const line of statuses.text.trim().split("\n")) { + if (!line) continue + const [code, file] = line.split("\t") + if (!code || !file) continue + status.set(file, code.startsWith("A") ? "added" : code.startsWith("D") ? "deleted" : "modified") } - } - return result + const numstat = yield* git( + [...quote, ...args(["diff", "--no-ext-diff", "--no-renames", "--numstat", from, to, "--", "."])], + { + cwd: state.directory, + }, + ) + + const rows = numstat.text + .trim() + .split("\n") + .filter(Boolean) + .flatMap((line) => { + const [adds, dels, file] = line.split("\t") + if (!file) return [] + const binary = adds === "-" && dels === "-" + const additions = binary ? 0 : parseInt(adds) + const deletions = binary ? 0 : parseInt(dels) + return [ + { + file, + status: status.get(file) ?? "modified", + binary, + additions: Number.isFinite(additions) ? additions : 0, + deletions: Number.isFinite(deletions) ? deletions : 0, + } satisfies Row, + ] + }) + + // Hide ignored-file removals from the user-facing diff output. + const ignored = yield* ignore(rows.map((r) => r.file)) + if (ignored.size > 0) { + const filtered = rows.filter((r) => !ignored.has(r.file)) + rows.length = 0 + rows.push(...filtered) + } + + const step = 100 + const patch = (file: string, before: string, after: string) => + formatPatch(structuredPatch(file, file, before, after, "", "", { context: Number.MAX_SAFE_INTEGER })) + + for (let i = 0; i < rows.length; i += step) { + const run = rows.slice(i, i + step) + const text = yield* load(run) + + for (const row of run) { + const hit = text?.get(row.file) ?? { before: "", after: "" } + const [before, after] = row.binary ? ["", ""] : text ? [hit.before, hit.after] : yield* show(row) + result.push({ + file: row.file, + patch: row.binary ? "" : patch(row.file, before, after), + additions: row.additions, + deletions: row.deletions, + status: row.status, + }) + } + } + + return result + }), + ) + }) + + yield* cleanup().pipe( + Effect.catchCause((cause) => { + log.error("cleanup loop failed", { cause: Cause.pretty(cause) }) + return Effect.void }), + Effect.repeat(Schedule.spaced(Duration.hours(1))), + Effect.delay(Duration.minutes(1)), + Effect.forkScoped, ) - }) - yield* cleanup().pipe( - Effect.catchCause((cause) => { - log.error("cleanup loop failed", { cause: Cause.pretty(cause) }) - return Effect.void - }), - Effect.repeat(Schedule.spaced(Duration.hours(1))), - Effect.delay(Duration.minutes(1)), - Effect.forkScoped, - ) + return { cleanup, track, patch, restore, revert, diff, diffFull } + }), + ) - return { cleanup, track, patch, restore, revert, diff, diffFull } - }), - ) - - return Service.of({ - init: Effect.fn("Snapshot.init")(function* () { - yield* InstanceState.get(state) - }), - cleanup: Effect.fn("Snapshot.cleanup")(function* () { - return yield* InstanceState.useEffect(state, (s) => s.cleanup()) - }), - track: Effect.fn("Snapshot.track")(function* () { - return yield* InstanceState.useEffect(state, (s) => s.track()) - }), - patch: Effect.fn("Snapshot.patch")(function* (hash: string) { - return yield* InstanceState.useEffect(state, (s) => s.patch(hash)) - }), - restore: Effect.fn("Snapshot.restore")(function* (snapshot: string) { - return yield* InstanceState.useEffect(state, (s) => s.restore(snapshot)) - }), - revert: Effect.fn("Snapshot.revert")(function* (patches: Patch[]) { - return yield* InstanceState.useEffect(state, (s) => s.revert(patches)) - }), - diff: Effect.fn("Snapshot.diff")(function* (hash: string) { - return yield* InstanceState.useEffect(state, (s) => s.diff(hash)) - }), - diffFull: Effect.fn("Snapshot.diffFull")(function* (from: string, to: string) { - return yield* InstanceState.useEffect(state, (s) => s.diffFull(from, to)) - }), - }) - }), -) + return Service.of({ + init: Effect.fn("Snapshot.init")(function* () { + yield* InstanceState.get(state) + }), + cleanup: Effect.fn("Snapshot.cleanup")(function* () { + return yield* InstanceState.useEffect(state, (s) => s.cleanup()) + }), + track: Effect.fn("Snapshot.track")(function* () { + return yield* InstanceState.useEffect(state, (s) => s.track()) + }), + patch: Effect.fn("Snapshot.patch")(function* (hash: string) { + return yield* InstanceState.useEffect(state, (s) => s.patch(hash)) + }), + restore: Effect.fn("Snapshot.restore")(function* (snapshot: string) { + return yield* InstanceState.useEffect(state, (s) => s.restore(snapshot)) + }), + revert: Effect.fn("Snapshot.revert")(function* (patches: Patch[]) { + return yield* InstanceState.useEffect(state, (s) => s.revert(patches)) + }), + diff: Effect.fn("Snapshot.diff")(function* (hash: string) { + return yield* InstanceState.useEffect(state, (s) => s.diff(hash)) + }), + diffFull: Effect.fn("Snapshot.diffFull")(function* (from: string, to: string) { + return yield* InstanceState.useEffect(state, (s) => s.diffFull(from, to)) + }), + }) + }), + ) export const defaultLayer = layer.pipe( - Layer.provide(CrossSpawnSpawner.defaultLayer), + Layer.provide(AppProcess.defaultLayer), Layer.provide(AppFileSystem.defaultLayer), Layer.provide(Config.defaultLayer), ) diff --git a/packages/opencode/src/storage/db.ts b/packages/opencode/src/storage/db.ts index 06cb99f97f..86e14da560 100644 --- a/packages/opencode/src/storage/db.ts +++ b/packages/opencode/src/storage/db.ts @@ -7,7 +7,6 @@ import { lazy } from "../util/lazy" import { Global } from "@opencode-ai/core/global" import * as Log from "@opencode-ai/core/util/log" import { NamedError } from "@opencode-ai/core/util/error" -import z from "zod" import path from "path" import { readFileSync, readdirSync, existsSync } from "fs" import { Flag } from "@opencode-ai/core/flag/flag" @@ -15,15 +14,13 @@ import { InstallationChannel } from "@opencode-ai/core/installation/version" import { InstanceState } from "@/effect/instance-state" import { iife } from "@/util/iife" import { init } from "#db" +import { Schema } from "effect" declare const OPENCODE_MIGRATIONS: { sql: string; timestamp: number; name: string }[] | undefined -export const NotFoundError = NamedError.create( - "NotFoundError", - z.object({ - message: z.string(), - }), -) +export const NotFoundError = NamedError.create("NotFoundError", { + message: Schema.String, +}) const log = Log.create({ service: "db" }) diff --git a/packages/opencode/src/storage/storage.ts b/packages/opencode/src/storage/storage.ts index bc4d8b8f17..ee2ee45f85 100644 --- a/packages/opencode/src/storage/storage.ts +++ b/packages/opencode/src/storage/storage.ts @@ -1,8 +1,6 @@ import * as Log from "@opencode-ai/core/util/log" import path from "path" import { Global } from "@opencode-ai/core/global" -import { NamedError } from "@opencode-ai/core/util/error" -import z from "zod" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { Effect, Exit, Layer, Option, RcMap, Schema, Context, TxReentrantLock } from "effect" import { NonNegativeInt } from "@opencode-ai/core/schema" @@ -16,14 +14,22 @@ type Migration = ( git: Git.Interface, ) => Effect.Effect -export const NotFoundError = NamedError.create( - "NotFoundError", - z.object({ - message: z.string(), - }), -) +export class NotFoundError extends Schema.TaggedErrorClass()("NotFoundError", { + message: Schema.String, +}) { + static isInstance(input: unknown): input is NotFoundError { + return input instanceof NotFoundError + } -export type Error = AppFileSystem.Error | InstanceType + toObject() { + return { + name: "NotFoundError" as const, + data: { message: this.message }, + } + } +} + +export type Error = AppFileSystem.Error | NotFoundError const RootFile = Schema.Struct({ path: Schema.optional( @@ -249,7 +255,7 @@ export const layer = Layer.effect( }), ) - const fail = (target: string): Effect.Effect> => + const fail = (target: string): Effect.Effect => Effect.fail(new NotFoundError({ message: `Resource not found: ${target}` })) const wrap = (target: string, body: Effect.Effect) => diff --git a/packages/opencode/src/sync/index.ts b/packages/opencode/src/sync/index.ts index 5c29101b6c..7f9b8eeef1 100644 --- a/packages/opencode/src/sync/index.ts +++ b/packages/opencode/src/sync/index.ts @@ -7,11 +7,11 @@ import type { InstanceContext } from "@/project/instance" import { EventSequenceTable, EventTable } from "./event.sql" import type { WorkspaceID } from "@/control-plane/schema" import { EventID } from "./schema" -import { Flag } from "@opencode-ai/core/flag/flag" import { Context, Effect, Layer, Schema as EffectSchema } from "effect" import type { DeepMutable } from "@opencode-ai/core/schema" import { serviceUse } from "@/effect/service-use" import { InstanceState } from "@/effect/instance-state" +import { RuntimeFlags } from "@/effect/runtime-flags" // Keep `Event["data"]` mutable because projectors mutate the persisted shape // when writing to the database. Bus payloads (`Properties`) stay readonly — @@ -69,6 +69,8 @@ export class Service extends Context.Service()("@opencode/Sy export const layer = Layer.effect(Service)( Effect.gen(function* () { + const flags = yield* RuntimeFlags.Service + const replay: Interface["replay"] = Effect.fn("SyncEvent.replay")(function* (event, options) { const def = registry.get(event.type) if (!def) { @@ -104,7 +106,12 @@ export const layer = Layer.effect(Service)( workspace: yield* InstanceState.workspaceID, } : undefined - process(def, event, { publish, context, ownerID: options?.ownerID }) + process(def, event, { + publish, + context, + ownerID: options?.ownerID, + experimentalWorkspaces: flags.experimentalWorkspaces, + }) }) const replayAll: Interface["replayAll"] = Effect.fn("SyncEvent.replayAll")(function* (events, options) { @@ -160,7 +167,7 @@ export const layer = Layer.effect(Service)( const seq = row?.seq != null ? row.seq + 1 : 0 const event = { id, seq, aggregateID: agg, data } - process(def, event, { publish, context }) + process(def, event, { publish, context, experimentalWorkspaces: flags.experimentalWorkspaces }) }, { behavior: "immediate", @@ -197,7 +204,7 @@ export const layer = Layer.effect(Service)( }), ) -export const defaultLayer = layer +export const defaultLayer = layer.pipe(Layer.provide(RuntimeFlags.defaultLayer)) export const use = serviceUse(Service) @@ -279,7 +286,7 @@ export function project( function process( def: Def, event: Event, - options: { publish: boolean; context?: PublishContext; ownerID?: string }, + options: { publish: boolean; context?: PublishContext; ownerID?: string; experimentalWorkspaces: boolean }, ) { if (projectors == null) { throw new Error("No projectors available. Call `SyncEvent.init` to install projectors") @@ -293,7 +300,7 @@ function process( Database.transaction((tx) => { projector(tx, event.data, event) - if (Flag.OPENCODE_EXPERIMENTAL_WORKSPACES) { + if (options.experimentalWorkspaces) { tx.insert(EventSequenceTable) .values({ aggregate_id: event.aggregateID, diff --git a/packages/opencode/src/tool/plan.ts b/packages/opencode/src/tool/plan.ts index d5195376b3..af206f66a5 100644 --- a/packages/opencode/src/tool/plan.ts +++ b/packages/opencode/src/tool/plan.ts @@ -6,16 +6,9 @@ import { Session } from "@/session/session" import { MessageV2 } from "../session/message-v2" import { Provider } from "@/provider/provider" import { InstanceState } from "@/effect/instance-state" -import { type SessionID, MessageID, PartID } from "../session/schema" +import { MessageID, PartID } from "../session/schema" import EXIT_DESCRIPTION from "./plan-exit.txt" -function getLastModel(sessionID: SessionID) { - for (const item of MessageV2.stream(sessionID)) { - if (item.info.role === "user" && item.info.model) return item.info.model - } - return undefined -} - export const Parameters = Schema.Struct({}) export const PlanExitTool = Tool.define( @@ -51,7 +44,10 @@ export const PlanExitTool = Tool.define( if (answers[0]?.[0] === "No") yield* new Question.RejectedError() - const model = getLastModel(ctx.sessionID) ?? (yield* provider.defaultModel()) + const messages = yield* session.messages({ sessionID: ctx.sessionID }).pipe(Effect.orDie) + const lastUser = messages.findLast((item) => item.info.role === "user" && item.info.model) + const model = + lastUser?.info.role === "user" && lastUser.info.model ? lastUser.info.model : yield* provider.defaultModel() const msg: MessageV2.User = { id: MessageID.ascending(), diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index f72f10dd1f..cb3e4ce6bf 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -24,7 +24,6 @@ import { ProviderID, type ModelID } from "../provider/schema" import { WebSearchTool } from "./websearch" import { RepoCloneTool } from "./repo_clone" import { RepoOverviewTool } from "./repo_overview" -import { Flag } from "@opencode-ai/core/flag/flag" import * as Log from "@opencode-ai/core/util/log" import { LspTool } from "./lsp" import * as Truncate from "./truncate" @@ -50,13 +49,11 @@ import { Git } from "@/git" import { Skill } from "../skill" import { Permission } from "@/permission" import { Reference } from "@/reference/reference" +import { RuntimeFlags } from "@/effect/runtime-flags" const log = Log.create({ service: "tool.registry" }) -export function webSearchEnabled( - providerID: ProviderID, - flags = { exa: Flag.OPENCODE_ENABLE_EXA, parallel: Flag.OPENCODE_ENABLE_PARALLEL }, -) { +export function webSearchEnabled(providerID: ProviderID, flags = { exa: false, parallel: false }) { return providerID === ProviderID.opencode || flags.exa || flags.parallel } @@ -101,6 +98,7 @@ export const layer: Layer.Layer< | Ripgrep.Service | Format.Service | Truncate.Service + | RuntimeFlags.Service > = Layer.effect( Service, Effect.gen(function* () { @@ -109,6 +107,7 @@ export const layer: Layer.Layer< const agents = yield* Agent.Service const skill = yield* Skill.Service const truncate = yield* Truncate.Service + const flags = yield* RuntimeFlags.Service const invalid = yield* InvalidTool const task = yield* TaskTool @@ -160,11 +159,13 @@ export const layer: Layer.Layer< const result = yield* Effect.promise(() => def.execute(args as any, pluginCtx)) const output = typeof result === "string" ? result : result.output const metadata = typeof result === "string" ? {} : (result.metadata ?? {}) + const attachments = typeof result === "string" ? undefined : result.attachments const info = yield* agent.get(toolCtx.agent) const out = yield* truncate.output(output, {}, info) return { - title: "", + title: typeof result === "string" ? "" : (result.title ?? ""), output: out.truncated ? out.content : output, + attachments, metadata: { ...metadata, truncated: out.truncated, @@ -207,8 +208,7 @@ export const layer: Layer.Layer< } yield* config.get() - const questionEnabled = - ["app", "cli", "desktop"].includes(Flag.OPENCODE_CLIENT) || Flag.OPENCODE_ENABLE_QUESTION_TOOL + const questionEnabled = ["app", "cli", "desktop"].includes(flags.client) || flags.enableQuestionTool const tool = yield* Effect.all({ invalid: Tool.init(invalid), @@ -246,11 +246,11 @@ export const layer: Layer.Layer< tool.fetch, tool.todo, tool.search, - ...(Flag.OPENCODE_EXPERIMENTAL_SCOUT ? [tool.repo_clone, tool.repo_overview] : []), + ...(flags.experimentalScout ? [tool.repo_clone, tool.repo_overview] : []), tool.skill, tool.patch, - ...(Flag.OPENCODE_EXPERIMENTAL_LSP_TOOL ? [tool.lsp] : []), - ...(Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag.OPENCODE_CLIENT === "cli" ? [tool.plan] : []), + ...(flags.experimentalLspTool ? [tool.lsp] : []), + ...(flags.experimentalPlanMode && flags.client === "cli" ? [tool.plan] : []), ], task: tool.task, read: tool.read, @@ -304,7 +304,7 @@ export const layer: Layer.Layer< const tools: Interface["tools"] = Effect.fn("ToolRegistry.tools")(function* (input) { const filtered = (yield* all()).filter((tool) => { if (tool.id === WebSearchTool.id) { - return webSearchEnabled(input.providerID) + return webSearchEnabled(input.providerID, { exa: flags.enableExa, parallel: flags.enableParallel }) } const usePatch = @@ -378,6 +378,7 @@ export const defaultLayer = Layer.suspend(() => Layer.provide(CrossSpawnSpawner.defaultLayer), Layer.provide(Ripgrep.defaultLayer), Layer.provide(Truncate.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), ), ) diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index c4d5bf7f4a..09bbaca262 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -86,7 +86,7 @@ export const TaskTool = Tool.define( ], })) - const msg = yield* Effect.sync(() => MessageV2.get({ sessionID: ctx.sessionID, messageID: ctx.messageID })) + const msg = yield* MessageV2.get({ sessionID: ctx.sessionID, messageID: ctx.messageID }).pipe(Effect.orDie) if (msg.info.role !== "assistant") return yield* Effect.fail(new Error("Not an assistant message")) const model = next.model ?? { diff --git a/packages/opencode/src/tool/webfetch.ts b/packages/opencode/src/tool/webfetch.ts index 8c2be44e99..f8a4b6233a 100644 --- a/packages/opencode/src/tool/webfetch.ts +++ b/packages/opencode/src/tool/webfetch.ts @@ -1,5 +1,6 @@ import { Effect, Schema } from "effect" import { HttpClient, HttpClientRequest } from "effect/unstable/http" +import { Parser } from "htmlparser2" import * as Tool from "./tool" import TurndownService from "turndown" import DESCRIPTION from "./webfetch.txt" @@ -139,8 +140,7 @@ export const WebFetchTool = Tool.define( case "text": if (contentType.includes("text/html")) { - const text = yield* Effect.promise(() => extractTextFromHTML(content)) - return { output: text, title, metadata: {} } + return { output: extractTextFromHTML(content), title, metadata: {} } } return { output: content, title, metadata: {} } @@ -155,35 +155,27 @@ export const WebFetchTool = Tool.define( }), ) -async function extractTextFromHTML(html: string) { +function extractTextFromHTML(html: string) { let text = "" - let skipContent = false + let skipDepth = 0 - const rewriter = new HTMLRewriter() - .on("script, style, noscript, iframe, object, embed", { - element() { - skipContent = true - }, - text() { - // Skip text content inside these elements - }, - }) - .on("*", { - element(element) { - // Reset skip flag when entering other elements - if (!["script", "style", "noscript", "iframe", "object", "embed"].includes(element.tagName)) { - skipContent = false - } - }, - text(input) { - if (!skipContent) { - text += input.text - } - }, - }) - .transform(new Response(html)) + const parser = new Parser({ + onopentag(name) { + if (skipDepth > 0 || ["script", "style", "noscript", "iframe", "object", "embed"].includes(name)) { + skipDepth++ + } + }, + ontext(input) { + if (skipDepth === 0) text += input + }, + onclosetag() { + if (skipDepth > 0) skipDepth-- + }, + }) + + parser.write(html) + parser.end() - await rewriter.text() return text.trim() } diff --git a/packages/opencode/src/tool/websearch.ts b/packages/opencode/src/tool/websearch.ts index 0218ecbe3b..d08ae1d153 100644 --- a/packages/opencode/src/tool/websearch.ts +++ b/packages/opencode/src/tool/websearch.ts @@ -3,9 +3,9 @@ import { HttpClient } from "effect/unstable/http" import * as Tool from "./tool" import * as McpWebSearch from "./mcp-websearch" import DESCRIPTION from "./websearch.txt" -import { Flag } from "@opencode-ai/core/flag/flag" import { checksum } from "@opencode-ai/core/util/encode" import { InstallationVersion } from "@opencode-ai/core/installation/version" +import { RuntimeFlags } from "@/effect/runtime-flags" export const Parameters = Schema.Struct({ query: Schema.String.annotate({ description: "Websearch query" }), @@ -27,10 +27,7 @@ export const Parameters = Schema.Struct({ const WebSearchProviderSchema = Schema.Literals(["exa", "parallel"]) export type WebSearchProvider = Schema.Schema.Type -export function selectWebSearchProvider( - sessionID: string, - flags = { exa: Flag.OPENCODE_ENABLE_EXA, parallel: Flag.OPENCODE_ENABLE_PARALLEL }, -): WebSearchProvider { +export function selectWebSearchProvider(sessionID: string, flags = { exa: false, parallel: false }): WebSearchProvider { const override = process.env.OPENCODE_WEBSEARCH_PROVIDER if (override === "exa" || override === "parallel") return override if (flags.parallel) return "parallel" @@ -103,6 +100,7 @@ export const WebSearchTool = Tool.define( "websearch", Effect.gen(function* () { const http = yield* HttpClient.HttpClient + const flags = yield* RuntimeFlags.Service return { get description() { @@ -111,7 +109,10 @@ export const WebSearchTool = Tool.define( parameters: Parameters, execute: (params: Schema.Schema.Type, ctx: Tool.Context) => Effect.gen(function* () { - const provider = selectWebSearchProvider(ctx.sessionID) + const provider = selectWebSearchProvider(ctx.sessionID, { + exa: flags.enableExa, + parallel: flags.enableParallel, + }) const title = webSearchProviderLabel(provider) yield* ctx.metadata({ title: `${title} "${params.query}"`, metadata: { provider } }) diff --git a/packages/opencode/src/util/abort.ts b/packages/opencode/src/util/abort.ts deleted file mode 100644 index 3e7cfd8b28..0000000000 --- a/packages/opencode/src/util/abort.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Creates an AbortController that automatically aborts after a timeout. - * - * Uses bind() instead of arrow functions to avoid capturing the surrounding - * scope in closures. Arrow functions like `() => controller.abort()` capture - * request bodies and other large objects, preventing GC for the timer lifetime. - * - * @param ms Timeout in milliseconds - * @returns Object with controller, signal, and clearTimeout function - */ -export function abortAfter(ms: number) { - const controller = new AbortController() - const id = setTimeout(controller.abort.bind(controller), ms) - return { - controller, - signal: controller.signal, - clearTimeout: () => globalThis.clearTimeout(id), - } -} - -/** - * Combines multiple AbortSignals with a timeout. - * - * @param ms Timeout in milliseconds - * @param signals Additional signals to combine - * @returns Combined signal that aborts on timeout or when any input signal aborts - */ -export function abortAfterAny(ms: number, ...signals: AbortSignal[]) { - const timeout = abortAfter(ms) - const signal = AbortSignal.any([timeout.signal, ...signals]) - return { - signal, - clearTimeout: timeout.clearTimeout, - } -} diff --git a/packages/opencode/src/util/color.ts b/packages/opencode/src/util/color.ts deleted file mode 100644 index 3752fd19bf..0000000000 --- a/packages/opencode/src/util/color.ts +++ /dev/null @@ -1,19 +0,0 @@ -export function isValidHex(hex?: string): hex is string { - if (!hex) return false - return /^#[0-9a-fA-F]{6}$/.test(hex) -} - -export function hexToRgb(hex: string): { r: number; g: number; b: number } { - const r = parseInt(hex.slice(1, 3), 16) - const g = parseInt(hex.slice(3, 5), 16) - const b = parseInt(hex.slice(5, 7), 16) - return { r, g, b } -} - -export function hexToAnsiBold(hex?: string): string | undefined { - if (!isValidHex(hex)) return undefined - const { r, g, b } = hexToRgb(hex) - return `\x1b[38;2;${r};${g};${b}m\x1b[1m` -} - -export * as Color from "./color" diff --git a/packages/opencode/src/util/filesystem.ts b/packages/opencode/src/util/filesystem.ts index ded2b45178..696603adbb 100644 --- a/packages/opencode/src/util/filesystem.ts +++ b/packages/opencode/src/util/filesystem.ts @@ -1,10 +1,11 @@ import { chmod, mkdir, readFile, stat as statFile, writeFile } from "fs/promises" import { createWriteStream, existsSync, statSync } from "fs" import { realpathSync } from "fs" -import { dirname, join, relative, resolve as pathResolve, win32 } from "path" +import { dirname, isAbsolute, join, relative, resolve as pathResolve, win32 } from "path" import { Readable } from "stream" import { pipeline } from "stream/promises" import { Glob } from "@opencode-ai/core/util/glob" +import { fileURLToPath } from "url" // Fast sync version for metadata checks export async function exists(p: string): Promise { @@ -142,6 +143,12 @@ export function resolve(p: string): string { } } +export function resolveFilePath(root: string, file: string): string { + const raw = file.startsWith("file://") ? fileURLToPath(file) : file + if (isAbsolute(raw)) return raw + return pathResolve(root, raw) +} + export function windowsPath(p: string): string { if (process.platform !== "win32") return p return ( diff --git a/packages/opencode/src/util/lock.ts b/packages/opencode/src/util/lock.ts deleted file mode 100644 index 15635996ee..0000000000 --- a/packages/opencode/src/util/lock.ts +++ /dev/null @@ -1,98 +0,0 @@ -const locks = new Map< - string, - { - readers: number - writer: boolean - waitingReaders: (() => void)[] - waitingWriters: (() => void)[] - } ->() - -function get(key: string) { - if (!locks.has(key)) { - locks.set(key, { - readers: 0, - writer: false, - waitingReaders: [], - waitingWriters: [], - }) - } - return locks.get(key)! -} - -function process(key: string) { - const lock = locks.get(key) - if (!lock || lock.writer || lock.readers > 0) return - - // Prioritize writers to prevent starvation - if (lock.waitingWriters.length > 0) { - const nextWriter = lock.waitingWriters.shift()! - nextWriter() - return - } - - // Wake up all waiting readers - while (lock.waitingReaders.length > 0) { - const nextReader = lock.waitingReaders.shift()! - nextReader() - } - - // Clean up empty locks - if (lock.readers === 0 && !lock.writer && lock.waitingReaders.length === 0 && lock.waitingWriters.length === 0) { - locks.delete(key) - } -} - -export async function read(key: string): Promise { - const lock = get(key) - - return new Promise((resolve) => { - if (!lock.writer && lock.waitingWriters.length === 0) { - lock.readers++ - resolve({ - [Symbol.dispose]: () => { - lock.readers-- - process(key) - }, - }) - } else { - lock.waitingReaders.push(() => { - lock.readers++ - resolve({ - [Symbol.dispose]: () => { - lock.readers-- - process(key) - }, - }) - }) - } - }) -} - -export async function write(key: string): Promise { - const lock = get(key) - - return new Promise((resolve) => { - if (!lock.writer && lock.readers === 0) { - lock.writer = true - resolve({ - [Symbol.dispose]: () => { - lock.writer = false - process(key) - }, - }) - } else { - lock.waitingWriters.push(() => { - lock.writer = true - resolve({ - [Symbol.dispose]: () => { - lock.writer = false - process(key) - }, - }) - }) - } - }) -} - -export * as Lock from "./lock" diff --git a/packages/opencode/src/util/named-schema-error.ts b/packages/opencode/src/util/named-schema-error.ts deleted file mode 100644 index a5ff0828ea..0000000000 --- a/packages/opencode/src/util/named-schema-error.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Schema } from "effect" - -/** - * Create a Schema-backed NamedError-shaped class. - * - * Drop-in replacement for `NamedError.create(tag, zodShape)` but backed by - * `Schema.Struct` under the hood. The wire shape emitted by the derived - * `.Schema` is still `{ name: tag, data: {...fields} }` so the generated - * OpenAPI/SDK output is byte-identical to the original NamedError schema. - * - * Preserves the existing surface: - * - static `Schema` (Effect schema of the wire shape) - * - static `isInstance(x)` - * - instance `toObject()` returning `{ name, data }` - * - `new X({ ...data }, { cause })` - */ -export function namedSchemaError(tag: Tag, fields: Fields) { - const dataSchema = Schema.Struct(fields) - // Wire shape matches the original NamedError output so the SDK stays stable. - const effectSchema = Schema.Struct({ - name: Schema.Literal(tag), - data: dataSchema, - }).annotate({ identifier: tag }) - - type Data = Schema.Schema.Type - - class NamedSchemaError extends Error { - static readonly Schema = effectSchema - static readonly EffectSchema = effectSchema - static readonly tag = tag - public static isInstance(input: unknown): input is NamedSchemaError { - return typeof input === "object" && input !== null && "name" in input && (input as { name: unknown }).name === tag - } - - public override readonly name: Tag = tag - public readonly data: Data - - constructor(data: Data, options?: ErrorOptions) { - super(tag, options) - this.data = data - } - - toObject(): { name: Tag; data: Data } { - return { name: tag, data: this.data } - } - } - - Object.defineProperty(NamedSchemaError, "name", { value: tag }) - - return NamedSchemaError -} diff --git a/packages/opencode/src/util/network.ts b/packages/opencode/src/util/network.ts deleted file mode 100644 index 69e5d17588..0000000000 --- a/packages/opencode/src/util/network.ts +++ /dev/null @@ -1,9 +0,0 @@ -export function online() { - const nav = globalThis.navigator - if (!nav || typeof nav.onLine !== "boolean") return true - return nav.onLine -} - -export function proxied() { - return !!(process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy) -} diff --git a/packages/opencode/src/util/scrap.ts b/packages/opencode/src/util/scrap.ts deleted file mode 100644 index 554dba1c54..0000000000 --- a/packages/opencode/src/util/scrap.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const foo: string = "42" -export const bar: number = 123 - -export function dummyFunction(): void { - console.log("This is a dummy function") -} - -export function randomHelper(): boolean { - return Math.random() > 0.5 -} diff --git a/packages/opencode/src/v2/model.ts b/packages/opencode/src/v2/model.ts deleted file mode 100644 index 56357ab400..0000000000 --- a/packages/opencode/src/v2/model.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { withStatics } from "@opencode-ai/core/schema" -import { ModelStatus } from "@/provider/model-status" -import { Array, Context, Effect, HashMap, Layer, Option, Order, pipe, Schema } from "effect" -import { DateTimeUtcFromMillis } from "effect/Schema" - -export const ID = Schema.String.pipe(Schema.brand("Model.ID")) -export type ID = typeof ID.Type - -export const ProviderID = Schema.String.pipe( - Schema.brand("Model.ProviderID"), - withStatics((schema) => ({ - // Well-known providers - opencode: schema.make("opencode"), - anthropic: schema.make("anthropic"), - openai: schema.make("openai"), - google: schema.make("google"), - googleVertex: schema.make("google-vertex"), - githubCopilot: schema.make("github-copilot"), - amazonBedrock: schema.make("amazon-bedrock"), - azure: schema.make("azure"), - openrouter: schema.make("openrouter"), - mistral: schema.make("mistral"), - gitlab: schema.make("gitlab"), - })), -) -export type ProviderID = typeof ProviderID.Type - -export const VariantID = Schema.String.pipe(Schema.brand("VariantID")) -export type VariantID = typeof VariantID.Type - -// Grouping of models, eg claude opus, claude sonnet -export const Family = Schema.String.pipe(Schema.brand("Family")) -export type Family = typeof Family.Type - -const OpenAIResponses = Schema.Struct({ - type: Schema.Literal("openai/responses"), - url: Schema.String, - websocket: Schema.optional(Schema.Boolean), -}) - -const OpenAICompletions = Schema.Struct({ - type: Schema.Literal("openai/completions"), - url: Schema.String, - reasoning: Schema.Union([ - Schema.Struct({ - type: Schema.Literal("reasoning_content"), - }), - Schema.Struct({ - type: Schema.Literal("reasoning_details"), - }), - ]).pipe(Schema.optional), -}) -export type OpenAICompletions = typeof OpenAICompletions.Type - -const AnthropicMessages = Schema.Struct({ - type: Schema.Literal("anthropic/messages"), - url: Schema.String, -}) - -export const Endpoint = Schema.Union([OpenAIResponses, OpenAICompletions, AnthropicMessages]).pipe( - Schema.toTaggedUnion("type"), -) -export type Endpoint = typeof Endpoint.Type - -export const Capabilities = Schema.Struct({ - tools: Schema.Boolean, - // mime patterns, image, audio, video/*, text/* - input: Schema.String.pipe(Schema.Array), - output: Schema.String.pipe(Schema.Array), -}) -export type Capabilities = typeof Capabilities.Type - -export const Options = Schema.Struct({ - headers: Schema.Record(Schema.String, Schema.String), - body: Schema.Record(Schema.String, Schema.Any), -}) -export type Options = typeof Options.Type - -export const Cost = Schema.Struct({ - tier: Schema.Struct({ - type: Schema.Literal("context"), - size: Schema.Int, - }).pipe(Schema.optional), - input: Schema.Finite, - output: Schema.Finite, - cache: Schema.Struct({ - read: Schema.Finite, - write: Schema.Finite, - }), -}) - -export const Ref = Schema.Struct({ - id: ID, - providerID: ProviderID, - variant: VariantID, -}) -export type Ref = typeof Ref.Type - -export class Info extends Schema.Class("Model.Info")({ - id: ID, - providerID: ProviderID, - family: Family.pipe(Schema.optional), - name: Schema.String, - endpoint: Endpoint, - capabilities: Capabilities, - options: Schema.Struct({ - ...Options.fields, - variant: Schema.String.pipe(Schema.optional), - }), - variants: Schema.Struct({ - id: VariantID, - ...Options.fields, - }).pipe(Schema.Array), - time: Schema.Struct({ - released: DateTimeUtcFromMillis, - }), - cost: Cost.pipe(Schema.Array), - status: ModelStatus, - limit: Schema.Struct({ - context: Schema.Int, - input: Schema.Int.pipe(Schema.optional), - output: Schema.Int, - }), -}) {} - -export function parse(input: string): { providerID: ProviderID; modelID: ID } { - const [providerID, ...modelID] = input.split("/") - return { - providerID: ProviderID.make(providerID), - modelID: ID.make(modelID.join("/")), - } -} - -export interface Interface { - readonly get: (providerID: ProviderID, modelID: ID) => Effect.Effect> - readonly add: (model: Info) => Effect.Effect - readonly remove: (providerID: ProviderID, modelID: ID) => Effect.Effect - readonly all: () => Effect.Effect - readonly default: () => Effect.Effect> - readonly small: (provider: ProviderID) => Effect.Effect> -} - -export class Service extends Context.Service()("@opencode/v2/Model") {} - -export const layer = Layer.effect( - Service, - Effect.gen(function* () { - let models = HashMap.empty() - - function key(providerID: ProviderID, modelID: ID) { - return `${providerID}/${modelID}` - } - - const result: Interface = { - get: Effect.fn("V2Model.get")(function* (providerID, modelID) { - return HashMap.get(models, key(providerID, modelID)) - }), - - add: Effect.fn("V2Model.add")(function* (model) { - models = HashMap.set(models, key(model.providerID, model.id), model) - }), - - remove: Effect.fn("V2Model.remove")(function* (providerID, modelID) { - models = HashMap.remove(models, key(providerID, modelID)) - }), - - all: Effect.fn("V2Model.all")(function* () { - return pipe( - models, - HashMap.toValues, - Array.sortWith((item) => item.time.released.epochMilliseconds, Order.flip(Order.Number)), - ) - }), - - default: Effect.fn("V2Model.default")(function* () { - const all = yield* result.all() - return Option.fromUndefinedOr(all[0]) - }), - - small: Effect.fn("V2Model.small")(function* (providerID) { - const all = yield* result.all() - const match = all.find((model) => model.providerID === providerID && model.id.toLowerCase().includes("small")) - return Option.fromUndefinedOr(match) - }), - } - - return Service.of(result) - }), -) - -export const defaultLayer = layer - -export * as Modelv2 from "./model" diff --git a/packages/opencode/src/v2/plugin-boot.ts b/packages/opencode/src/v2/plugin-boot.ts new file mode 100644 index 0000000000..d19872f2d2 --- /dev/null +++ b/packages/opencode/src/v2/plugin-boot.ts @@ -0,0 +1,50 @@ +export * as PluginBoot from "./plugin-boot" + +import { Npm } from "@opencode-ai/core/npm" +import { Effect, Layer } from "effect" +import { AuthV2 } from "@opencode-ai/core/auth" +import { Catalog } from "@opencode-ai/core/catalog" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AuthPlugin } from "@opencode-ai/core/plugin/auth" +import { EnvPlugin } from "@opencode-ai/core/plugin/env" +import { ProviderPlugins } from "@opencode-ai/core/plugin/provider" +import { ModelsDevPlugin } from "./plugin/models-dev" + +type Plugin = { + id: PluginV2.ID + effect: Effect.Effect +} + +export const layer = Layer.effectDiscard( + Effect.gen(function* () { + const catalog = yield* Catalog.Service + const plugin = yield* PluginV2.Service + const auth = yield* AuthV2.Service + const npm = yield* Npm.Service + + 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), + ), + }) + }) + + yield* add(EnvPlugin) + yield* add(AuthPlugin) + for (const item of ProviderPlugins) { + yield* add(item) + } + yield* add(ModelsDevPlugin) + }), +) + +export const defaultLayer = layer.pipe( + Layer.provide(Catalog.defaultLayer), + Layer.provide(PluginV2.defaultLayer), + Layer.provide(Layer.orDie(AuthV2.defaultLayer)), + Layer.provide(Npm.defaultLayer), +) diff --git a/packages/opencode/src/v2/plugin/models-dev.ts b/packages/opencode/src/v2/plugin/models-dev.ts new file mode 100644 index 0000000000..7c0e902c79 --- /dev/null +++ b/packages/opencode/src/v2/plugin/models-dev.ts @@ -0,0 +1,108 @@ +import { DateTime, Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" +import { ModelV2 } from "@opencode-ai/core/model" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { ModelsDev } from "@/provider/models" +import { PluginV2 } from "@opencode-ai/core/plugin" + +function released(date: string) { + const time = Date.parse(date) + return DateTime.makeUnsafe(Number.isFinite(time) ? time : 0) +} + +function cost(input: ModelsDev.Model["cost"]) { + const base = { + input: input?.input ?? 0, + output: input?.output ?? 0, + cache: { + read: input?.cache_read ?? 0, + write: input?.cache_write ?? 0, + }, + } + if (!input?.context_over_200k) return [base] + return [ + base, + { + tier: { + type: "context" as const, + size: 200_000, + }, + input: input.context_over_200k.input, + output: input.context_over_200k.output, + cache: { + read: input.context_over_200k.cache_read ?? 0, + write: input.context_over_200k.cache_write ?? 0, + }, + }, + ] +} + +function variants(model: ModelsDev.Model) { + return Object.entries(model.experimental?.modes ?? {}).map(([id, item]) => ({ + id: ModelV2.VariantID.make(id), + headers: { ...(item.provider?.headers ?? {}) }, + body: { ...(item.provider?.body ?? {}) }, + aisdk: { + provider: {}, + request: {}, + }, + })) +} + +export const ModelsDevPlugin = PluginV2.define({ + id: PluginV2.ID.make("models-dev"), + 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 + ? { + 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, + } + }) + .pipe(Effect.orDie) + } + } + }).pipe(Effect.provide(ModelsDev.defaultLayer)), +}) diff --git a/packages/opencode/src/v2/provider-parity-checklist.md b/packages/opencode/src/v2/provider-parity-checklist.md new file mode 100644 index 0000000000..e3a599d8ec --- /dev/null +++ b/packages/opencode/src/v2/provider-parity-checklist.md @@ -0,0 +1,95 @@ +# Unported Provider Logic Checklist + +This tracks legacy provider behavior from `packages/opencode/src/provider/provider.ts` that still needs to be ported into the v2 provider plugins under `packages/opencode/src/v2/plugin/provider/`. Keep entries checked only when v2 has equivalent behavior or when the item is intentionally skipped. + +## Provider Setup + +- [x] Cloudflare AI Gateway custom SDK construction with `createAiGateway` / `createUnified`. +- [x] Google Vertex authenticated `fetch` injection. +- [x] Amazon Bedrock AWS credential chain setup. +- [x] Amazon Bedrock bearer token setup. +- [x] SAP AI Core service key setup. + +## Provider Options + +- [x] Azure resource name resolution. +- [x] Azure missing-resource error. +- [x] Azure Cognitive Services baseURL resolution. +- [x] Cloudflare Workers AI account ID validation. +- [x] Cloudflare Workers AI account ID vars. +- [x] Cloudflare AI Gateway account ID validation. +- [x] Cloudflare AI Gateway gateway ID validation. +- [x] Cloudflare AI Gateway token validation. +- [x] Amazon Bedrock region precedence. +- [x] Amazon Bedrock profile precedence. +- [x] Amazon Bedrock endpoint precedence. +- [x] Google Vertex project resolution. +- [x] Google Vertex location resolution. +- [x] GitLab instance URL resolution. +- [x] GitLab token resolution. +- [x] GitLab AI gateway headers. +- [x] GitLab feature flags. +- [x] Opencode unauthenticated paid-model filtering. +- [x] Opencode public API key fallback. + +## Request Behavior + +- [x] Request timeout handling. +- [x] Chunk timeout handling. +- [x] SSE timeout wrapping. +- [x] OpenAI response item ID stripping. +- [x] Azure response item ID stripping. +- [x] OpenAI-compatible `includeUsage` defaulting. + +## Dynamic Models + +- [ ] GitLab workflow model discovery. + +## Model Filtering + +- [ ] Experimental alpha model filtering. +- [ ] Deprecated model filtering. +- [ ] Config whitelist filtering. +- [ ] Config blacklist filtering. +- [ ] `gpt-5-chat-latest` filtering. +- [ ] OpenRouter `openai/gpt-5-chat` filtering. + +## Default Models + +- [x] Configured default model selection. Replaced by explicit `Catalog.model.setDefault`. +- [SKIP] Recent-history default model selection — not porting to server-side v2 catalog. +- [x] Default model fallback sorting. Uses newest available model, not legacy hard-coded priority. + +## Small Models + +- [SKIP] Configured `small_model` selection — not porting config-driven selection to server-side v2 catalog. +- [x] Provider-specific small model priority. Replaced by cheapest output cost selection. +- [x] Opencode small model priority. Replaced by cheapest output cost selection. +- [x] GitHub Copilot small model priority. Replaced by cheapest output cost selection. +- [x] Amazon Bedrock region-aware small model selection. Replaced by cheapest output cost selection. + +## URL And Env Vars + +- [SKIP] BaseURL `${VAR}` interpolation — not porting generic URL templating; provider plugins should construct concrete URLs. +- [x] Azure `AZURE_RESOURCE_NAME` vars. Handled by Azure provider plugins. +- [x] Google Vertex vars. Handled by Google Vertex provider plugins. +- [x] Cloudflare Workers AI vars. Handled by Cloudflare Workers AI provider plugin. + +## Auth + +- [ ] Auth-derived provider API keys. +- [ ] OpenAI OAuth/API auth distinction. +- [ ] GitLab OAuth token selection. +- [ ] GitLab API token selection. +- [ ] Azure auth metadata resource name. +- [ ] Cloudflare auth metadata account ID. +- [ ] Cloudflare auth metadata gateway ID. + +## Config And Plugin Parity + +- [ ] Legacy plugin auth loader behavior. +- [ ] Config provider merge behavior. +- [ ] Config model merge behavior. +- [ ] Variant generation from model metadata. +- [ ] Config variant merge behavior. +- [ ] Config variant disable behavior. diff --git a/packages/opencode/src/v2/session-event.ts b/packages/opencode/src/v2/session-event.ts index fa211bd8c4..1fd0f909d5 100644 --- a/packages/opencode/src/v2/session-event.ts +++ b/packages/opencode/src/v2/session-event.ts @@ -1,12 +1,12 @@ import { SessionID } from "@/session/schema" import { NonNegativeInt } from "@opencode-ai/core/schema" import { EventV2 } from "./event" -import { FileAttachment, Prompt } from "./session-prompt" +import { FileAttachment, Prompt } from "@opencode-ai/core/session-prompt" import { Schema } from "effect" export { FileAttachment } -import { ToolOutput } from "./tool-output" -import { V2Schema } from "./schema" -import { Modelv2 } from "./model" +import { ToolOutput } from "@opencode-ai/core/tool-output" +import { V2Schema } from "@opencode-ai/core/v2-schema" +import { ModelV2 } from "@opencode-ai/core/model" export const Source = Schema.Struct({ start: NonNegativeInt, @@ -47,7 +47,7 @@ export const ModelSwitched = EventV2.define({ version: 1, schema: { ...Base, - model: Modelv2.Ref, + model: ModelV2.Ref, }, }) export type ModelSwitched = Schema.Schema.Type @@ -104,7 +104,7 @@ export namespace Step { schema: { ...Base, agent: Schema.String, - model: Modelv2.Ref, + model: ModelV2.Ref, snapshot: Schema.String.pipe(Schema.optional), }, }) diff --git a/packages/opencode/src/v2/session-message.ts b/packages/opencode/src/v2/session-message.ts index 62fc75fc83..fa7c299ae5 100644 --- a/packages/opencode/src/v2/session-message.ts +++ b/packages/opencode/src/v2/session-message.ts @@ -1,10 +1,10 @@ import { Schema } from "effect" -import { Prompt } from "./session-prompt" +import { Prompt } from "@opencode-ai/core/session-prompt" import { SessionEvent } from "./session-event" import { EventV2 } from "./event" -import { ToolOutput } from "./tool-output" -import { V2Schema } from "./schema" -import { Modelv2 } from "./model" +import { ToolOutput } from "@opencode-ai/core/tool-output" +import { V2Schema } from "@opencode-ai/core/v2-schema" +import { ModelV2 } from "@opencode-ai/core/model" export const ID = EventV2.ID export type ID = Schema.Schema.Type @@ -26,7 +26,7 @@ export class AgentSwitched extends Schema.Class("Session.Message. export class ModelSwitched extends Schema.Class("Session.Message.ModelSwitched")({ ...Base, type: Schema.Literal("model-switched"), - model: Modelv2.Ref, + model: ModelV2.Ref, }) {} export class User extends Schema.Class("Session.Message.User")({ diff --git a/packages/opencode/src/v2/session.ts b/packages/opencode/src/v2/session.ts index f6084cb4c0..97c31d39b2 100644 --- a/packages/opencode/src/v2/session.ts +++ b/packages/opencode/src/v2/session.ts @@ -5,14 +5,15 @@ import { and, asc, desc, eq, gt, gte, isNull, like, lt, or, type SQL } from "@/s import * as Database from "@/storage/db" import { Context, DateTime, Effect, Layer, Option, Schema } from "effect" import { SessionMessage } from "./session-message" -import type { Prompt } from "./session-prompt" +import type { Prompt } from "@opencode-ai/core/session-prompt" import { EventV2 } from "./event" import { ProjectID } from "@/project/schema" import { SessionEvent } from "./session-event" -import { V2Schema } from "./schema" +import { V2Schema } from "@opencode-ai/core/v2-schema" import { optionalOmitUndefined } from "@opencode-ai/core/schema" -import { Modelv2 } from "./model" import { SyncEvent } from "@/sync" +import { ModelV2 } from "@opencode-ai/core/model" +import { ProviderV2 } from "@opencode-ai/core/provider" export const Delivery = Schema.Literals(["immediate", "deferred"]).annotate({ identifier: "Session.Delivery", @@ -28,7 +29,7 @@ export class Info extends Schema.Class("Session.Info")({ workspaceID: optionalOmitUndefined(WorkspaceID), path: optionalOmitUndefined(Schema.String), agent: optionalOmitUndefined(Schema.String), - model: Modelv2.Ref.pipe(optionalOmitUndefined), + model: ModelV2.Ref.pipe(optionalOmitUndefined), cost: Schema.Finite, tokens: Schema.Struct({ input: Schema.Finite, @@ -67,7 +68,7 @@ export class NotFoundError extends Schema.TaggedErrorClass()("Ses export interface Interface { readonly create: (input?: { agent?: string - model?: Modelv2.Ref + model?: ModelV2.Ref parentID?: SessionID workspaceID?: WorkspaceID }) => Effect.Effect @@ -111,10 +112,10 @@ export interface Interface { parentID: SessionID prompt: Prompt agent: string - model?: Modelv2.Ref + model?: ModelV2.Ref }) => Effect.Effect readonly switchAgent: (input: { sessionID: SessionID; agent: string }) => Effect.Effect - readonly switchModel: (input: { sessionID: SessionID; model: Modelv2.Ref }) => Effect.Effect + readonly switchModel: (input: { sessionID: SessionID; model: ModelV2.Ref }) => Effect.Effect readonly compact: (sessionID: SessionID) => Effect.Effect readonly wait: (sessionID: SessionID) => Effect.Effect } @@ -141,9 +142,9 @@ export const layer = Layer.effect( agent: row.agent ?? undefined, model: row.model ? { - id: Modelv2.ID.make(row.model.id), - providerID: Modelv2.ProviderID.make(row.model.providerID), - variant: Modelv2.VariantID.make(row.model.variant ?? "default"), + id: ModelV2.ID.make(row.model.id), + providerID: ProviderV2.ID.make(row.model.providerID), + variant: ModelV2.VariantID.make(row.model.variant ?? "default"), } : undefined, cost: row.cost, @@ -164,7 +165,7 @@ export const layer = Layer.effect( }) } - const result: Interface = { + const result = Service.of({ create: Effect.fn("V2Session.create")(function* (_input) { return {} as any }), @@ -306,7 +307,7 @@ export const layer = Layer.effect( }), subagent: Effect.fn("V2Session.subagent")(function* (input) { const parent = yield* result.get(input.parentID) - const session = yield* result.create({ + const child = yield* result.create({ agent: input.agent, model: input.model, parentID: input.parentID, @@ -314,11 +315,11 @@ export const layer = Layer.effect( }) yield* result.prompt({ prompt: input.prompt, - sessionID: session.id, + sessionID: child.id, }) yield* Effect.gen(function* () { - yield* result.wait(session.id) - const messages = yield* result.messages({ sessionID: session.id, order: "desc" }) + yield* result.wait(child.id) + const messages = yield* result.messages({ sessionID: child.id, order: "desc" }) const assistant = messages.find((msg) => msg.type === "assistant") if (!assistant) return const text = assistant.content.findLast((part) => part.type === "text") @@ -327,9 +328,9 @@ export const layer = Layer.effect( }), compact: Effect.fn("V2Session.compact")(function* (_sessionID) {}), wait: Effect.fn("V2Session.wait")(function* (_sessionID) {}), - } + }) - return Service.of(result) + return result }), ) diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts index 439f36e0a9..8f79102080 100644 --- a/packages/opencode/src/worktree/index.ts +++ b/packages/opencode/src/worktree/index.ts @@ -1,5 +1,3 @@ -import z from "zod" -import { NamedError } from "@opencode-ai/core/util/error" import { Global } from "@opencode-ai/core/global" import { InstanceLayer } from "@/project/instance-layer" import { InstanceStore } from "@/project/instance-store" @@ -14,12 +12,12 @@ import { errorMessage } from "../util/error" import { BusEvent } from "@/bus/bus-event" import { GlobalBus } from "@/bus/global" import { Git } from "@/git" -import { Effect, Layer, Path, Schema, Scope, Context, Stream } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { Effect, Layer, Path, Schema, Scope, Context } from "effect" +import { ChildProcess } from "effect/unstable/process" import { NodePath } from "@effect/platform-node" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { BootstrapRuntime } from "@/effect/bootstrap-runtime" -import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { AppProcess } from "@opencode-ai/core/process" import { InstanceState } from "@/effect/instance-state" const log = Log.create({ service: "worktree" }) @@ -65,54 +63,48 @@ export const ResetInput = Schema.Struct({ }).annotate({ identifier: "WorktreeResetInput" }) export type ResetInput = Schema.Schema.Type -export const NotGitError = NamedError.create( - "WorktreeNotGitError", - z.object({ - message: z.string(), - }), -) +export class NotGitError extends Schema.TaggedErrorClass()("WorktreeNotGitError", { + message: Schema.String, +}) {} -export const NameGenerationFailedError = NamedError.create( +export class NameGenerationFailedError extends Schema.TaggedErrorClass()( "WorktreeNameGenerationFailedError", - z.object({ - message: z.string(), - }), -) + { + message: Schema.String, + }, +) {} -export const CreateFailedError = NamedError.create( - "WorktreeCreateFailedError", - z.object({ - message: z.string(), - }), -) +export class CreateFailedError extends Schema.TaggedErrorClass()("WorktreeCreateFailedError", { + message: Schema.String, +}) {} -export const StartCommandFailedError = NamedError.create( +export class StartCommandFailedError extends Schema.TaggedErrorClass()( "WorktreeStartCommandFailedError", - z.object({ - message: z.string(), - }), -) + { + message: Schema.String, + }, +) {} -export const RemoveFailedError = NamedError.create( - "WorktreeRemoveFailedError", - z.object({ - message: z.string(), - }), -) +export class RemoveFailedError extends Schema.TaggedErrorClass()("WorktreeRemoveFailedError", { + message: Schema.String, +}) {} -export const ResetFailedError = NamedError.create( - "WorktreeResetFailedError", - z.object({ - message: z.string(), - }), -) +export class ResetFailedError extends Schema.TaggedErrorClass()("WorktreeResetFailedError", { + message: Schema.String, +}) {} -export const ListFailedError = NamedError.create( - "WorktreeListFailedError", - z.object({ - message: z.string(), - }), -) +export class ListFailedError extends Schema.TaggedErrorClass()("WorktreeListFailedError", { + message: Schema.String, +}) {} + +export type Error = + | NotGitError + | NameGenerationFailedError + | CreateFailedError + | StartCommandFailedError + | RemoveFailedError + | ResetFailedError + | ListFailedError function slugify(input: string) { return input @@ -143,12 +135,12 @@ function failedRemoves(...chunks: string[]) { // --------------------------------------------------------------------------- export interface Interface { - readonly makeWorktreeInfo: (options?: { name?: string; detached?: boolean }) => Effect.Effect - readonly createFromInfo: (info: Info, startCommand?: string) => Effect.Effect - readonly create: (input?: CreateInput) => Effect.Effect - readonly list: () => Effect.Effect<(Omit & { branch?: string })[]> - readonly remove: (input: RemoveInput) => Effect.Effect - readonly reset: (input: ResetInput) => Effect.Effect + readonly makeWorktreeInfo: (options?: { name?: string; detached?: boolean }) => Effect.Effect + readonly createFromInfo: (info: Info, startCommand?: string) => Effect.Effect + readonly create: (input?: CreateInput) => Effect.Effect + readonly list: () => Effect.Effect<(Omit & { branch?: string })[], Error> + readonly remove: (input: RemoveInput) => Effect.Effect + readonly reset: (input: ResetInput) => Effect.Effect } export class Service extends Context.Service()("@opencode/Worktree") {} @@ -158,38 +150,35 @@ type GitResult = { code: number; text: string; stderr: string } export const layer: Layer.Layer< Service, never, - | AppFileSystem.Service - | Path.Path - | ChildProcessSpawner.ChildProcessSpawner - | Git.Service - | Project.Service - | InstanceStore.Service + AppFileSystem.Service | Path.Path | AppProcess.Service | Git.Service | Project.Service | InstanceStore.Service > = Layer.effect( Service, Effect.gen(function* () { const scope = yield* Scope.Scope const fs = yield* AppFileSystem.Service const pathSvc = yield* Path.Path - const spawner = yield* ChildProcessSpawner.ChildProcessSpawner + const appProcess = yield* AppProcess.Service const gitSvc = yield* Git.Service const project = yield* Project.Service const store = yield* InstanceStore.Service const git = Effect.fnUntraced( function* (args: string[], opts?: { cwd?: string }) { - const handle = yield* spawner.spawn( + const result = yield* appProcess.run( ChildProcess.make("git", args, { cwd: opts?.cwd, extendEnv: true, stdin: "ignore" }), ) - const [text, stderr] = yield* Effect.all( - [Stream.mkString(Stream.decodeText(handle.stdout)), Stream.mkString(Stream.decodeText(handle.stderr))], - { concurrency: 2 }, - ) - const code = yield* handle.exitCode - return { code, text, stderr } satisfies GitResult + return { + code: result.exitCode, + text: result.stdout.toString("utf8"), + stderr: result.stderr.toString("utf8"), + } satisfies GitResult }, - Effect.scoped, Effect.catch((e) => - Effect.succeed({ code: 1, text: "", stderr: e instanceof Error ? e.message : String(e) } satisfies GitResult), + Effect.succeed({ + code: 1, + text: "", + stderr: e instanceof Error ? e.message : String(e), + } satisfies GitResult), ), ) @@ -215,7 +204,7 @@ export const layer: Layer.Layer< return { name, directory, ...(branch ? { branch } : {}) } } - throw new NameGenerationFailedError({ message: "Failed to generate a unique worktree name" }) + return yield* new NameGenerationFailedError({ message: "Failed to generate a unique worktree name" }) }) const makeWorktreeInfo = Effect.fn("Worktree.makeWorktreeInfo")(function* (input?: { @@ -224,7 +213,7 @@ export const layer: Layer.Layer< }) { const ctx = yield* InstanceState.context if (ctx.project.vcs !== "git") { - throw new NotGitError({ message: "Worktrees are only supported for git projects" }) + return yield* new NotGitError({ message: "Worktrees are only supported for git projects" }) } const root = pathSvc.join(Global.Path.data, "worktree", ctx.project.id) @@ -242,7 +231,9 @@ export const layer: Layer.Layer< { cwd: ctx.worktree }, ) if (created.code !== 0) { - throw new CreateFailedError({ message: created.stderr || created.text || "Failed to create git worktree" }) + return yield* new CreateFailedError({ + message: created.stderr || created.text || "Failed to create git worktree", + }) } yield* project.addSandbox(ctx.project.id, info.directory).pipe(Effect.catch(() => Effect.void)) @@ -358,7 +349,7 @@ export const layer: Layer.Layer< const result = yield* git(["worktree", "list", "--porcelain"], { cwd: ctx.worktree }) if (result.code !== 0) { - throw new ListFailedError({ message: result.stderr || result.text || "Failed to read git worktrees" }) + return yield* new ListFailedError({ message: result.stderr || result.text || "Failed to read git worktrees" }) } const primary = yield* canonical(ctx.worktree) @@ -386,27 +377,27 @@ export const layer: Layer.Layer< } function cleanDirectory(target: string) { - return Effect.promise(() => - import("fs/promises") - .then((fsp) => fsp.rm(target, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })) - .catch((error) => { - const message = errorMessage(error) - throw new RemoveFailedError({ message: message || "Failed to remove git worktree directory" }) - }), - ) + return Effect.tryPromise({ + try: () => + import("fs/promises").then((fsp) => + fsp.rm(target, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }), + ), + catch: (error) => + new RemoveFailedError({ message: errorMessage(error) || "Failed to remove git worktree directory" }), + }) } const remove = Effect.fn("Worktree.remove")(function* (input: RemoveInput) { const ctx = yield* InstanceState.context if (ctx.project.vcs !== "git") { - throw new NotGitError({ message: "Worktrees are only supported for git projects" }) + return yield* new NotGitError({ message: "Worktrees are only supported for git projects" }) } const directory = yield* canonical(input.directory) const list = yield* git(["worktree", "list", "--porcelain"], { cwd: ctx.worktree }) if (list.code !== 0) { - throw new RemoveFailedError({ message: list.stderr || list.text || "Failed to read git worktrees" }) + return yield* new RemoveFailedError({ message: list.stderr || list.text || "Failed to read git worktrees" }) } const entries = parseWorktreeList(list.text) @@ -426,14 +417,16 @@ export const layer: Layer.Layer< if (removed.code !== 0) { const next = yield* git(["worktree", "list", "--porcelain"], { cwd: ctx.worktree }) if (next.code !== 0) { - throw new RemoveFailedError({ + return yield* new RemoveFailedError({ message: removed.stderr || removed.text || next.stderr || next.text || "Failed to remove git worktree", }) } const stale = yield* locateWorktree(parseWorktreeList(next.text), directory) if (stale?.path) { - throw new RemoveFailedError({ message: removed.stderr || removed.text || "Failed to remove git worktree" }) + return yield* new RemoveFailedError({ + message: removed.stderr || removed.text || "Failed to remove git worktree", + }) } } @@ -443,7 +436,7 @@ export const layer: Layer.Layer< if (branch) { const deleted = yield* git(["branch", "-D", branch], { cwd: ctx.worktree }) if (deleted.code !== 0) { - throw new RemoveFailedError({ + return yield* new RemoveFailedError({ message: deleted.stderr || deleted.text || "Failed to delete worktree branch", }) } @@ -458,25 +451,18 @@ export const layer: Layer.Layer< error: (r: GitResult) => Error, ) { const result = yield* git(args, opts) - if (result.code !== 0) throw error(result) + if (result.code !== 0) return yield* error(result) return result }) const runStartCommand = Effect.fnUntraced( function* (directory: string, cmd: string) { const [shell, args] = process.platform === "win32" ? ["cmd", ["/c", cmd]] : ["bash", ["-lc", cmd]] - const handle = yield* spawner.spawn( - ChildProcess.make(shell, args, { cwd: directory, extendEnv: true, stdin: "ignore" }), + const result = yield* appProcess.run( + ChildProcess.make(shell, args as string[], { cwd: directory, extendEnv: true, stdin: "ignore" }), ) - // Drain stdout, capture stderr for error reporting - const [, stderr] = yield* Effect.all( - [Stream.runDrain(handle.stdout), Stream.mkString(Stream.decodeText(handle.stderr))], - { concurrency: 2 }, - ).pipe(Effect.orDie) - const code = yield* handle.exitCode - return { code, stderr } + return { code: result.exitCode, stderr: result.stderr.toString("utf8") } }, - Effect.scoped, Effect.catch(() => Effect.succeed({ code: 1, stderr: "" })), ) @@ -533,30 +519,30 @@ export const layer: Layer.Layer< const reset = Effect.fn("Worktree.reset")(function* (input: ResetInput) { const ctx = yield* InstanceState.context if (ctx.project.vcs !== "git") { - throw new NotGitError({ message: "Worktrees are only supported for git projects" }) + return yield* new NotGitError({ message: "Worktrees are only supported for git projects" }) } const directory = yield* canonical(input.directory) const primary = yield* canonical(ctx.worktree) if (directory === primary) { - throw new ResetFailedError({ message: "Cannot reset the primary workspace" }) + return yield* new ResetFailedError({ message: "Cannot reset the primary workspace" }) } const list = yield* git(["worktree", "list", "--porcelain"], { cwd: ctx.worktree }) if (list.code !== 0) { - throw new ResetFailedError({ message: list.stderr || list.text || "Failed to read git worktrees" }) + return yield* new ResetFailedError({ message: list.stderr || list.text || "Failed to read git worktrees" }) } const entry = yield* locateWorktree(parseWorktreeList(list.text), directory) if (!entry?.path) { - throw new ResetFailedError({ message: "Worktree not found" }) + return yield* new ResetFailedError({ message: "Worktree not found" }) } const worktreePath = entry.path const base = yield* gitSvc.defaultBranch(ctx.worktree) if (!base) { - throw new ResetFailedError({ message: "Default branch not found" }) + return yield* new ResetFailedError({ message: "Default branch not found" }) } const sep = base.ref.indexOf("/") @@ -578,7 +564,9 @@ export const layer: Layer.Layer< const cleanResult = yield* sweep(worktreePath) if (cleanResult.code !== 0) { - throw new ResetFailedError({ message: cleanResult.stderr || cleanResult.text || "Failed to clean worktree" }) + return yield* new ResetFailedError({ + message: cleanResult.stderr || cleanResult.text || "Failed to clean worktree", + }) } yield* gitExpect( @@ -601,11 +589,11 @@ export const layer: Layer.Layer< const status = yield* git(["-c", "core.fsmonitor=false", "status", "--porcelain=v1"], { cwd: worktreePath }) if (status.code !== 0) { - throw new ResetFailedError({ message: status.stderr || status.text || "Failed to read git status" }) + return yield* new ResetFailedError({ message: status.stderr || status.text || "Failed to read git status" }) } if (status.text.trim()) { - throw new ResetFailedError({ message: `Worktree reset left local changes:\n${status.text.trim()}` }) + return yield* new ResetFailedError({ message: `Worktree reset left local changes:\n${status.text.trim()}` }) } yield* runStartScripts(worktreePath, { projectID: ctx.project.id }).pipe( @@ -622,7 +610,7 @@ export const layer: Layer.Layer< export const appLayer = layer.pipe( Layer.provide(Git.defaultLayer), - Layer.provide(CrossSpawnSpawner.defaultLayer), + Layer.provide(AppProcess.defaultLayer), Layer.provide(Project.defaultLayer), Layer.provide(AppFileSystem.defaultLayer), Layer.provide(NodePath.layer), diff --git a/packages/opencode/test/EFFECT_TEST_MIGRATION.md b/packages/opencode/test/EFFECT_TEST_MIGRATION.md index 2c160b993d..73acea9148 100644 --- a/packages/opencode/test/EFFECT_TEST_MIGRATION.md +++ b/packages/opencode/test/EFFECT_TEST_MIGRATION.md @@ -1,16 +1,21 @@ -# Effect Test Migration Plan +# Effect Test Migration -This document describes how to move opencode tests out of Promise-land and into the shared `testEffect` pattern. +Move tests that exercise Effect services out of Promise-land and into the +shared `testEffect` pattern. + +This file is guidance, not a live inventory. Before claiming a migration, +search current `dev` for the exact anti-pattern and update any PR notes +with what you actually changed. ## Target Pattern -Every test file that exercises Effect services should have one local runner near the top: +Every Effect service test should have one local runner near the top: ```ts const it = testEffect(layer) ``` -Then each test should use one of the runner methods: +Use the runner method that matches the behavior: ```ts it.effect("pure service behavior", () => @@ -23,7 +28,7 @@ it.effect("pure service behavior", () => it.instance("instance-local behavior", () => Effect.gen(function* () { const test = yield* TestInstance - // test.directory is a scoped temp opencode instance + expect(test.directory).toContain("opencode-test-") }), ) @@ -35,40 +40,22 @@ it.live("live filesystem or process behavior", () => ) ``` -Use `it.effect` for pure Effect code that should run with `TestClock` and `TestConsole`. -Use `it.instance` when the test needs one scoped opencode instance. -Use `it.live` when the test depends on real time, filesystem mtimes, git, child processes, servers, file watchers, or OS behavior. +## Choosing The Runner -## Anti-Patterns To Remove +- `it.effect(...)` — pure Effect behavior with `TestClock` and + `TestConsole`. +- `it.instance(...)` — service behavior that needs one scoped opencode + instance. +- `it.live(...)` — real time, filesystem mtimes, child processes, git, + locks, servers, watchers, or OS behavior. -Avoid these in tests that already target Effect services: - -- `test(..., async () => Effect.runPromise(...))` -- local `run(...)`, `load(...)`, `svc(...)`, or `runtime.runPromise(...)` wrappers that only provide a layer -- `tmpdir()` plus `WithInstance.provide(...)` in Promise test bodies -- custom `ManagedRuntime.make(...)` in test files -- Promise `try/catch` around Effect failures -- `Promise.withResolvers`, `Bun.sleep`, or `setTimeout` for synchronization when `Deferred`, `Fiber`, or `Effect.sleep` can express the same behavior - -Promise helpers are acceptable at the boundary for non-Effect APIs, but they should be yielded from an Effect body with `Effect.promise(...)` rather than becoming the test harness. +Most integration-style tests use `it.live(...)` or `it.instance(...)`. ## Layer Rules -Compose tests from open service layers, not closed `defaultLayer` graphs when a dependency needs replacing. - -Good: - -```ts -const layer = Config.layer.pipe( - Layer.provide(AppFileSystem.defaultLayer), - Layer.provide(Env.defaultLayer), - Layer.provide(AuthTest.empty), - Layer.provide(AccountTest.empty), - Layer.provide(NpmTest.noop), -) -``` - -Avoid using a fully closed layer and hoping to override an inner dependency later. Once `Agent.defaultLayer` has already provided `Config.defaultLayer`, tests cannot cleanly swap the `Npm.Service` used by that config layer. +Compose tests from open service layers when a dependency needs replacing. +Do not use a closed `defaultLayer` and then try to override an inner +dependency after it has already been provided. Prefer small reusable fake boundary layers in `test/fake/*`: @@ -80,146 +67,103 @@ SkillTest.empty ProviderTest.fake().layer ``` -Do not add generic test-layer builders until repeated local compositions prove the need. Shared fake boundary services are the first reusable unit. Pre-composed subtrees such as `AgentTest.withPlugins` should come later, only after the same graph appears in multiple files. +Use `Layer.mock` for partial service stubs. Missing methods should fail +loudly if the test accidentally calls them. + +Do not add generic test-layer builders until repeated local compositions +prove the need. ## Fixture Rules Use Effect-aware fixtures from `test/fixture/fixture.ts`: -- `TestInstance` inside `it.instance(...)` for the current temp instance path -- `tmpdirScoped(...)` inside `Effect.gen` for additional temp directories -- `provideInstance(dir)(effect)` when one test needs to switch instance context -- `provideTmpdirInstance((dir) => effect, options)` when a live test needs custom instance setup or multiple instance scopes -- `disposeAllInstances()` in `afterEach` only for integration tests that intentionally touch shared instance registries +- `TestInstance` inside `it.instance(...)` for the current temp instance. +- `tmpdirScoped(...)` inside `Effect.gen` for extra temp directories. +- `provideInstance(dir)(effect)` when one test needs to switch instance + context. +- `provideTmpdirInstance((dir) => effect, options)` when a live test needs + custom instance setup or multiple instance scopes. +- `disposeAllInstances()` in `afterEach` only for integration tests that + intentionally touch shared instance registries. -Use finalizers only as a temporary bridge for existing global mutations: +Avoid mutable global setup. If a global mutation is unavoidable during a +migration, scope it with acquire/release and treat it as temporary. -```ts -yield * - Effect.acquireUseRelease( - Effect.sync(() => { - const previous = process.env.MY_FLAG - process.env.MY_FLAG = "1" - return previous - }), - () => testBody, - (previous) => - Effect.sync(() => { - if (previous === undefined) delete process.env.MY_FLAG - else process.env.MY_FLAG = previous - }), - ) -``` +Long term, tests should not toggle `process.env`, `Global.Path`, or +mutable flags when behavior can be modeled with services. Prefer layers +such as `RuntimeFlags.layer(...)` or focused fake services. -TODO: eliminate this pattern over time. Tests should not toggle process-global flags or env vars when the behavior can be modeled with services. Prefer moving flag/env reads behind injectable services such as `Config.Service`, `Env.Service`, or focused test layers, then provide the desired test value through the layer graph instead of mutating `process.env` or `Global.Path`. +## Anti-Patterns To Remove + +- `test(..., async () => Effect.runPromise(...))` +- local `run(...)`, `load(...)`, `svc(...)`, or `runtime.runPromise(...)` + wrappers that only provide a layer +- `tmpdir()` plus legacy instance provision in Promise test bodies +- custom `ManagedRuntime.make(...)` in test files +- Promise `try/catch` around Effect failures +- `Promise.withResolvers`, `Bun.sleep`, or `setTimeout` for synchronization + when events, `Deferred`, fibers, or deterministic state checks fit +- mutable env/global/flag changes after layers are built + +Promise helpers are acceptable at non-Effect boundaries, but yield them from +inside an Effect body with `Effect.promise(...)` rather than making them the +test harness. ## Conversion Recipe -1. Identify the real service under test and its open `*.layer`. -2. Build one top-level `layer` with real dependencies where they are relevant and `test/fake/*` layers at slow or external boundaries. -3. Replace local Promise wrappers with Effect helpers: - -```ts -const run = Effect.fn("MyTest.run")(function* (input: Input) { - const service = yield* MyService.Service - return yield* service.run(input) -}) -``` - -4. Convert `test(..., async () => { ... })` to `it.effect`, `it.instance`, or `it.live`. +1. Identify the real service under test and whether its open `layer` or + closed `defaultLayer` is appropriate. +2. Build one top-level `layer` with real dependencies where relevant and + fake layers at slow or external boundaries. +3. Replace local Promise wrappers with Effect helpers. +4. Convert `test(..., async () => { ... })` to `it.effect`, `it.instance`, + or `it.live`. 5. Move `await` calls inside `Effect.gen` as `yield*` calls. -6. Replace `await using tmp = await tmpdir(...)` with `yield* tmpdirScoped(...)` when the temp directory is inside an Effect test. -7. Replace `WithInstance.provide({ directory, fn })` with `it.instance(...)`, `provideInstance(directory)(effect)`, or `provideTmpdirInstance(...)`. -8. Replace Promise failure assertions with Effect assertions: - -```ts -const exit = yield * run(input).pipe(Effect.exit) -expect(Exit.isFailure(exit)).toBe(true) -``` - -This is correct but still verbose. Track repeated assertion shapes during migration so we can add small test assertion helpers later instead of copying low-level `Exit` plumbing everywhere. - -9. Keep concurrency concurrent by using `Effect.forkScoped`, `Fiber.join`, `Deferred`, or `Effect.all(..., { concurrency: "unbounded" })` instead of serializing formerly parallel Promise work. -10. Run the focused test file and `bun typecheck` from `packages/opencode`. +6. Replace `await using tmp = await tmpdir(...)` with + `yield* tmpdirScoped(...)` when the temp directory lives inside the + Effect test. +7. Replace Promise failure assertions with `Effect.exit`, `Effect.flip`, or + focused assertion helpers. +8. Preserve concurrency with fibers, `Deferred`, and + `Effect.all(..., { concurrency: "unbounded" })`; do not accidentally + serialize formerly parallel behavior. +9. Run the focused test file and `bun typecheck` from `packages/opencode`. ## Good Examples -Use these files as models: +Use current examples as patterns, but re-check them before copying because +test migrations are active: -- `test/tool/write.test.ts`: strong `it.instance` tests, top-level `testEffect(...)`, and Effect-native test helpers. -- `test/effect/instance-state.test.ts`: good `it.live` use for scoped directories, instance switching, reload/disposal, and concurrency. -- `test/bus/bus-effect.test.ts`: good `Deferred`, streams, and scoped fibers. -- `test/tool/truncation.test.ts`: good configured runners and concise live service tests. -- `test/tool/repo_clone.test.ts`: good live git integration while staying inside Effect fixtures. -- `test/server/httpapi-instance.test.ts`: good scoped integration layer setup and live HTTP assertions. -- `test/account/service.test.ts`: good service-level live tests, `Effect.flip`, typed errors, and fake HTTP clients. -- `test/agent/plugin-agent-regression.test.ts`: good example of open real service layers plus reusable fake boundary layers. +- `test/effect/instance-state.test.ts` — scoped directories, instance + switching, disposal, and concurrency. +- `test/bus/bus-effect.test.ts` — `Deferred`, streams, scoped fibers. +- `test/agent/plugin-agent-regression.test.ts` — real service layers plus + fake boundary layers. +- `test/account/service.test.ts` — service-level live tests, typed errors, + fake HTTP clients. -## Current Promise-Land Hotspots +## Migration Queue Policy -Start with files that already exercise Effect services but still manually run Promises: +Do not maintain a long file checklist here. It goes stale quickly. -- `test/config/config.test.ts`: many `Effect.runPromise`, `tmpdir()`, and `WithInstance.provide(...)` patterns despite already having `const it = testEffect(layer)`. -- `test/tool/shell.test.ts`: custom `ManagedRuntime`, Promise test helpers, and instance setup around shell execution. -- `test/tool/edit.test.ts`: manual runtime helpers and Promise concurrency patterns that should become fibers/deferreds. -- `test/session/messages-pagination.test.ts`: local Promise service facade over `Session.defaultLayer`. -- `test/snapshot/snapshot.test.ts`: Promise helper with `provideInstance` around snapshot operations. -- `test/file/index.test.ts`: Promise wrappers for `File.Service` plus repeated temp instance setup. -- `test/provider/provider.test.ts`: `AppRuntime.runPromise` helpers and mutable env/config setup. -- `test/project/vcs.test.ts`: Promise event waiting and `AppRuntime.runPromise` around VCS service calls. +When looking for the next target, search for current anti-patterns: -## Migration Order +```bash +git grep -n "Effect.runPromise\|ManagedRuntime\|Promise.withResolvers\|Bun.sleep\|WithInstance" -- packages/opencode/test +``` -1. Convert one small file with straightforward service calls and no race behavior. -2. Convert `config.test.ts` incrementally by cluster, not in one PR. -3. Extract additional `test/fake/*` boundary layers only when a second test needs the same fake. -4. Convert files with concurrency or watchers after the simple files, preserving timing semantics with `Deferred` and fibers. -5. Leave pure non-Effect utility tests alone unless converting the underlying code to Effect. +Then choose one file or one small cluster, keep the PR focused, and mention +the focused verification in the PR body. -## Claimable Checklist +## Rough Edges To Watch -Use this as a migration queue. Each checkbox should be safe for one agent or one PR unless the notes say otherwise. Agents should claim one item, convert only that file or cluster, run the focused test file, run `bun typecheck`, and update this checklist in the PR description or follow-up note. - -- [ ] `test/file/index.test.ts`: straightforward service wrapper cleanup. Replace local Promise helpers with Effect helpers and use `it.instance` / `it.live` around existing temp instance cases. -- [ ] `test/session/messages-pagination.test.ts`: convert the local `run(...)` / `svc(...)` facade to `testEffect(Session.defaultLayer...)` and direct service yields. Good early target. -- [ ] `test/snapshot/snapshot.test.ts`: convert snapshot operations to `it.live` with `tmpdirScoped` / `provideInstance`. Keep git/filesystem behavior live. -- [ ] `test/project/vcs.test.ts`: convert `AppRuntime.runPromise` service calls first. Leave event/watcher timing intact until the first Effect version is stable. -- [ ] `test/provider/provider.test.ts` cluster 1: convert provider service tests that only read config/env and do not mutate global state heavily. -- [ ] `test/provider/provider.test.ts` cluster 2: convert tests with env/config mutation after introducing or reusing service-backed test seams. -- [ ] `test/tool/shell.test.ts`: replace custom `ManagedRuntime` with `testEffect`, keep as `it.live`, and preserve process behavior. -- [ ] `test/tool/edit.test.ts` cluster 1: convert straightforward edit/read/write cases and remove manual runtime helpers. -- [ ] `test/tool/edit.test.ts` cluster 2: convert concurrency/race tests using `Deferred`, fibers, and `Effect.all` without serializing behavior. -- [ ] `test/config/config.test.ts` setup pass: replace inline fake layers with shared `test/fake/*` layers where possible and turn Promise helpers into Effect helpers. -- [ ] `test/config/config.test.ts` cluster 1: convert simple config load/merge tests that only need one instance. -- [ ] `test/config/config.test.ts` cluster 2: convert managed/global config tests that mutate `Global.Path` or managed config directories. Prefer service seams; use finalizers only as a bridge. -- [ ] `test/config/config.test.ts` cluster 3: convert plugin/dependency tests after ensuring `NpmTest.noop` or explicit fake NPM layers are used. -- [ ] `test/config/config.test.ts` cluster 4: convert remote/account/provider config tests after isolating auth/account/env dependencies through layers. -- [ ] Audit remaining `Effect.runPromise` in `packages/opencode/test/**/*.ts` and create follow-up checklist entries for any missed files. -- [ ] Audit remaining `WithInstance.provide` in `packages/opencode/test/**/*.ts` and convert cases that can use `it.instance` or `provideInstance` inside Effect. -- [ ] Audit repeated `Exit` / `Cause` assertion shapes and propose `test/lib/effect-assert.ts` helpers if at least three files repeat the same pattern. - -Parallelization notes: - -- The first four items are mostly independent and good for separate worktrees. -- `provider.test.ts`, `tool/edit.test.ts`, and `config.test.ts` should be split by cluster so agents do not edit the same file concurrently. -- Any new fake boundary layer under `test/fake/*` should be small and independently useful. Do not add a fake just for one assertion unless it removes a real external dependency. -- Do not combine assertion-helper design with file migrations. First collect repeated shapes, then add helpers in a separate pass. - -Orchestration rules: - -- Prefer supervised foreground agents for implementation. Background agents are acceptable for research-only surveys, but code migrations need a returned diff, focused test output, and local commit before moving on. -- Create one worktree per claim and verify the branch/worktree path before edits. A status check should include `git status --short --branch` from the claimed worktree. -- After an agent reports completion, the coordinator must independently inspect `git status`, run the focused test, run `bun typecheck`, and review the diff before pushing. -- If an agent edits the wrong worktree, move the patch deliberately with `git diff` / `git apply`, then clean the accidental worktree before opening a PR. -- Keep dependency setup boring. Prefer reusing existing installed dependencies via worktrees or symlinks over running a fresh `bun install` in a temporary path unless the native build path is known to work. -- Do not delete worktrees with unpushed commits or uncommitted changes. Once a migration PR branch is pushed and clean, the local worktree can be removed while leaving the branch on the fork. - -## Effectified Test Rough Edges - -Track patterns that are technically Effect-native but still too noisy. These should become a second cleanup pass after the Promise-land migration is underway. - -- Failure assertions against `Exit` / `Cause` are often verbose. Consider helpers such as `expectEffectFailure(effect)`, `expectTaggedError(effect, Tag)`, or custom Bun matchers if the same shapes repeat. -- Some tests still need `Effect.promise(...)` around Node/Bun filesystem helpers. Prefer Effect platform services when the surrounding code already uses them, but do not block migrations on perfect filesystem abstraction. -- Scoped global mutation with `process.env`, `Global.Path`, or flags should disappear behind injectable services over time. -- Layer composition can be noisy when a test needs a real service subtree plus fake boundaries. Keep extracting small `test/fake/*` boundary layers before inventing larger builders. -- Concurrency tests can become harder to read after replacing Promise resolvers with `Deferred` and fibers. Look for repeated patterns that deserve named helpers. +- Failure assertions against `Exit` / `Cause` can get verbose. Add helpers + only after the same shape repeats across multiple files. +- Some tests still need `Effect.promise(...)` around Node/Bun APIs. Prefer + Effect platform services when the surrounding code already uses them, but + do not block useful migrations on perfect abstraction. +- Layer composition can be noisy when a test needs real service subtrees plus + fake boundaries. Extract small `test/fake/*` layers before inventing + larger builders. +- Concurrency tests can get harder to read after replacing Promise + resolvers. Look for repeated patterns that deserve named helpers. diff --git a/packages/opencode/test/acp/event-subscription.test.ts b/packages/opencode/test/acp/event-subscription.test.ts index 791b5c578f..2c9371d74d 100644 --- a/packages/opencode/test/acp/event-subscription.test.ts +++ b/packages/opencode/test/acp/event-subscription.test.ts @@ -8,8 +8,7 @@ import type { ToolStatePending, ToolStateRunning, } from "@opencode-ai/sdk/v2" -import { WithInstance } from "../../src/project/with-instance" -import { tmpdir } from "../fixture/fixture" +import { provideTestInstance, tmpdir } from "../fixture/fixture" type SessionUpdateParams = Parameters[0] type RequestPermissionParams = Parameters[0] @@ -317,7 +316,7 @@ function createFakeAgent() { describe("acp.agent event subscription", () => { test("routes message.part.delta by the event sessionID (no cross-session pollution)", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, controller, updates, stop } = createFakeAgent() @@ -352,7 +351,7 @@ describe("acp.agent event subscription", () => { test("does not emit user_message_chunk for live prompt parts", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, controller, sessionUpdates, stop } = createFakeAgent() @@ -392,7 +391,7 @@ describe("acp.agent event subscription", () => { test("keeps concurrent sessions isolated when message.part.delta events are interleaved", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, controller, chunks, stop } = createFakeAgent() @@ -444,7 +443,7 @@ describe("acp.agent event subscription", () => { test("does not create additional event subscriptions on repeated loadSession()", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, calls, stop } = createFakeAgent() @@ -466,7 +465,7 @@ describe("acp.agent event subscription", () => { test("permission.asked events are handled and replied", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const permissionReplies: string[] = [] @@ -505,7 +504,7 @@ describe("acp.agent event subscription", () => { test("permission prompt on session A does not block message updates for session B", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const permissionReplies: string[] = [] @@ -592,7 +591,7 @@ describe("acp.agent event subscription", () => { test("streams running bash output snapshots and de-dupes identical snapshots", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, controller, sessionUpdates, stop } = createFakeAgent() @@ -626,7 +625,7 @@ describe("acp.agent event subscription", () => { test("emits synthetic pending before first running update for any tool", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, controller, sessionUpdates, stop } = createFakeAgent() @@ -671,7 +670,7 @@ describe("acp.agent event subscription", () => { test("emits image attachments as ACP tool content blocks on live completed tool updates", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, controller, sessionUpdates, stop } = createFakeAgent() @@ -728,7 +727,7 @@ describe("acp.agent event subscription", () => { test("replays completed tool image attachments as ACP tool content blocks", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, sessionUpdates, stop, sdk } = createFakeAgent() @@ -795,7 +794,7 @@ describe("acp.agent event subscription", () => { test("does not emit duplicate synthetic pending after replayed running tool", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, controller, sessionUpdates, stop, sdk } = createFakeAgent() @@ -854,7 +853,7 @@ describe("acp.agent event subscription", () => { test("clears bash snapshot marker on pending state", async () => { await using tmp = await tmpdir() - await WithInstance.provide({ + await provideTestInstance({ directory: tmp.path, fn: async () => { const { agent, controller, sessionUpdates, stop } = createFakeAgent() diff --git a/packages/opencode/test/agent/agent.test.ts b/packages/opencode/test/agent/agent.test.ts index df68fdfdc6..e0defc1386 100644 --- a/packages/opencode/test/agent/agent.test.ts +++ b/packages/opencode/test/agent/agent.test.ts @@ -1,12 +1,31 @@ -import { afterEach, test, expect } from "bun:test" -import { Effect } from "effect" +import { afterEach, expect } from "bun:test" +import { Cause, Effect, Exit, Layer } from "effect" import path from "path" -import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture" -import { WithInstance } from "../../src/project/with-instance" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" import { Agent } from "../../src/agent/agent" +import { Auth } from "../../src/auth" +import { Config } from "../../src/config/config" +import { RuntimeFlags } from "../../src/effect/runtime-flags" import { Global } from "@opencode-ai/core/global" -import { Flag } from "@opencode-ai/core/flag/flag" import { Permission } from "../../src/permission" +import { Plugin } from "../../src/plugin" +import { Provider } from "../../src/provider/provider" +import { Skill } from "../../src/skill" +import { Truncate } from "../../src/tool/truncate" + +const agentLayer = (flags: Partial = {}) => + Agent.layer.pipe( + Layer.provide(Plugin.defaultLayer), + Layer.provide(Provider.defaultLayer), + Layer.provide(Auth.defaultLayer), + Layer.provide(Config.defaultLayer), + Layer.provide(Skill.defaultLayer), + Layer.provide(RuntimeFlags.layer(flags)), + ) + +const it = testEffect(agentLayer()) +const scout = testEffect(agentLayer({ experimentalScout: true })) // Helper to evaluate permission for a tool with wildcard pattern function evalPerm(agent: Agent.Info | undefined, permission: string): Permission.Action | undefined { @@ -14,196 +33,165 @@ function evalPerm(agent: Agent.Info | undefined, permission: string): Permission return Permission.evaluate(permission, "*", agent.permission).action } -function load(dir: string, fn: (svc: Agent.Interface) => Effect.Effect) { - return Effect.runPromise(provideInstance(dir)(Agent.Service.use(fn)).pipe(Effect.provide(Agent.defaultLayer))) +function load(fn: (svc: Agent.Interface) => Effect.Effect) { + return Agent.Service.use(fn) } -async function withExperimentalScout(enabled: boolean, fn: () => Promise) { - const original = Flag.OPENCODE_EXPERIMENTAL_SCOUT - Flag.OPENCODE_EXPERIMENTAL_SCOUT = enabled - try { - await fn() - } finally { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = original - } -} +const expectDefaultAgentError = Effect.fn("AgentTest.expectDefaultAgentError")(function* (message: string) { + const exit = yield* load((svc) => svc.defaultAgent()).pipe(Effect.exit) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) expect(Cause.pretty(exit.cause)).toContain(message) +}) afterEach(async () => { await disposeAllInstances() }) -test("returns default native agents when no config", async () => { - await withExperimentalScout(false, async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const agents = await load(tmp.path, (svc) => svc.list()) - const names = agents.map((a) => a.name) - expect(names).toContain("build") - expect(names).toContain("plan") - expect(names).toContain("general") - expect(names).toContain("explore") - expect(names).not.toContain("scout") - expect(names).toContain("compaction") - expect(names).toContain("title") - expect(names).toContain("summary") - }, - }) - }) -}) +it.instance("returns default native agents when no config", () => + Effect.gen(function* () { + const agents = yield* load((svc) => svc.list()) + const names = agents.map((a) => a.name) + expect(names).toContain("build") + expect(names).toContain("plan") + expect(names).toContain("general") + expect(names).toContain("explore") + expect(names).not.toContain("scout") + expect(names).toContain("compaction") + expect(names).toContain("title") + expect(names).toContain("summary") + }), +) -test("build agent has correct default properties", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(build).toBeDefined() - expect(build?.mode).toBe("primary") - expect(build?.native).toBe(true) - expect(evalPerm(build, "edit")).toBe("allow") - expect(evalPerm(build, "bash")).toBe("allow") - expect(evalPerm(build, "repo_clone")).toBe("deny") - expect(evalPerm(build, "repo_overview")).toBe("deny") - }, - }) -}) +it.instance("build agent has correct default properties", () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(build).toBeDefined() + expect(build?.mode).toBe("primary") + expect(build?.native).toBe(true) + expect(evalPerm(build, "edit")).toBe("allow") + expect(evalPerm(build, "bash")).toBe("allow") + expect(evalPerm(build, "repo_clone")).toBe("deny") + expect(evalPerm(build, "repo_overview")).toBe("deny") + }), +) -test("plan agent denies edits except .opencode/plans/*", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const plan = await load(tmp.path, (svc) => svc.get("plan")) - expect(plan).toBeDefined() - // Wildcard is denied - expect(evalPerm(plan, "edit")).toBe("deny") - // But specific path is allowed - expect(Permission.evaluate("edit", ".opencode/plans/foo.md", plan!.permission).action).toBe("allow") - }, - }) -}) +it.instance("plan agent denies edits except .opencode/plans/*", () => + Effect.gen(function* () { + const plan = yield* load((svc) => svc.get("plan")) + expect(plan).toBeDefined() + // Wildcard is denied + expect(evalPerm(plan, "edit")).toBe("deny") + // But specific path is allowed + expect(Permission.evaluate("edit", ".opencode/plans/foo.md", plan!.permission).action).toBe("allow") + }), +) -test("explore agent denies edit and write", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const explore = await load(tmp.path, (svc) => svc.get("explore")) - expect(explore).toBeDefined() - expect(explore?.mode).toBe("subagent") - expect(evalPerm(explore, "edit")).toBe("deny") - expect(evalPerm(explore, "write")).toBe("deny") - expect(evalPerm(explore, "todowrite")).toBe("deny") - }, - }) -}) +it.instance("explore agent denies edit and write", () => + Effect.gen(function* () { + const explore = yield* load((svc) => svc.get("explore")) + expect(explore).toBeDefined() + expect(explore?.mode).toBe("subagent") + expect(evalPerm(explore, "edit")).toBe("deny") + expect(evalPerm(explore, "write")).toBe("deny") + expect(evalPerm(explore, "todowrite")).toBe("deny") + }), +) -test("explore agent asks for external directories and allows whitelisted external paths", async () => { - const { Truncate } = await import("../../src/tool/truncate") - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const explore = await load(tmp.path, (svc) => svc.get("explore")) - expect(explore).toBeDefined() - expect(Permission.evaluate("external_directory", "/some/other/path", explore!.permission).action).toBe("ask") - expect(Permission.evaluate("external_directory", Truncate.GLOB, explore!.permission).action).toBe("allow") - expect( - Permission.evaluate("external_directory", path.join(Global.Path.tmp, "agent-work"), explore!.permission).action, - ).toBe("allow") - }, - }) -}) +it.instance("explore agent asks for external directories and allows whitelisted external paths", () => + Effect.gen(function* () { + const explore = yield* load((svc) => svc.get("explore")) + expect(explore).toBeDefined() + expect(Permission.evaluate("external_directory", "/some/other/path", explore!.permission).action).toBe("ask") + expect(Permission.evaluate("external_directory", Truncate.GLOB, explore!.permission).action).toBe("allow") + expect( + Permission.evaluate("external_directory", path.join(Global.Path.tmp, "agent-work"), explore!.permission).action, + ).toBe("allow") + }), +) -test("scout agent allows repo cloning and repo cache reads", async () => { - await withExperimentalScout(true, async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const scout = await load(tmp.path, (svc) => svc.get("scout")) - expect(scout).toBeDefined() - expect(scout?.mode).toBe("subagent") - expect(evalPerm(scout, "repo_clone")).toBe("allow") - expect(evalPerm(scout, "repo_overview")).toBe("allow") - expect(evalPerm(scout, "edit")).toBe("deny") - expect( - Permission.evaluate( - "external_directory", - path.join(Global.Path.repos, "github.com", "owner", "repo", "README.md"), - scout!.permission, - ).action, - ).toBe("allow") - }, - }) - }) -}) +scout.instance("scout agent allows repo cloning and repo cache reads", () => + Effect.gen(function* () { + const scout = yield* load((svc) => svc.get("scout")) + expect(scout).toBeDefined() + expect(scout?.mode).toBe("subagent") + expect(evalPerm(scout, "repo_clone")).toBe("allow") + expect(evalPerm(scout, "repo_overview")).toBe("allow") + expect(evalPerm(scout, "edit")).toBe("deny") + expect( + Permission.evaluate( + "external_directory", + path.join(Global.Path.repos, "github.com", "owner", "repo", "README.md"), + scout!.permission, + ).action, + ).toBe("allow") + }), +) -test("reference config does not create subagents", async () => { - await withExperimentalScout(true, async () => { - await using tmp = await tmpdir({ - config: { - reference: { - effect: "github.com/effect/effect-smol", - effectFull: { - repository: "Effect-TS/effect", - branch: "main", - }, - localdocs: "../docs", - localdocsFull: { - path: "../local-docs", - }, +scout.instance( + "reference config does not create subagents", + () => + Effect.gen(function* () { + const agents = yield* load((svc) => svc.list()) + const names = agents.map((agent) => agent.name) + expect(names).toContain("scout") + expect(names).not.toContain("effect") + expect(names).not.toContain("effectFull") + expect(names).not.toContain("localdocs") + expect(names).not.toContain("localdocsFull") + }), + { + config: { + reference: { + effect: "github.com/effect/effect-smol", + effectFull: { + repository: "Effect-TS/effect", + branch: "main", + }, + localdocs: "../docs", + localdocsFull: { + path: "../local-docs", }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const agents = await load(tmp.path, (svc) => svc.list()) - const names = agents.map((agent) => agent.name) - expect(names).toContain("scout") - expect(names).not.toContain("effect") - expect(names).not.toContain("effectFull") - expect(names).not.toContain("localdocs") - expect(names).not.toContain("localdocsFull") - }, - }) - }) -}) - -test("general agent denies todo tools", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const general = await load(tmp.path, (svc) => svc.get("general")) - expect(general).toBeDefined() - expect(general?.mode).toBe("subagent") - expect(general?.hidden).toBeUndefined() - expect(evalPerm(general, "todowrite")).toBe("deny") }, - }) -}) + }, +) -test("compaction agent denies all permissions", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const compaction = await load(tmp.path, (svc) => svc.get("compaction")) - expect(compaction).toBeDefined() - expect(compaction?.hidden).toBe(true) - expect(evalPerm(compaction, "bash")).toBe("deny") - expect(evalPerm(compaction, "edit")).toBe("deny") - expect(evalPerm(compaction, "read")).toBe("deny") - }, - }) -}) +it.instance("general agent denies todo tools", () => + Effect.gen(function* () { + const general = yield* load((svc) => svc.get("general")) + expect(general).toBeDefined() + expect(general?.mode).toBe("subagent") + expect(general?.hidden).toBeUndefined() + expect(evalPerm(general, "todowrite")).toBe("deny") + }), +) -test("custom agent from config creates new agent", async () => { - await using tmp = await tmpdir({ +it.instance("compaction agent denies all permissions", () => + Effect.gen(function* () { + const compaction = yield* load((svc) => svc.get("compaction")) + expect(compaction).toBeDefined() + expect(compaction?.hidden).toBe(true) + expect(evalPerm(compaction, "bash")).toBe("deny") + expect(evalPerm(compaction, "edit")).toBe("deny") + expect(evalPerm(compaction, "read")).toBe("deny") + }), +) + +it.instance( + "custom agent from config creates new agent", + () => + Effect.gen(function* () { + const custom = yield* load((svc) => svc.get("my_custom_agent")) + expect(custom).toBeDefined() + expect(String(custom?.model?.providerID)).toBe("openai") + expect(String(custom?.model?.modelID)).toBe("gpt-4") + expect(custom?.description).toBe("My custom agent") + expect(custom?.temperature).toBe(0.5) + expect(custom?.topP).toBe(0.9) + expect(custom?.native).toBe(false) + expect(custom?.mode).toBe("all") + }), + { config: { agent: { my_custom_agent: { @@ -214,25 +202,23 @@ test("custom agent from config creates new agent", async () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const custom = await load(tmp.path, (svc) => svc.get("my_custom_agent")) - expect(custom).toBeDefined() - expect(String(custom?.model?.providerID)).toBe("openai") - expect(String(custom?.model?.modelID)).toBe("gpt-4") - expect(custom?.description).toBe("My custom agent") - expect(custom?.temperature).toBe(0.5) - expect(custom?.topP).toBe(0.9) - expect(custom?.native).toBe(false) - expect(custom?.mode).toBe("all") - }, - }) -}) + }, +) -test("custom agent config overrides native agent properties", async () => { - await using tmp = await tmpdir({ +it.instance( + "custom agent config overrides native agent properties", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(build).toBeDefined() + expect(String(build?.model?.providerID)).toBe("anthropic") + expect(String(build?.model?.modelID)).toBe("claude-3") + expect(build?.description).toBe("Custom build agent") + expect(build?.temperature).toBe(0.7) + expect(build?.color).toBe("#FF0000") + expect(build?.native).toBe(true) + }), + { config: { agent: { build: { @@ -243,44 +229,40 @@ test("custom agent config overrides native agent properties", async () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(build).toBeDefined() - expect(String(build?.model?.providerID)).toBe("anthropic") - expect(String(build?.model?.modelID)).toBe("claude-3") - expect(build?.description).toBe("Custom build agent") - expect(build?.temperature).toBe(0.7) - expect(build?.color).toBe("#FF0000") - expect(build?.native).toBe(true) - }, - }) -}) + }, +) -test("agent disable removes agent from list", async () => { - await using tmp = await tmpdir({ +it.instance( + "agent disable removes agent from list", + () => + Effect.gen(function* () { + const explore = yield* load((svc) => svc.get("explore")) + expect(explore).toBeUndefined() + const agents = yield* load((svc) => svc.list()) + const names = agents.map((a) => a.name) + expect(names).not.toContain("explore") + }), + { config: { agent: { explore: { disable: true }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const explore = await load(tmp.path, (svc) => svc.get("explore")) - expect(explore).toBeUndefined() - const agents = await load(tmp.path, (svc) => svc.list()) - const names = agents.map((a) => a.name) - expect(names).not.toContain("explore") - }, - }) -}) + }, +) -test("agent permission config merges with defaults", async () => { - await using tmp = await tmpdir({ +it.instance( + "agent permission config merges with defaults", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(build).toBeDefined() + // Specific pattern is denied + expect(Permission.evaluate("bash", "rm -rf *", build!.permission).action).toBe("deny") + // Edit still allowed + expect(evalPerm(build, "edit")).toBe("allow") + }), + { config: { agent: { build: { @@ -292,111 +274,102 @@ test("agent permission config merges with defaults", async () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(build).toBeDefined() - // Specific pattern is denied - expect(Permission.evaluate("bash", "rm -rf *", build!.permission).action).toBe("deny") - // Edit still allowed - expect(evalPerm(build, "edit")).toBe("allow") - }, - }) -}) + }, +) -test("global permission config applies to all agents", async () => { - await using tmp = await tmpdir({ +it.instance( + "global permission config applies to all agents", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(build).toBeDefined() + expect(evalPerm(build, "bash")).toBe("deny") + }), + { config: { permission: { bash: "deny", }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(build).toBeDefined() - expect(evalPerm(build, "bash")).toBe("deny") - }, - }) -}) + }, +) -test("agent steps/maxSteps config sets steps property", async () => { - await using tmp = await tmpdir({ +it.instance( + "agent steps/maxSteps config sets steps property", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + const plan = yield* load((svc) => svc.get("plan")) + expect(build?.steps).toBe(50) + expect(plan?.steps).toBe(100) + }), + { config: { agent: { build: { steps: 50 }, plan: { maxSteps: 100 }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - const plan = await load(tmp.path, (svc) => svc.get("plan")) - expect(build?.steps).toBe(50) - expect(plan?.steps).toBe(100) - }, - }) -}) + }, +) -test("agent mode can be overridden", async () => { - await using tmp = await tmpdir({ +it.instance( + "agent mode can be overridden", + () => + Effect.gen(function* () { + const explore = yield* load((svc) => svc.get("explore")) + expect(explore?.mode).toBe("primary") + }), + { config: { agent: { explore: { mode: "primary" }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const explore = await load(tmp.path, (svc) => svc.get("explore")) - expect(explore?.mode).toBe("primary") - }, - }) -}) + }, +) -test("agent name can be overridden", async () => { - await using tmp = await tmpdir({ +it.instance( + "agent name can be overridden", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(build?.name).toBe("Builder") + }), + { config: { agent: { build: { name: "Builder" }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(build?.name).toBe("Builder") - }, - }) -}) + }, +) -test("agent prompt can be set from config", async () => { - await using tmp = await tmpdir({ +it.instance( + "agent prompt can be set from config", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(build?.prompt).toBe("Custom system prompt") + }), + { config: { agent: { build: { prompt: "Custom system prompt" }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(build?.prompt).toBe("Custom system prompt") - }, - }) -}) + }, +) -test("unknown agent properties are placed into options", async () => { - await using tmp = await tmpdir({ +it.instance( + "unknown agent properties are placed into options", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(build?.options.random_property).toBe("hello") + expect(build?.options.another_random).toBe(123) + }), + { config: { agent: { build: { @@ -405,19 +378,18 @@ test("unknown agent properties are placed into options", async () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(build?.options.random_property).toBe("hello") - expect(build?.options.another_random).toBe(123) - }, - }) -}) + }, +) -test("agent options merge correctly", async () => { - await using tmp = await tmpdir({ +it.instance( + "agent options merge correctly", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(build?.options.custom_option).toBe(true) + expect(build?.options.another_option).toBe("value") + }), + { config: { agent: { build: { @@ -428,19 +400,21 @@ test("agent options merge correctly", async () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(build?.options.custom_option).toBe(true) - expect(build?.options.another_option).toBe("value") - }, - }) -}) + }, +) -test("multiple custom agents can be defined", async () => { - await using tmp = await tmpdir({ +it.instance( + "multiple custom agents can be defined", + () => + Effect.gen(function* () { + const agentA = yield* load((svc) => svc.get("agent_a")) + const agentB = yield* load((svc) => svc.get("agent_b")) + expect(agentA?.description).toBe("Agent A") + expect(agentA?.mode).toBe("subagent") + expect(agentB?.description).toBe("Agent B") + expect(agentB?.mode).toBe("primary") + }), + { config: { agent: { agent_a: { @@ -453,22 +427,18 @@ test("multiple custom agents can be defined", async () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const agentA = await load(tmp.path, (svc) => svc.get("agent_a")) - const agentB = await load(tmp.path, (svc) => svc.get("agent_b")) - expect(agentA?.description).toBe("Agent A") - expect(agentA?.mode).toBe("subagent") - expect(agentB?.description).toBe("Agent B") - expect(agentB?.mode).toBe("primary") - }, - }) -}) + }, +) -test("Agent.list keeps the default agent first and sorts the rest by name", async () => { - await using tmp = await tmpdir({ +it.instance( + "Agent.list keeps the default agent first and sorts the rest by name", + () => + Effect.gen(function* () { + const names = (yield* load((svc) => svc.list())).map((a) => a.name) + expect(names[0]).toBe("plan") + expect(names.slice(1)).toEqual(names.slice(1).toSorted((a, b) => a.localeCompare(b))) + }), + { config: { default_agent: "plan", agent: { @@ -482,53 +452,40 @@ test("Agent.list keeps the default agent first and sorts the rest by name", asyn }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const names = (await load(tmp.path, (svc) => svc.list())).map((a) => a.name) - expect(names[0]).toBe("plan") - expect(names.slice(1)).toEqual(names.slice(1).toSorted((a, b) => a.localeCompare(b))) - }, - }) -}) + }, +) -test("Agent.get returns undefined for non-existent agent", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const nonExistent = await load(tmp.path, (svc) => svc.get("does_not_exist")) - expect(nonExistent).toBeUndefined() - }, - }) -}) +it.instance("Agent.get returns undefined for non-existent agent", () => + Effect.gen(function* () { + const nonExistent = yield* load((svc) => svc.get("does_not_exist")) + expect(nonExistent).toBeUndefined() + }), +) -test("default permission includes doom_loop and external_directory as ask", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(evalPerm(build, "doom_loop")).toBe("ask") - expect(evalPerm(build, "external_directory")).toBe("ask") - }, - }) -}) +it.instance("default permission includes doom_loop and external_directory as ask", () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(evalPerm(build, "doom_loop")).toBe("ask") + expect(evalPerm(build, "external_directory")).toBe("ask") + }), +) -test("webfetch is allowed by default", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(evalPerm(build, "webfetch")).toBe("allow") - }, - }) -}) +it.instance("webfetch is allowed by default", () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(evalPerm(build, "webfetch")).toBe("allow") + }), +) -test("legacy tools config converts to permissions", async () => { - await using tmp = await tmpdir({ +it.instance( + "legacy tools config converts to permissions", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(evalPerm(build, "bash")).toBe("deny") + expect(evalPerm(build, "read")).toBe("deny") + }), + { config: { agent: { build: { @@ -539,19 +496,17 @@ test("legacy tools config converts to permissions", async () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(evalPerm(build, "bash")).toBe("deny") - expect(evalPerm(build, "read")).toBe("deny") - }, - }) -}) + }, +) -test("legacy tools config maps write/edit/patch to edit permission", async () => { - await using tmp = await tmpdir({ +it.instance( + "legacy tools config maps write/edit/patch to edit permission", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(evalPerm(build, "edit")).toBe("deny") + }), + { config: { agent: { build: { @@ -561,53 +516,47 @@ test("legacy tools config maps write/edit/patch to edit permission", async () => }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(evalPerm(build, "edit")).toBe("deny") - }, - }) -}) + }, +) -test("Truncate.GLOB is allowed even when user denies external_directory globally", async () => { - const { Truncate } = await import("../../src/tool/truncate") - await using tmp = await tmpdir({ +it.instance( + "Truncate.GLOB is allowed even when user denies external_directory globally", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(Permission.evaluate("external_directory", Truncate.GLOB, build!.permission).action).toBe("allow") + expect(Permission.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny") + expect(Permission.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("deny") + }), + { config: { permission: { external_directory: "deny", }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) + }, +) + +it.instance("global tmp directory children are allowed for external_directory", () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect( + Permission.evaluate("external_directory", path.join(Global.Path.tmp, "scratch"), build!.permission).action, + ).toBe("allow") + expect(Permission.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("ask") + }), +) + +it.instance( + "Truncate.GLOB is allowed even when user denies external_directory per-agent", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) expect(Permission.evaluate("external_directory", Truncate.GLOB, build!.permission).action).toBe("allow") expect(Permission.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny") expect(Permission.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("deny") - }, - }) -}) - -test("global tmp directory children are allowed for external_directory", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect( - Permission.evaluate("external_directory", path.join(Global.Path.tmp, "scratch"), build!.permission).action, - ).toBe("allow") - expect(Permission.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("ask") - }, - }) -}) - -test("Truncate.GLOB is allowed even when user denies external_directory per-agent", async () => { - const { Truncate } = await import("../../src/tool/truncate") - await using tmp = await tmpdir({ + }), + { config: { agent: { build: { @@ -617,21 +566,18 @@ test("Truncate.GLOB is allowed even when user denies external_directory per-agen }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(Permission.evaluate("external_directory", Truncate.GLOB, build!.permission).action).toBe("allow") - expect(Permission.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny") - expect(Permission.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("deny") - }, - }) -}) + }, +) -test("explicit Truncate.GLOB deny is respected", async () => { - const { Truncate } = await import("../../src/tool/truncate") - await using tmp = await tmpdir({ +it.instance( + "explicit Truncate.GLOB deny is respected", + () => + Effect.gen(function* () { + const build = yield* load((svc) => svc.get("build")) + expect(Permission.evaluate("external_directory", Truncate.GLOB, build!.permission).action).toBe("deny") + expect(Permission.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny") + }), + { config: { permission: { external_directory: { @@ -640,81 +586,80 @@ test("explicit Truncate.GLOB deny is respected", async () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - expect(Permission.evaluate("external_directory", Truncate.GLOB, build!.permission).action).toBe("deny") - expect(Permission.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny") - }, - }) -}) + }, +) -test("skill directories are allowed for external_directory", async () => { - await using tmp = await tmpdir({ - git: true, - init: async (dir) => { - const skillDir = path.join(dir, ".opencode", "skill", "perm-skill") - await Bun.write( - path.join(skillDir, "SKILL.md"), - `--- +it.instance( + "skill directories are allowed for external_directory", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const skillDir = path.join(test.directory, ".opencode", "skill", "perm-skill") + yield* Effect.promise(() => + Bun.write( + path.join(skillDir, "SKILL.md"), + `--- name: perm-skill description: Permission skill. --- # Permission Skill `, + ), ) - }, - }) - const home = process.env.OPENCODE_TEST_HOME - process.env.OPENCODE_TEST_HOME = tmp.path + const home = process.env.OPENCODE_TEST_HOME + process.env.OPENCODE_TEST_HOME = test.directory + yield* Effect.addFinalizer(() => + Effect.sync(() => { + process.env.OPENCODE_TEST_HOME = home + }), + ) - try { - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const build = await load(tmp.path, (svc) => svc.get("build")) - const skillDir = path.join(tmp.path, ".opencode", "skill", "perm-skill") - const target = path.join(skillDir, "reference", "notes.md") - expect(Permission.evaluate("external_directory", target, build!.permission).action).toBe("allow") - }, - }) - } finally { - process.env.OPENCODE_TEST_HOME = home - } -}) + const build = yield* load((svc) => svc.get("build")) + const target = path.join(skillDir, "reference", "notes.md") + expect(Permission.evaluate("external_directory", target, build!.permission).action).toBe("allow") + }), + { git: true }, +) -test("defaultAgent returns build when no default_agent config", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const agent = await load(tmp.path, (svc) => svc.defaultAgent()) - expect(agent).toBe("build") - }, - }) -}) +it.instance("defaultAgent returns build when no default_agent config", () => + Effect.gen(function* () { + const agent = yield* load((svc) => svc.defaultAgent()) + expect(agent).toBe("build") + }), +) -test("defaultAgent respects default_agent config set to plan", async () => { - await using tmp = await tmpdir({ +it.instance("defaultInfo returns resolved build agent when no default_agent config", () => + Effect.gen(function* () { + const agent = yield* load((svc) => svc.defaultInfo()) + expect(agent.name).toBe("build") + expect(agent.mode).toBe("primary") + }), +) + +it.instance( + "defaultAgent respects default_agent config set to plan", + () => + Effect.gen(function* () { + const agent = yield* load((svc) => svc.defaultAgent()) + expect(agent).toBe("plan") + }), + { config: { default_agent: "plan", }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const agent = await load(tmp.path, (svc) => svc.defaultAgent()) - expect(agent).toBe("plan") - }, - }) -}) + }, +) -test("defaultAgent respects default_agent config set to custom agent with mode all", async () => { - await using tmp = await tmpdir({ +it.instance( + "defaultAgent respects default_agent config set to custom agent with mode all", + () => + Effect.gen(function* () { + const agent = yield* load((svc) => svc.defaultAgent()) + expect(agent).toBe("my_custom") + }), + { config: { default_agent: "my_custom", agent: { @@ -723,92 +668,65 @@ test("defaultAgent respects default_agent config set to custom agent with mode a }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const agent = await load(tmp.path, (svc) => svc.defaultAgent()) - expect(agent).toBe("my_custom") - }, - }) -}) + }, +) -test("defaultAgent throws when default_agent points to subagent", async () => { - await using tmp = await tmpdir({ +it.instance( + "defaultAgent throws when default_agent points to subagent", + () => expectDefaultAgentError('default agent "explore" is a subagent'), + { config: { default_agent: "explore", }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await expect(load(tmp.path, (svc) => svc.defaultAgent())).rejects.toThrow('default agent "explore" is a subagent') - }, - }) -}) + }, +) -test("defaultAgent throws when default_agent points to hidden agent", async () => { - await using tmp = await tmpdir({ +it.instance( + "defaultAgent throws when default_agent points to hidden agent", + () => expectDefaultAgentError('default agent "compaction" is hidden'), + { config: { default_agent: "compaction", }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await expect(load(tmp.path, (svc) => svc.defaultAgent())).rejects.toThrow('default agent "compaction" is hidden') - }, - }) -}) + }, +) -test("defaultAgent throws when default_agent points to non-existent agent", async () => { - await using tmp = await tmpdir({ +it.instance( + "defaultAgent throws when default_agent points to non-existent agent", + () => expectDefaultAgentError('default agent "does_not_exist" not found'), + { config: { default_agent: "does_not_exist", }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await expect(load(tmp.path, (svc) => svc.defaultAgent())).rejects.toThrow( - 'default agent "does_not_exist" not found', - ) - }, - }) -}) + }, +) -test("defaultAgent returns plan when build is disabled and default_agent not set", async () => { - await using tmp = await tmpdir({ +it.instance( + "defaultAgent returns plan when build is disabled and default_agent not set", + () => + Effect.gen(function* () { + const agent = yield* load((svc) => svc.defaultAgent()) + // build is disabled, so it should return plan (next primary agent) + expect(agent).toBe("plan") + }), + { config: { agent: { build: { disable: true }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const agent = await load(tmp.path, (svc) => svc.defaultAgent()) - // build is disabled, so it should return plan (next primary agent) - expect(agent).toBe("plan") - }, - }) -}) + }, +) -test("defaultAgent throws when all primary agents are disabled", async () => { - await using tmp = await tmpdir({ +it.instance( + "defaultAgent throws when all primary agents are disabled", + () => expectDefaultAgentError("no primary visible agent found"), + { config: { agent: { build: { disable: true }, plan: { disable: true }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - // build and plan are disabled, no primary-capable agents remain - await expect(load(tmp.path, (svc) => svc.defaultAgent())).rejects.toThrow("no primary visible agent found") - }, - }) -}) + }, +) diff --git a/packages/opencode/test/agent/plan-mode-subagent-bypass.test.ts b/packages/opencode/test/agent/plan-mode-subagent-bypass.test.ts index 5ba6b54834..641a929aeb 100644 --- a/packages/opencode/test/agent/plan-mode-subagent-bypass.test.ts +++ b/packages/opencode/test/agent/plan-mode-subagent-bypass.test.ts @@ -18,110 +18,98 @@ * permissions are passed through, and Plan Mode's restrictions live on the * agent, not the session. */ -import { test, expect, afterEach } from "bun:test" +import { expect } from "bun:test" import { Effect } from "effect" -import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture" -import { WithInstance } from "../../src/project/with-instance" import { Agent } from "../../src/agent/agent" import { deriveSubagentSessionPermission } from "../../src/agent/subagent-permissions" import { Permission } from "../../src/permission" +import { testEffect } from "../lib/effect" -afterEach(async () => { - await disposeAllInstances() -}) +const it = testEffect(Agent.defaultLayer) -function load(dir: string, fn: (svc: Agent.Interface) => Effect.Effect) { - return Effect.runPromise(provideInstance(dir)(Agent.Service.use(fn)).pipe(Effect.provide(Agent.defaultLayer))) +function testAgent(input: { + name: string + mode: Agent.Info["mode"] + permission: Parameters[0] +}) { + return { + name: input.name, + mode: input.mode, + permission: Permission.fromConfig(input.permission), + options: {}, + } satisfies Agent.Info } // `deriveSubagentSessionPermission` is imported from production. The test // exercises the actual helper that task.ts uses to build the subagent's // session permission, so any regression in that helper trips this test. -test("[#26514] subagent spawned from plan mode inherits read-only restriction (edit denied)", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const planAgent = await load(tmp.path, (svc) => svc.get("plan")) - const generalAgent = await load(tmp.path, (svc) => svc.get("general")) +it.instance("[#26514] subagent spawned from plan mode inherits read-only restriction (edit denied)", () => + Effect.gen(function* () { + const planAgent = yield* Agent.Service.use((svc) => svc.get("plan")) + const generalAgent = yield* Agent.Service.use((svc) => svc.get("general")) - expect(planAgent).toBeDefined() - expect(generalAgent).toBeDefined() - // Sanity: the plan agent itself blocks edit. (Note: `write` and - // `apply_patch` route through the `edit` permission at the runtime - // tool layer — see Permission.disabled / EDIT_TOOLS.) - expect(Permission.evaluate("edit", "/some/file.ts", planAgent!.permission).action).toBe("deny") + expect(planAgent).toBeDefined() + expect(generalAgent).toBeDefined() + // Sanity: the plan agent itself blocks edit. (Note: `write` and + // `apply_patch` route through the `edit` permission at the runtime + // tool layer — see Permission.disabled / EDIT_TOOLS.) + expect(Permission.evaluate("edit", "/some/file.ts", planAgent!.permission).action).toBe("deny") - // Simulate the plan-mode parent session: in real flow the plan - // session's `permission` field is empty (Plan Mode lives on the agent - // ruleset, not the session). So we pass [] through as the parent - // session permission, exactly like the actual code path. - const parentSessionPermission: Permission.Ruleset = [] + // Simulate the plan-mode parent session: in real flow the plan + // session's `permission` field is empty (Plan Mode lives on the agent + // ruleset, not the session). So we pass [] through as the parent + // session permission, exactly like the actual code path. + const parentSessionPermission: Permission.Ruleset = [] - const subagentSessionPermission = deriveSubagentSessionPermission({ - parentSessionPermission, - parentAgent: planAgent, - subagent: generalAgent!, - }) + const subagentSessionPermission = deriveSubagentSessionPermission({ + parentSessionPermission, + parentAgent: planAgent, + subagent: generalAgent!, + }) - // Mirror the runtime evaluation in session/prompt.ts (~line 410, 639): - // ruleset: Permission.merge(agent.permission, session.permission ?? []) - const effective = Permission.merge(generalAgent!.permission, subagentSessionPermission) + // Mirror the runtime evaluation in session/prompt.ts (~line 410, 639): + // ruleset: Permission.merge(agent.permission, session.permission ?? []) + const effective = Permission.merge(generalAgent!.permission, subagentSessionPermission) - expect(Permission.evaluate("edit", "/some/file.ts", effective).action).toBe("deny") - expect(Permission.evaluate("edit", "/another/path/index.tsx", effective).action).toBe("deny") - }, - }) -}) + expect(Permission.evaluate("edit", "/some/file.ts", effective).action).toBe("deny") + expect(Permission.evaluate("edit", "/another/path/index.tsx", effective).action).toBe("deny") + }), +) -test("[#26514] explore subagent launched from plan mode also stays read-only", async () => { +it.instance("[#26514] explore subagent launched from plan mode also stays read-only", () => // Sibling check: even though `explore` is intrinsically read-only, the // bug surface is the same. Including this case to document that the fix // should propagate the parent **agent** permissions, not just deny edit // when the subagent happens to already deny it. - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const planAgent = await load(tmp.path, (svc) => svc.get("plan")) - const explore = await load(tmp.path, (svc) => svc.get("explore")) - expect(planAgent).toBeDefined() - expect(explore).toBeDefined() + Effect.gen(function* () { + const planAgent = yield* Agent.Service.use((svc) => svc.get("plan")) + const explore = yield* Agent.Service.use((svc) => svc.get("explore")) + expect(planAgent).toBeDefined() + expect(explore).toBeDefined() - const parentSessionPermission: Permission.Ruleset = [] - const subagentSessionPermission = deriveSubagentSessionPermission({ - parentSessionPermission, - parentAgent: planAgent, - subagent: explore!, - }) - const effective = Permission.merge(explore!.permission, subagentSessionPermission) + const parentSessionPermission: Permission.Ruleset = [] + const subagentSessionPermission = deriveSubagentSessionPermission({ + parentSessionPermission, + parentAgent: planAgent, + subagent: explore!, + }) + const effective = Permission.merge(explore!.permission, subagentSessionPermission) - // Already deny — sanity check. - expect(Permission.evaluate("edit", "/x.ts", effective).action).toBe("deny") - }, - }) -}) + // Already deny — sanity check. + expect(Permission.evaluate("edit", "/x.ts", effective).action).toBe("deny") + }), +) -test("[#26514] custom user subagent launched from plan mode bypasses Plan Mode read-only", async () => { +it.instance( + "[#26514] custom user subagent launched from plan mode bypasses Plan Mode read-only", // The most damaging case: a user-defined subagent with default // permissions (allow-by-default, like `general`). The subagent must NOT // be able to edit when the parent agent is `plan`. - await using tmp = await tmpdir({ - config: { - agent: { - my_subagent: { - description: "A user-defined subagent", - mode: "subagent", - }, - }, - }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const planAgent = await load(tmp.path, (svc) => svc.get("plan")) - const my = await load(tmp.path, (svc) => svc.get("my_subagent")) + () => + Effect.gen(function* () { + const planAgent = yield* Agent.Service.use((svc) => svc.get("plan")) + const my = yield* Agent.Service.use((svc) => svc.get("my_subagent")) expect(planAgent).toBeDefined() expect(my).toBeDefined() @@ -136,6 +124,89 @@ test("[#26514] custom user subagent launched from plan mode bypasses Plan Mode r // BUG: on origin/dev edit resolves to "allow" because the plan // agent's `edit: deny *` rule never reaches the subagent. expect(Permission.evaluate("edit", "/some/file.ts", effective).action).toBe("deny") + }), + { + config: { + agent: { + my_subagent: { + description: "A user-defined subagent", + mode: "subagent", + }, + }, }, - }) -}) + }, +) + +it.effect("[#26700] controller self-restrictions do not erase executor permissions", () => + Effect.sync(() => { + const controller = testAgent({ + name: "controller", + mode: "primary", + permission: { + "*": "deny", + read: "deny", + bash: "deny", + task: { + "*": "deny", + executor: "allow", + }, + edit: "deny", + write: "deny", + }, + }) + const executor = testAgent({ + name: "executor", + mode: "subagent", + permission: { + "*": "deny", + read: "allow", + bash: "allow", + task: { + "*": "deny", + worker: "allow", + }, + edit: "deny", + write: "deny", + }, + }) + + const effective = Permission.merge( + executor.permission, + deriveSubagentSessionPermission({ + parentSessionPermission: [], + parentAgent: controller, + subagent: executor, + }), + ) + + expect(Permission.evaluate("read", "README.md", effective).action).toBe("allow") + expect(Permission.evaluate("bash", "git status", effective).action).toBe("allow") + expect(Permission.evaluate("task", "worker", effective).action).toBe("allow") + expect(Permission.evaluate("task", "other", effective).action).toBe("deny") + expect(Permission.disabled(["edit", "write", "apply_patch"], effective)).toEqual( + new Set(["edit", "write", "apply_patch"]), + ) + }), +) + +it.effect("subagent inherits parent session deny rules as hard runtime ceilings", () => + Effect.sync(() => { + const executor = testAgent({ + name: "executor", + mode: "subagent", + permission: { + bash: "allow", + }, + }) + const effective = Permission.merge( + executor.permission, + deriveSubagentSessionPermission({ + parentSessionPermission: Permission.fromConfig({ bash: "deny" }), + parentAgent: undefined, + subagent: executor, + }), + ) + + expect(Permission.evaluate("bash", "git status", effective).action).toBe("deny") + }), +) diff --git a/packages/opencode/test/agent/plugin-agent-regression.test.ts b/packages/opencode/test/agent/plugin-agent-regression.test.ts index e2dd8a5f7c..c437281cc6 100644 --- a/packages/opencode/test/agent/plugin-agent-regression.test.ts +++ b/packages/opencode/test/agent/plugin-agent-regression.test.ts @@ -7,6 +7,7 @@ import { Agent } from "../../src/agent/agent" import { Bus } from "../../src/bus" import { Config } from "../../src/config/config" import { Env } from "../../src/env" +import { RuntimeFlags } from "../../src/effect/runtime-flags" import { Plugin } from "../../src/plugin" import { AccountTest } from "../fake/account" import { AuthTest } from "../fake/auth" @@ -29,13 +30,18 @@ const configLayer = Config.layer.pipe( Layer.provide(AccountTest.empty), Layer.provide(NpmTest.noop), ) -const pluginLayer = Plugin.layer.pipe(Layer.provide(Bus.layer), Layer.provide(configLayer)) +const pluginLayer = Plugin.layer.pipe( + Layer.provide(Bus.layer), + Layer.provide(configLayer), + Layer.provide(RuntimeFlags.layer({ disableDefaultPlugins: true })), +) const agentLayer = Agent.layer.pipe( Layer.provide(configLayer), Layer.provide(AuthTest.empty), Layer.provide(SkillTest.empty), Layer.provide(provider.layer), Layer.provide(pluginLayer), + Layer.provide(RuntimeFlags.layer({ disableDefaultPlugins: true })), ) const it = testEffect(Layer.mergeAll(agentLayer, pluginLayer)) diff --git a/packages/opencode/test/bus/bus-integration.test.ts b/packages/opencode/test/bus/bus-integration.test.ts index 3e3d7a3e90..645a94fb3b 100644 --- a/packages/opencode/test/bus/bus-integration.test.ts +++ b/packages/opencode/test/bus/bus-integration.test.ts @@ -1,88 +1,88 @@ -import { afterEach, describe, expect, test } from "bun:test" -import { Schema } from "effect" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { afterEach, describe, expect } from "bun:test" +import { Deferred, Effect, Layer, Schema } from "effect" import { Bus } from "../../src/bus" import { BusEvent } from "../../src/bus/bus-event" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, provideInstance, tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" const TestEvent = BusEvent.define("test.integration", Schema.Struct({ value: Schema.Number })) - -function withInstance(directory: string, fn: () => Promise) { - return WithInstance.provide({ directory, fn }) -} +const it = testEffect(Layer.mergeAll(Bus.layer, CrossSpawnSpawner.defaultLayer)) describe("Bus integration: acquireRelease subscriber pattern", () => { afterEach(() => disposeAllInstances()) - test("subscriber via callback facade receives events and cleans up on unsub", async () => { - await using tmp = await tmpdir() - const received: number[] = [] + it.instance("subscriber via callback facade receives events and cleans up on unsub", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const received: number[] = [] + const receivedTwo = yield* Deferred.make() - await withInstance(tmp.path, async () => { - const unsub = Bus.subscribe(TestEvent, (evt) => { + const unsub = yield* bus.subscribeCallback(TestEvent, (evt) => { received.push(evt.properties.value) + if (received.length === 2) Deferred.doneUnsafe(receivedTwo, Effect.void) }) - await Bun.sleep(10) - await Bus.publish(TestEvent, { value: 1 }) - await Bus.publish(TestEvent, { value: 2 }) - await Bun.sleep(10) + yield* bus.publish(TestEvent, { value: 1 }) + yield* bus.publish(TestEvent, { value: 2 }) + yield* Deferred.await(receivedTwo).pipe(Effect.timeout("2 seconds")) expect(received).toEqual([1, 2]) - unsub() - await Bun.sleep(10) - await Bus.publish(TestEvent, { value: 3 }) - await Bun.sleep(10) + yield* Effect.sync(unsub) + yield* bus.publish(TestEvent, { value: 3 }) + yield* Effect.sleep("10 millis") expect(received).toEqual([1, 2]) - }) - }) + }), + ) - test("subscribeAll receives events from multiple types", async () => { - await using tmp = await tmpdir() - const received: Array<{ type: string; value?: number }> = [] + it.instance("subscribeAll receives events from multiple types", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const received: Array<{ type: string; value?: number }> = [] + const OtherEvent = BusEvent.define("test.other", Schema.Struct({ value: Schema.Number })) + const receivedTwo = yield* Deferred.make() - const OtherEvent = BusEvent.define("test.other", Schema.Struct({ value: Schema.Number })) - - await withInstance(tmp.path, async () => { - Bus.subscribeAll((evt) => { + yield* bus.subscribeAllCallback((evt) => { received.push({ type: evt.type, value: evt.properties.value }) + if (received.length === 2) Deferred.doneUnsafe(receivedTwo, Effect.void) }) - await Bun.sleep(10) - await Bus.publish(TestEvent, { value: 10 }) - await Bus.publish(OtherEvent, { value: 20 }) - await Bun.sleep(10) - }) + yield* bus.publish(TestEvent, { value: 10 }) + yield* bus.publish(OtherEvent, { value: 20 }) + yield* Deferred.await(receivedTwo).pipe(Effect.timeout("2 seconds")) - expect(received).toEqual([ - { type: "test.integration", value: 10 }, - { type: "test.other", value: 20 }, - ]) - }) + expect(received).toEqual([ + { type: "test.integration", value: 10 }, + { type: "test.other", value: 20 }, + ]) + }), + ) - test("subscriber cleanup on instance disposal interrupts the stream", async () => { - await using tmp = await tmpdir() - const received: number[] = [] - let disposed = false + it.live("subscriber cleanup on instance disposal interrupts the stream", () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped() + const received: number[] = [] + const seen = yield* Deferred.make() + const disposed = yield* Deferred.make() - await withInstance(tmp.path, async () => { - Bus.subscribeAll((evt) => { - if (evt.type === Bus.InstanceDisposed.type) { - disposed = true - return - } - received.push(evt.properties.value) - }) - await Bun.sleep(10) - await Bus.publish(TestEvent, { value: 1 }) - await Bun.sleep(10) - }) + yield* Effect.gen(function* () { + const bus = yield* Bus.Service + yield* bus.subscribeAllCallback((evt) => { + if (evt.type === Bus.InstanceDisposed.type) { + Deferred.doneUnsafe(disposed, Effect.void) + return + } + received.push(evt.properties.value) + Deferred.doneUnsafe(seen, Effect.void) + }) + yield* bus.publish(TestEvent, { value: 1 }) + yield* Deferred.await(seen).pipe(Effect.timeout("2 seconds")) + }).pipe(provideInstance(dir)) - await disposeAllInstances() - await Bun.sleep(50) + yield* Effect.promise(() => disposeAllInstances()) + yield* Deferred.await(disposed).pipe(Effect.timeout("2 seconds")) - expect(received).toEqual([1]) - expect(disposed).toBe(true) - }) + expect(received).toEqual([1]) + }), + ) }) diff --git a/packages/opencode/test/bus/bus.test.ts b/packages/opencode/test/bus/bus.test.ts index 876cb1ed74..0844986162 100644 --- a/packages/opencode/test/bus/bus.test.ts +++ b/packages/opencode/test/bus/bus.test.ts @@ -1,220 +1,240 @@ -import { afterEach, describe, expect, test } from "bun:test" -import { Schema } from "effect" +import { afterEach, describe, expect } from "bun:test" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { Deferred, Effect, Layer, Schema } from "effect" import { Bus } from "../../src/bus" import { BusEvent } from "../../src/bus/bus-event" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, provideInstance, tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" const TestEvent = { Ping: BusEvent.define("test.ping", Schema.Struct({ value: Schema.Number })), Pong: BusEvent.define("test.pong", Schema.Struct({ message: Schema.String })), } -function withInstance(directory: string, fn: () => Promise) { - return WithInstance.provide({ directory, fn }) -} +const it = testEffect(Layer.mergeAll(Bus.layer, CrossSpawnSpawner.defaultLayer)) describe("Bus", () => { afterEach(() => disposeAllInstances()) describe("publish + subscribe", () => { - test("subscriber is live immediately after subscribe returns", async () => { - await using tmp = await tmpdir() - const received: number[] = [] + it.instance("subscriber is live immediately after subscribe returns", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const received: number[] = [] + const done = yield* Deferred.make() - await withInstance(tmp.path, async () => { - Bus.subscribe(TestEvent.Ping, (evt) => { + yield* bus.subscribeCallback(TestEvent.Ping, (evt) => { received.push(evt.properties.value) + Deferred.doneUnsafe(done, Effect.void) }) - await Bus.publish(TestEvent.Ping, { value: 42 }) - await Bun.sleep(10) - }) + yield* bus.publish(TestEvent.Ping, { value: 42 }) + yield* Deferred.await(done).pipe(Effect.timeout("2 seconds")) - expect(received).toEqual([42]) - }) + expect(received).toEqual([42]) + }), + ) - test("subscriber receives matching events", async () => { - await using tmp = await tmpdir() - const received: number[] = [] + it.instance("subscriber receives matching events", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const received: number[] = [] + const done = yield* Deferred.make() - await withInstance(tmp.path, async () => { - Bus.subscribe(TestEvent.Ping, (evt) => { + yield* bus.subscribeCallback(TestEvent.Ping, (evt) => { received.push(evt.properties.value) + if (received.length === 2) Deferred.doneUnsafe(done, Effect.void) }) - // Give the subscriber fiber time to start consuming - await Bun.sleep(10) - await Bus.publish(TestEvent.Ping, { value: 42 }) - await Bus.publish(TestEvent.Ping, { value: 99 }) - // Give subscriber time to process - await Bun.sleep(10) - }) + yield* bus.publish(TestEvent.Ping, { value: 42 }) + yield* bus.publish(TestEvent.Ping, { value: 99 }) + yield* Deferred.await(done).pipe(Effect.timeout("2 seconds")) - expect(received).toEqual([42, 99]) - }) + expect(received).toEqual([42, 99]) + }), + ) - test("subscriber does not receive events of other types", async () => { - await using tmp = await tmpdir() - const pings: number[] = [] + it.instance("subscriber does not receive events of other types", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const pings: number[] = [] + const done = yield* Deferred.make() - await withInstance(tmp.path, async () => { - Bus.subscribe(TestEvent.Ping, (evt) => { + yield* bus.subscribeCallback(TestEvent.Ping, (evt) => { pings.push(evt.properties.value) + Deferred.doneUnsafe(done, Effect.void) }) - await Bun.sleep(10) - await Bus.publish(TestEvent.Pong, { message: "hello" }) - await Bus.publish(TestEvent.Ping, { value: 1 }) - await Bun.sleep(10) - }) + yield* bus.publish(TestEvent.Pong, { message: "hello" }) + yield* bus.publish(TestEvent.Ping, { value: 1 }) + yield* Deferred.await(done).pipe(Effect.timeout("2 seconds")) - expect(pings).toEqual([1]) - }) + expect(pings).toEqual([1]) + }), + ) - test("publish with no subscribers does not throw", async () => { - await using tmp = await tmpdir() - - await withInstance(tmp.path, async () => { - await Bus.publish(TestEvent.Ping, { value: 1 }) - }) - }) + it.instance("publish with no subscribers does not throw", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + yield* bus.publish(TestEvent.Ping, { value: 1 }) + }), + ) }) describe("unsubscribe", () => { - test("unsubscribe stops delivery", async () => { - await using tmp = await tmpdir() - const received: number[] = [] + it.instance("unsubscribe stops delivery", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const received: number[] = [] + const first = yield* Deferred.make() - await withInstance(tmp.path, async () => { - const unsub = Bus.subscribe(TestEvent.Ping, (evt) => { + const unsub = yield* bus.subscribeCallback(TestEvent.Ping, (evt) => { received.push(evt.properties.value) + if (evt.properties.value === 1) Deferred.doneUnsafe(first, Effect.void) }) - await Bun.sleep(10) - await Bus.publish(TestEvent.Ping, { value: 1 }) - await Bun.sleep(10) - unsub() - await Bun.sleep(10) - await Bus.publish(TestEvent.Ping, { value: 2 }) - await Bun.sleep(10) - }) + yield* bus.publish(TestEvent.Ping, { value: 1 }) + yield* Deferred.await(first).pipe(Effect.timeout("2 seconds")) + yield* Effect.sync(unsub) + yield* bus.publish(TestEvent.Ping, { value: 2 }) + yield* Effect.sleep("10 millis") - expect(received).toEqual([1]) - }) + expect(received).toEqual([1]) + }), + ) }) describe("subscribeAll", () => { - test("subscribeAll is live immediately after subscribe returns", async () => { - await using tmp = await tmpdir() - const received: string[] = [] + it.instance("subscribeAll is live immediately after subscribe returns", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const received: string[] = [] + const done = yield* Deferred.make() - await withInstance(tmp.path, async () => { - Bus.subscribeAll((evt) => { + yield* bus.subscribeAllCallback((evt) => { received.push(evt.type) + Deferred.doneUnsafe(done, Effect.void) }) - await Bus.publish(TestEvent.Ping, { value: 1 }) - await Bun.sleep(10) - }) + yield* bus.publish(TestEvent.Ping, { value: 1 }) + yield* Deferred.await(done).pipe(Effect.timeout("2 seconds")) - expect(received).toEqual(["test.ping"]) - }) + expect(received).toEqual(["test.ping"]) + }), + ) - test("receives all event types", async () => { - await using tmp = await tmpdir() - const received: string[] = [] + it.instance("receives all event types", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const received: string[] = [] + const done = yield* Deferred.make() - await withInstance(tmp.path, async () => { - Bus.subscribeAll((evt) => { + yield* bus.subscribeAllCallback((evt) => { received.push(evt.type) + if (received.length === 2) Deferred.doneUnsafe(done, Effect.void) }) - await Bun.sleep(10) - await Bus.publish(TestEvent.Ping, { value: 1 }) - await Bus.publish(TestEvent.Pong, { message: "hi" }) - await Bun.sleep(10) - }) + yield* bus.publish(TestEvent.Ping, { value: 1 }) + yield* bus.publish(TestEvent.Pong, { message: "hi" }) + yield* Deferred.await(done).pipe(Effect.timeout("2 seconds")) - expect(received).toContain("test.ping") - expect(received).toContain("test.pong") - }) + expect(received).toContain("test.ping") + expect(received).toContain("test.pong") + }), + ) }) describe("multiple subscribers", () => { - test("all subscribers for same event type are called", async () => { - await using tmp = await tmpdir() - const a: number[] = [] - const b: number[] = [] + it.instance("all subscribers for same event type are called", () => + Effect.gen(function* () { + const bus = yield* Bus.Service + const a: number[] = [] + const b: number[] = [] + const doneA = yield* Deferred.make() + const doneB = yield* Deferred.make() - await withInstance(tmp.path, async () => { - Bus.subscribe(TestEvent.Ping, (evt) => { + yield* bus.subscribeCallback(TestEvent.Ping, (evt) => { a.push(evt.properties.value) + Deferred.doneUnsafe(doneA, Effect.void) }) - Bus.subscribe(TestEvent.Ping, (evt) => { + yield* bus.subscribeCallback(TestEvent.Ping, (evt) => { b.push(evt.properties.value) + Deferred.doneUnsafe(doneB, Effect.void) }) - await Bun.sleep(10) - await Bus.publish(TestEvent.Ping, { value: 7 }) - await Bun.sleep(10) - }) + yield* bus.publish(TestEvent.Ping, { value: 7 }) + yield* Deferred.await(doneA).pipe(Effect.timeout("2 seconds")) + yield* Deferred.await(doneB).pipe(Effect.timeout("2 seconds")) - expect(a).toEqual([7]) - expect(b).toEqual([7]) - }) + expect(a).toEqual([7]) + expect(b).toEqual([7]) + }), + ) }) describe("instance isolation", () => { - test("events in one directory do not reach subscribers in another", async () => { - await using tmpA = await tmpdir() - await using tmpB = await tmpdir() - const receivedA: number[] = [] - const receivedB: number[] = [] + it.live("events in one directory do not reach subscribers in another", () => + Effect.gen(function* () { + const tmpA = yield* tmpdirScoped() + const tmpB = yield* tmpdirScoped() + const receivedA: number[] = [] + const receivedB: number[] = [] + const doneA = yield* Deferred.make() + const doneB = yield* Deferred.make() - await withInstance(tmpA.path, async () => { - Bus.subscribe(TestEvent.Ping, (evt) => { - receivedA.push(evt.properties.value) - }) - await Bun.sleep(10) - }) + yield* Effect.gen(function* () { + const bus = yield* Bus.Service + yield* bus.subscribeCallback(TestEvent.Ping, (evt) => { + receivedA.push(evt.properties.value) + Deferred.doneUnsafe(doneA, Effect.void) + }) + }).pipe(provideInstance(tmpA)) - await withInstance(tmpB.path, async () => { - Bus.subscribe(TestEvent.Ping, (evt) => { - receivedB.push(evt.properties.value) - }) - await Bun.sleep(10) - }) + yield* Effect.gen(function* () { + const bus = yield* Bus.Service + yield* bus.subscribeCallback(TestEvent.Ping, (evt) => { + receivedB.push(evt.properties.value) + Deferred.doneUnsafe(doneB, Effect.void) + }) + }).pipe(provideInstance(tmpB)) - await withInstance(tmpA.path, async () => { - await Bus.publish(TestEvent.Ping, { value: 1 }) - await Bun.sleep(10) - }) + yield* Effect.gen(function* () { + const bus = yield* Bus.Service + yield* bus.publish(TestEvent.Ping, { value: 1 }) + }).pipe(provideInstance(tmpA)) - await withInstance(tmpB.path, async () => { - await Bus.publish(TestEvent.Ping, { value: 2 }) - await Bun.sleep(10) - }) + yield* Effect.gen(function* () { + const bus = yield* Bus.Service + yield* bus.publish(TestEvent.Ping, { value: 2 }) + }).pipe(provideInstance(tmpB)) - expect(receivedA).toEqual([1]) - expect(receivedB).toEqual([2]) - }) + yield* Deferred.await(doneA).pipe(Effect.timeout("2 seconds")) + yield* Deferred.await(doneB).pipe(Effect.timeout("2 seconds")) + + expect(receivedA).toEqual([1]) + expect(receivedB).toEqual([2]) + }), + ) }) describe("instance disposal", () => { - test("InstanceDisposed is delivered to wildcard subscribers before stream ends", async () => { - await using tmp = await tmpdir() - const received: string[] = [] + it.live("InstanceDisposed is delivered to wildcard subscribers before stream ends", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + const received: string[] = [] + const seen = yield* Deferred.make() + const disposed = yield* Deferred.make() - await withInstance(tmp.path, async () => { - Bus.subscribeAll((evt) => { - received.push(evt.type) - }) - await Bun.sleep(10) - await Bus.publish(TestEvent.Ping, { value: 1 }) - await Bun.sleep(10) - }) + yield* Effect.gen(function* () { + const bus = yield* Bus.Service + yield* bus.subscribeAllCallback((evt) => { + received.push(evt.type) + if (evt.type === TestEvent.Ping.type) Deferred.doneUnsafe(seen, Effect.void) + if (evt.type === Bus.InstanceDisposed.type) Deferred.doneUnsafe(disposed, Effect.void) + }) + yield* bus.publish(TestEvent.Ping, { value: 1 }) + yield* Deferred.await(seen).pipe(Effect.timeout("2 seconds")) + }).pipe(provideInstance(tmp)) - // disposeAllInstances triggers the finalizer which publishes InstanceDisposed - await disposeAllInstances() - await Bun.sleep(50) + yield* Effect.promise(disposeAllInstances) + yield* Deferred.await(disposed).pipe(Effect.timeout("2 seconds")) - expect(received).toContain("test.ping") - expect(received).toContain(Bus.InstanceDisposed.type) - }) + expect(received).toContain("test.ping") + expect(received).toContain(Bus.InstanceDisposed.type) + }), + ) }) }) diff --git a/packages/opencode/test/cli/cmd/tui/attention.test.ts b/packages/opencode/test/cli/cmd/tui/attention.test.ts new file mode 100644 index 0000000000..071aabdd79 --- /dev/null +++ b/packages/opencode/test/cli/cmd/tui/attention.test.ts @@ -0,0 +1,484 @@ +import { describe, expect, test } from "bun:test" +import type { AudioPlayOptions, AudioSound } from "@opentui/core" +import { createTuiAttention } from "@/cli/cmd/tui/attention" +import type { TuiConfig } from "@/cli/cmd/tui/config/tui" + +type FocusEvent = "focus" | "blur" + +type AttentionConfig = Pick + +class FakeRenderer { + isDestroyed = false + notificationResult = true + notificationThrows = false + notifications: { message: string; title: string | undefined }[] = [] + listeners: Record void>> = { + focus: new Set(), + blur: new Set(), + } + + on(event: FocusEvent, listener: () => void) { + this.listeners[event].add(listener) + return this + } + + off(event: FocusEvent, listener: () => void) { + this.listeners[event].delete(listener) + return this + } + + emit(event: FocusEvent) { + for (const listener of this.listeners[event]) listener() + } + + listenerCount(event: FocusEvent) { + return this.listeners[event].size + } + + triggerNotification(message: string, title?: string) { + if (this.notificationThrows) throw new Error("notification failed") + this.notifications.push({ message, title }) + return this.notificationResult + } +} + +class FakeAudioEngine { + loadResult: AudioSound | null = 1 + playResult: number | null = 1 + loadCalls = 0 + playCalls = 0 + volumes: (number | undefined)[] = [] + loadPaths: string[] = [] + rejectLoad = false + rejectPaths = new Set() + + async loadSoundFile(path: string) { + this.loadCalls += 1 + this.loadPaths.push(path) + if (this.rejectLoad || this.rejectPaths.has(path)) throw new Error("decode failed") + return this.loadResult + } + + play(_sound: AudioSound, options?: AudioPlayOptions) { + this.playCalls += 1 + this.volumes.push(options?.volume) + return this.playResult + } +} + +class FakeKV { + store: Record = {} + + get ready() { + return true + } + + get(key: string, fallback?: Value) { + return (this.store[key] ?? fallback) as Value + } + + set(key: string, value: unknown) { + this.store[key] = value + } +} + +function config(attention: Partial = {}): AttentionConfig { + return { + attention: { + enabled: true, + notifications: true, + sound: true, + volume: 0.4, + sound_pack: "opencode.default", + sounds: {}, + ...attention, + }, + } +} + +describe("createTuiAttention", () => { + test("defaults to sound always and notification blurred", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + + expect(await attention.notify({ message: "hello" })).toEqual({ + ok: true, + notification: false, + sound: true, + }) + expect(renderer.notifications).toHaveLength(0) + expect(audio.playCalls).toBe(1) + }) + + test("supports blurred-only requests", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + + expect(await attention.notify({ message: "unknown", sound: { when: "blurred" } })).toEqual({ + ok: false, + notification: false, + sound: false, + skipped: "focus_unknown", + }) + renderer.emit("focus") + expect(await attention.notify({ message: "focused", sound: { when: "blurred" } })).toEqual({ + ok: false, + notification: false, + sound: false, + skipped: "focused", + }) + renderer.emit("blur") + expect(await attention.notify({ message: "blurred", sound: { when: "blurred" } })).toEqual({ + ok: true, + notification: true, + sound: true, + }) + expect(audio.playCalls).toBe(1) + }) + + test("supports focused-only requests", async () => { + const renderer = new FakeRenderer() + const attention = createTuiAttention({ renderer, config: config(), audio: new FakeAudioEngine() }) + + expect(await attention.notify({ message: "unknown", notification: { when: "focused" }, sound: false })).toEqual({ + ok: false, + notification: false, + sound: false, + skipped: "focus_unknown", + }) + renderer.emit("blur") + expect(await attention.notify({ message: "blurred", notification: { when: "focused" }, sound: false })).toEqual({ + ok: false, + notification: false, + sound: false, + skipped: "blurred", + }) + renderer.emit("focus") + expect(await attention.notify({ message: "focused", notification: { when: "focused" }, sound: false })).toEqual({ + ok: true, + notification: true, + sound: false, + }) + expect(renderer.notifications).toEqual([{ title: "opencode", message: "focused" }]) + }) + + test("notification can deliver while focused when requested", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + renderer.emit("focus") + + expect(await attention.notify({ message: "hello", notification: { when: "always" } })).toEqual({ + ok: true, + notification: true, + sound: true, + }) + expect(audio.playCalls).toBe(1) + expect(renderer.notifications).toEqual([{ title: "opencode", message: "hello" }]) + }) + + test("notifies while blurred", async () => { + const renderer = new FakeRenderer() + const attention = createTuiAttention({ renderer, config: config(), audio: new FakeAudioEngine() }) + renderer.emit("blur") + + expect(await attention.notify({ title: "opencode", message: "hello", sound: false })).toEqual({ + ok: true, + notification: true, + sound: false, + }) + expect(renderer.notifications).toEqual([{ title: "opencode", message: "hello" }]) + }) + + test("when requested, blurred-only calls do not notify or play sound while focused", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + renderer.emit("focus") + + expect(await attention.notify({ message: "hello", sound: { when: "blurred" } })).toEqual({ + ok: false, + notification: false, + sound: false, + skipped: "focused", + }) + expect(renderer.notifications).toHaveLength(0) + expect(audio.loadCalls).toBe(0) + }) + + test("can play sound always while notification is blurred-only", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + renderer.emit("focus") + + expect( + await attention.notify({ + message: "hello", + sound: { name: "question" }, + }), + ).toEqual({ + ok: true, + notification: false, + sound: true, + }) + expect(renderer.notifications).toHaveLength(0) + expect(audio.playCalls).toBe(1) + + renderer.emit("blur") + expect( + await attention.notify({ + message: "hello again", + sound: { name: "question" }, + }), + ).toEqual({ + ok: true, + notification: true, + sound: true, + }) + expect(renderer.notifications).toEqual([{ title: "opencode", message: "hello again" }]) + }) + + test("can disable notification per call while still playing sound", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + + expect(await attention.notify({ message: "hello", notification: false })).toEqual({ + ok: true, + notification: false, + sound: true, + }) + expect(renderer.notifications).toHaveLength(0) + expect(audio.playCalls).toBe(1) + }) + + test("skips empty messages and disabled attention", async () => { + const empty = new FakeRenderer() + empty.emit("blur") + const disabled = new FakeRenderer() + disabled.emit("blur") + + expect(await createTuiAttention({ renderer: empty, config: config() }).notify({ message: " \n " })).toEqual({ + ok: false, + notification: false, + sound: false, + skipped: "empty_message", + }) + expect( + await createTuiAttention({ renderer: disabled, config: config({ enabled: false }) }).notify({ message: "hello" }), + ).toEqual({ + ok: false, + notification: false, + sound: false, + skipped: "attention_disabled", + }) + }) + + test("respects notification and sound config independently", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config({ notifications: false }), audio }) + renderer.emit("blur") + + expect(await attention.notify({ message: "hello", sound: true })).toEqual({ + ok: true, + notification: false, + sound: true, + }) + expect(renderer.notifications).toHaveLength(0) + expect(audio.playCalls).toBe(1) + + const soundDisabledRenderer = new FakeRenderer() + const soundDisabledAudio = new FakeAudioEngine() + const soundDisabled = createTuiAttention({ + renderer: soundDisabledRenderer, + config: config({ sound: false }), + audio: soundDisabledAudio, + }) + soundDisabledRenderer.emit("blur") + + expect(await soundDisabled.notify({ message: "hello", sound: true })).toEqual({ + ok: true, + notification: true, + sound: false, + }) + expect(soundDisabledAudio.loadCalls).toBe(0) + }) + + test("loads audio lazily only for eligible sound requests", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + + await attention.notify({ message: "unknown", sound: { when: "blurred" } }) + expect(audio.loadCalls).toBe(0) + + renderer.emit("blur") + expect(await attention.notify({ message: "blurred", sound: { volume: 2 } })).toEqual({ + ok: true, + notification: true, + sound: true, + }) + expect(audio.loadCalls).toBe(1) + expect(audio.volumes).toEqual([1]) + }) + + test("handles unavailable playback and delegates sound loading", async () => { + const unavailableRenderer = new FakeRenderer() + const unavailableAudio = new FakeAudioEngine() + unavailableAudio.playResult = null + const unavailable = createTuiAttention({ renderer: unavailableRenderer, config: config(), audio: unavailableAudio }) + unavailableRenderer.emit("blur") + + expect(await unavailable.notify({ message: "hello", sound: true })).toEqual({ + ok: true, + notification: true, + sound: false, + }) + expect(unavailableAudio.loadCalls).toBe(1) + expect(unavailableAudio.playCalls).toBe(1) + + const repeatedRenderer = new FakeRenderer() + const repeatedAudio = new FakeAudioEngine() + const repeated = createTuiAttention({ renderer: repeatedRenderer, config: config(), audio: repeatedAudio }) + repeatedRenderer.emit("blur") + + await repeated.notify({ message: "one", sound: true }) + await repeated.notify({ message: "two", sound: true }) + expect(repeatedAudio.loadCalls).toBe(2) + expect(repeatedAudio.playCalls).toBe(2) + }) + + test("plays named sounds from the active sound pack", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + renderer.emit("blur") + + const dispose = attention.soundboard.registerPack({ + id: "acme.soft", + name: "Soft Alerts", + sounds: { + question: "/tmp/question.mp3", + }, + }) + + expect(attention.soundboard.activate("acme.soft")).toBe(true) + expect(attention.soundboard.current()).toBe("acme.soft") + expect(attention.soundboard.list()).toContainEqual({ + id: "acme.soft", + name: "Soft Alerts", + active: true, + builtin: false, + }) + + expect(await attention.notify({ message: "question", sound: { name: "question" } })).toEqual({ + ok: true, + notification: true, + sound: true, + }) + expect(audio.loadPaths).toEqual(["/tmp/question.mp3"]) + + dispose() + expect(attention.soundboard.current()).toBe("opencode.default") + }) + + test("uses config sound overrides before active pack sounds and falls back on load failure", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + audio.rejectPaths.add("/tmp/bad-question.mp3") + const attention = createTuiAttention({ + renderer, + config: config({ sounds: { question: "/tmp/bad-question.mp3" } }), + audio, + }) + renderer.emit("blur") + + attention.soundboard.registerPack({ + id: "acme.soft", + sounds: { + question: "/tmp/good-question.mp3", + }, + }) + attention.soundboard.activate("acme.soft") + + expect(await attention.notify({ message: "question", sound: { name: "question" } })).toEqual({ + ok: true, + notification: true, + sound: true, + }) + expect(audio.loadPaths).toEqual(["/tmp/bad-question.mp3", "/tmp/good-question.mp3"]) + }) + + test("persists activated sound pack in KV", () => { + const kv = new FakeKV() + const renderer = new FakeRenderer() + const attention = createTuiAttention({ renderer, config: config(), kv }) + + attention.soundboard.registerPack({ id: "acme.soft", sounds: { done: "/tmp/done.mp3" } }) + + expect(attention.soundboard.activate("missing", { persist: true })).toBe(false) + expect(kv.store.attention_sound_pack).toBeUndefined() + expect(attention.soundboard.activate("acme.soft", { persist: true })).toBe(true) + expect(kv.store.attention_sound_pack).toBe("acme.soft") + + const next = createTuiAttention({ renderer: new FakeRenderer(), config: config(), kv }) + next.soundboard.registerPack({ id: "acme.soft", sounds: { done: "/tmp/done.mp3" } }) + expect(next.soundboard.current()).toBe("acme.soft") + }) + + test("does not throw for notification or sound failures", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + renderer.notificationThrows = true + audio.rejectLoad = true + const attention = createTuiAttention({ renderer, config: config(), audio }) + renderer.emit("blur") + + expect(await attention.notify({ message: "hello", sound: true })).toEqual({ + ok: false, + notification: false, + sound: false, + }) + }) + + test("strips unsafe notification text", async () => { + const renderer = new FakeRenderer() + const attention = createTuiAttention({ renderer, config: config(), audio: new FakeAudioEngine() }) + renderer.emit("blur") + + await attention.notify({ + title: "\u001b[31m danger\n title\u0007", + message: "\u001b[32m hello\n world\u0000", + }) + + expect(renderer.notifications).toEqual([{ title: "danger title", message: "hello world" }]) + }) + + test("disposes renderer listeners", async () => { + const renderer = new FakeRenderer() + const audio = new FakeAudioEngine() + const attention = createTuiAttention({ renderer, config: config(), audio }) + renderer.emit("blur") + await attention.notify({ message: "hello", sound: true }) + + expect(renderer.listenerCount("focus")).toBe(1) + expect(renderer.listenerCount("blur")).toBe(1) + + attention.dispose() + renderer.isDestroyed = true + + expect(renderer.listenerCount("focus")).toBe(0) + expect(renderer.listenerCount("blur")).toBe(0) + expect(audio.loadCalls).toBe(1) + expect(await attention.notify({ message: "hello" })).toEqual({ + ok: false, + notification: false, + sound: false, + skipped: "renderer_destroyed", + }) + }) +}) diff --git a/packages/opencode/test/cli/cmd/tui/notifications.test.ts b/packages/opencode/test/cli/cmd/tui/notifications.test.ts new file mode 100644 index 0000000000..17ed54bafd --- /dev/null +++ b/packages/opencode/test/cli/cmd/tui/notifications.test.ts @@ -0,0 +1,267 @@ +import { describe, expect, test } from "bun:test" +import Notifications from "@/cli/cmd/tui/feature-plugins/system/notifications" +import type { Event, PermissionRequest, QuestionRequest, Session } from "@opencode-ai/sdk/v2" +import type { TuiAttentionNotifyInput } from "@opencode-ai/plugin/tui" +import { createTuiPluginApi } from "../../../fixture/tui-plugin" + +async function setup() { + const notifications: TuiAttentionNotifyInput[] = [] + const handlers = new Map void)[]>() + const session = (id: string, title: string, parentID?: string): Session => ({ + id, + title, + slug: id, + projectID: "project", + directory: "/workspace", + ...(parentID && { parentID }), + version: "0.0.0-test", + time: { created: 0, updated: 0 }, + }) + const sessions: Record = { + session: session("session", "Demo session"), + subagent: session("subagent", "Subagent session", "session"), + abort: session("abort", "Abort session"), + timeout: session("timeout", "Timeout session"), + } + + await Notifications.tui( + createTuiPluginApi({ + attention: { + async notify(input) { + notifications.push(input) + return { ok: true, notification: true, sound: true } + }, + }, + event: { + on: (type: Type, handler: (event: Extract) => void) => { + const list = handlers.get(type) ?? [] + const wrapped = handler as (event: Event) => void + list.push(wrapped) + handlers.set(type, list) + return () => { + handlers.set( + type, + (handlers.get(type) ?? []).filter((item) => item !== wrapped), + ) + } + }, + }, + state: { + session: { + get: (sessionID: string) => sessions[sessionID], + }, + }, + }), + undefined, + {} as never, + ) + + return { + notifications, + emit(event: Event) { + for (const handler of handlers.get(event.type) ?? []) handler(event) + }, + } +} + +function question(id: string, sessionID = "session"): QuestionRequest { + return { + id, + sessionID, + questions: [], + } +} + +function permission(id: string, sessionID = "session"): PermissionRequest { + return { + id, + sessionID, + permission: "edit", + patterns: [], + metadata: {}, + always: [], + } +} + +const questionNotification: TuiAttentionNotifyInput = { + title: "Demo session", + message: "Question needs input", + notification: { when: "blurred" }, + sound: { name: "question", when: "always" }, +} + +const permissionNotification: TuiAttentionNotifyInput = { + title: "Demo session", + message: "Permission needs input", + notification: { when: "blurred" }, + sound: { name: "permission", when: "always" }, +} + +describe("internal notifications TUI plugin", () => { + test("notifies for question and permission requests with blurred notifications and always-on sounds", async () => { + const harness = await setup() + + harness.emit({ id: "event-1", type: "question.asked", properties: question("question-1") }) + harness.emit({ id: "event-2", type: "permission.asked", properties: permission("permission-1") }) + + expect(harness.notifications).toEqual([questionNotification, permissionNotification]) + }) + + test("dedupes pending questions and permissions until they are resolved", async () => { + const harness = await setup() + + harness.emit({ id: "event-1", type: "question.asked", properties: question("question-1") }) + harness.emit({ id: "event-2", type: "question.asked", properties: question("question-1") }) + harness.emit({ + id: "event-3", + type: "question.replied", + properties: { sessionID: "session", requestID: "question-1", answers: [] }, + }) + harness.emit({ id: "event-4", type: "question.asked", properties: question("question-1") }) + + harness.emit({ id: "event-5", type: "permission.asked", properties: permission("permission-1") }) + harness.emit({ id: "event-6", type: "permission.asked", properties: permission("permission-1") }) + harness.emit({ + id: "event-7", + type: "permission.replied", + properties: { sessionID: "session", requestID: "permission-1", reply: "once" }, + }) + harness.emit({ id: "event-8", type: "permission.asked", properties: permission("permission-1") }) + + expect(harness.notifications).toEqual([ + questionNotification, + questionNotification, + permissionNotification, + permissionNotification, + ]) + }) + + test("notifies when an active session becomes idle and suppresses no-op idle", async () => { + const harness = await setup() + + harness.emit({ + id: "event-1", + type: "session.status", + properties: { sessionID: "session", status: { type: "idle" } }, + }) + harness.emit({ + id: "event-2", + type: "session.status", + properties: { sessionID: "session", status: { type: "busy" } }, + }) + harness.emit({ + id: "event-3", + type: "session.status", + properties: { sessionID: "session", status: { type: "idle" } }, + }) + + expect(harness.notifications).toEqual([ + { + title: "Demo session", + message: "Session done", + notification: { when: "blurred" }, + sound: { name: "done", when: "always" }, + }, + ]) + }) + + test("uses sound-only notifications and subagent_done sound for subagent sessions", async () => { + const harness = await setup() + + harness.emit({ id: "event-1", type: "question.asked", properties: question("question-1", "subagent") }) + harness.emit({ + id: "event-2", + type: "session.status", + properties: { sessionID: "subagent", status: { type: "busy" } }, + }) + harness.emit({ + id: "event-3", + type: "session.status", + properties: { sessionID: "subagent", status: { type: "idle" } }, + }) + + expect(harness.notifications).toEqual([ + { + title: "Subagent session", + message: "Question needs input", + notification: false, + sound: { name: "question", when: "always" }, + }, + { + title: "Subagent session", + message: "Session done", + notification: false, + sound: { name: "subagent_done", when: "always" }, + }, + ]) + }) + + test("notifies session errors once and suppresses the following idle done notification", async () => { + const harness = await setup() + + harness.emit({ + id: "event-1", + type: "session.status", + properties: { sessionID: "session", status: { type: "busy" } }, + }) + harness.emit({ + id: "event-2", + type: "session.error", + properties: { sessionID: "session", error: { name: "UnknownError", data: { message: "boom" } } }, + }) + harness.emit({ + id: "event-3", + type: "session.status", + properties: { sessionID: "session", status: { type: "idle" } }, + }) + + expect(harness.notifications).toEqual([ + { + title: "Demo session", + message: "Session error", + notification: { when: "blurred" }, + sound: { name: "error", when: "always" }, + }, + ]) + }) + + test("special-cases aborts and model response timeouts", async () => { + const harness = await setup() + + harness.emit({ + id: "event-1", + type: "session.status", + properties: { sessionID: "abort", status: { type: "busy" } }, + }) + harness.emit({ + id: "event-2", + type: "session.error", + properties: { sessionID: "abort", error: { name: "MessageAbortedError", data: { message: "Aborted" } } }, + }) + harness.emit({ + id: "event-3", + type: "session.status", + properties: { sessionID: "timeout", status: { type: "busy" } }, + }) + harness.emit({ + id: "event-4", + type: "session.error", + properties: { sessionID: "timeout", error: { name: "UnknownError", data: { message: "SSE read timed out" } } }, + }) + + expect(harness.notifications).toEqual([ + { + title: "Abort session", + message: "Session aborted", + notification: { when: "blurred" }, + sound: { name: "error", when: "always" }, + }, + { + title: "Timeout session", + message: "Model stopped responding", + notification: { when: "blurred" }, + sound: { name: "error", when: "always" }, + }, + ]) + }) +}) diff --git a/packages/opencode/test/cli/effect-cmd-instance-als.test.ts b/packages/opencode/test/cli/effect-cmd-instance-als.test.ts index de6fed8daa..122b87f174 100644 --- a/packages/opencode/test/cli/effect-cmd-instance-als.test.ts +++ b/packages/opencode/test/cli/effect-cmd-instance-als.test.ts @@ -1,8 +1,13 @@ -import { afterEach, expect, test } from "bun:test" +import { afterEach, expect } from "bun:test" +import { AppFileSystem } from "@opencode-ai/core/filesystem" import { Effect } from "effect" -import fs from "fs/promises" +import { fileURLToPath } from "url" +import { InstanceRef } from "../../src/effect/instance-ref" import { Instance } from "../../src/project/instance" -import { disposeAllInstances, provideTestInstance, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" + +const it = testEffect(AppFileSystem.defaultLayer) afterEach(async () => { await disposeAllInstances() @@ -14,35 +19,40 @@ afterEach(async () => { // has lost the outer InstanceRef. Services that read `InstanceState.context` // then fall back to `Instance.current` ALS, which must be installed at the JS // callback boundary (Node ALS persists across awaits, Effect's fiber context -// does not). `provideTestInstance` mirrors effectCmd's load + ALS-restore wrap. +// does not). `it.instance` provides the loaded InstanceRef; the explicit +// Instance.restore mirrors effectCmd's load + ALS-restore wrap. // Pins effect-cmd.ts directly: the pattern test below exercises the load + -// Instance.restore + dispose triple via the shared `provideTestInstance` fixture, +// Instance.restore boundary via the shared `it.instance` fixture, // so a regression that removed `Instance.restore` from effect-cmd.ts wouldn't // fail it. This grep guards the actual production callsite. -test("effect-cmd.ts wraps the handler body in Instance.restore", async () => { - const source = await fs.readFile(new URL("../../src/cli/effect-cmd.ts", import.meta.url), "utf8") - expect(source).toContain("Instance.restore(ctx") -}) +it.live("effect-cmd.ts wraps the handler body in Instance.restore", () => + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const source = yield* fs.readFileString(fileURLToPath(new URL("../../src/cli/effect-cmd.ts", import.meta.url))) + expect(source).toContain("Instance.restore(ctx") + }), +) -test("Instance.current reachable from inner runPromise inside Effect.promise(async)", async () => { - await using dir = await tmpdir({ git: true }) - await provideTestInstance({ - directory: dir.path, - fn: () => - Effect.runPromise( - Effect.promise(async () => { - await new Promise((r) => setTimeout(r, 5)) - const current = await Effect.runPromise( - Effect.sync(() => { - try { - return Instance.current - } catch { - return undefined - } - }), - ) - expect(current?.directory).toBe(dir.path) +it.instance( + "Instance.current reachable after await inside restored Effect.promise(async)", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const ctx = yield* InstanceRef + if (!ctx) throw new Error("InstanceRef not provided") + + const current = yield* Effect.promise(() => + Instance.restore(ctx, async () => { + await Promise.resolve() + try { + return Instance.current + } catch { + return undefined + } }), - ), - }) -}) + ) + + expect(current?.directory).toBe(test.directory) + }), + { git: true }, +) diff --git a/packages/opencode/test/cli/error.test.ts b/packages/opencode/test/cli/error.test.ts index 6af2633ce6..6c5ab265b3 100644 --- a/packages/opencode/test/cli/error.test.ts +++ b/packages/opencode/test/cli/error.test.ts @@ -1,8 +1,56 @@ import { describe, expect, test } from "bun:test" import { AccountTransportError } from "../../src/account/schema" import { FormatError } from "../../src/cli/error" +import { UI } from "../../src/cli/ui" describe("cli.error", () => { + test("formats legacy and tagged config errors the same way", () => { + const cases = [ + { + tag: "ConfigJsonError", + data: { path: "/tmp/opencode.jsonc", message: "Unexpected token" }, + expected: "Config file at /tmp/opencode.jsonc is not valid JSON(C): Unexpected token", + }, + { + tag: "ConfigDirectoryTypoError", + data: { path: "/tmp/opencode.jsonc", dir: ".opencode", suggestion: "opencode" }, + expected: + 'Directory ".opencode" in /tmp/opencode.jsonc is not valid. Rename the directory to "opencode" or remove it. This is a common typo.', + }, + { + tag: "ConfigFrontmatterError", + data: { path: "/tmp/AGENTS.md", message: "failed frontmatter" }, + expected: "failed frontmatter", + }, + { + tag: "ConfigInvalidError", + data: { + path: "/tmp/opencode.jsonc", + message: "schema mismatch", + issues: [{ message: "Expected string", path: ["provider", "id"] }], + }, + expected: "Configuration is invalid at /tmp/opencode.jsonc: schema mismatch\n↳ Expected string provider.id", + }, + ] + + for (const item of cases) { + expect(FormatError({ name: item.tag, data: item.data })).toBe(item.expected) + expect(FormatError({ _tag: item.tag, ...item.data })).toBe(item.expected) + } + }) + + test("preserves multiline JSONC diagnostics for tagged config errors", () => { + const data = { + path: "/tmp/opencode.jsonc", + message: + '\n--- JSONC Input ---\n{\n "model": \n}\n--- Errors ---\nValueExpected at line 3, column 1\n Line 3: }\n ^\n--- End ---', + } + const expected = `Config file at ${data.path} is not valid JSON(C): ${data.message}` + + expect(FormatError({ name: "ConfigJsonError", data })).toBe(expected) + expect(FormatError({ _tag: "ConfigJsonError", ...data })).toBe(expected) + }) + test("formats account transport errors clearly", () => { const error = new AccountTransportError({ method: "POST", @@ -15,4 +63,8 @@ describe("cli.error", () => { expect(formatted).toContain("This failed before the server returned an HTTP response.") expect(formatted).toContain("Check your network, proxy, or VPN configuration and try again.") }) + + test("formats cancelled UI errors as empty output", () => { + expect(FormatError(new UI.CancelledError())).toBe("") + }) }) diff --git a/packages/opencode/test/cli/run/runtime.boot.test.ts b/packages/opencode/test/cli/run/runtime.boot.test.ts index e2569b0ac6..8dd9785532 100644 --- a/packages/opencode/test/cli/run/runtime.boot.test.ts +++ b/packages/opencode/test/cli/run/runtime.boot.test.ts @@ -1,14 +1,9 @@ import { afterEach, describe, expect, mock, spyOn, test } from "bun:test" -import type { KeyEvent, Renderable } from "@opentui/core" -import type { Binding } from "@opentui/keymap" -import { createBindingLookup } from "@opentui/keymap/extras" import { OpencodeClient, type Provider } from "@opencode-ai/sdk/v2" import { TuiConfig, type Resolved } from "@/cli/cmd/tui/config/tui" import { formatBindings } from "@/cli/cmd/run/keymap.shared" -import { TuiKeybind } from "@/cli/cmd/tui/config/keybind" import { resolveDiffStyle, resolveFooterKeybinds, resolveModelInfo } from "@/cli/cmd/run/runtime.boot" - -type RunBinding = Binding +import { createTuiResolvedConfig } from "../../fixture/tui-runtime" function model(id: string, providerID: string, context: number, variants?: Record>) { return { @@ -61,45 +56,37 @@ function model(id: string, providerID: string, context: number, variants?: Recor } } -function bindings(...keys: string[]) { - return keys.map((key) => ({ key })) -} - function config(input?: { leader?: string leaderTimeout?: number diff_style?: "auto" | "stacked" bindings?: Partial<{ - commandList: RunBinding[] - variantCycle: RunBinding[] - interrupt: RunBinding[] - historyPrevious: RunBinding[] - historyNext: RunBinding[] - inputClear: RunBinding[] - inputSubmit: RunBinding[] - inputNewline: RunBinding[] + commandList: string[] + variantCycle: string[] + interrupt: string[] + historyPrevious: string[] + historyNext: string[] + inputClear: string[] + inputSubmit: string[] + inputNewline: string[] }> }): Resolved { const bind = input?.bindings - const keybinds = TuiKeybind.Keybinds.parse({ - ...(input?.leader && { leader: input.leader }), - ...(bind?.commandList && { command_list: bind.commandList }), - ...(bind?.variantCycle && { variant_cycle: bind.variantCycle }), - ...(bind?.interrupt && { session_interrupt: bind.interrupt }), - ...(bind?.historyPrevious && { history_previous: bind.historyPrevious }), - ...(bind?.historyNext && { history_next: bind.historyNext }), - ...(bind?.inputClear && { input_clear: bind.inputClear }), - ...(bind?.inputSubmit && { input_submit: bind.inputSubmit }), - ...(bind?.inputNewline && { input_newline: bind.inputNewline }), - }) - return { + return createTuiResolvedConfig({ diff_style: input?.diff_style, - keybinds: createBindingLookup(TuiKeybind.toBindingConfig(keybinds), { - commandMap: TuiKeybind.CommandMap, - bindingDefaults: TuiKeybind.bindingDefaults(), - }), - leader_timeout: input?.leaderTimeout ?? 2000, - } + leader_timeout: input?.leaderTimeout, + keybinds: { + ...(input?.leader && { leader: input.leader }), + ...(bind?.commandList && { command_list: bind.commandList }), + ...(bind?.variantCycle && { variant_cycle: bind.variantCycle }), + ...(bind?.interrupt && { session_interrupt: bind.interrupt }), + ...(bind?.historyPrevious && { history_previous: bind.historyPrevious }), + ...(bind?.historyNext && { history_next: bind.historyNext }), + ...(bind?.inputClear && { input_clear: bind.inputClear }), + ...(bind?.inputSubmit && { input_submit: bind.inputSubmit }), + ...(bind?.inputNewline && { input_newline: bind.inputNewline }), + }, + }) } describe("run runtime boot", () => { @@ -112,14 +99,14 @@ describe("run runtime boot", () => { config({ leader: "ctrl+g", bindings: { - commandList: bindings("ctrl+p"), - variantCycle: bindings("ctrl+t", "alt+t"), - interrupt: bindings("ctrl+c"), - historyPrevious: bindings("k"), - historyNext: bindings("j"), - inputClear: bindings("ctrl+l"), - inputSubmit: bindings("ctrl+s"), - inputNewline: bindings("alt+return"), + commandList: ["ctrl+p"], + variantCycle: ["ctrl+t", "alt+t"], + interrupt: ["ctrl+c"], + historyPrevious: ["k"], + historyNext: ["j"], + inputClear: ["ctrl+l"], + inputSubmit: ["ctrl+s"], + inputNewline: ["alt+return"], }, }), ) diff --git a/packages/opencode/test/cli/tui/plugin-loader.test.ts b/packages/opencode/test/cli/tui/plugin-loader.test.ts index 493520fc00..ce62550e12 100644 --- a/packages/opencode/test/cli/tui/plugin-loader.test.ts +++ b/packages/opencode/test/cli/tui/plugin-loader.test.ts @@ -3,6 +3,7 @@ import fs from "fs/promises" import path from "path" import { pathToFileURL } from "url" import { createTestKeymap } from "@opentui/keymap/testing" +import type { TuiAttentionSoundPack } from "@opencode-ai/plugin/tui" import { tmpdir } from "../../fixture/fixture" import { createTuiPluginApi } from "../../fixture/tui-plugin" import { createTuiResolvedConfig, mockTuiRuntime } from "../../fixture/tui-runtime" @@ -854,6 +855,85 @@ test("plugin keymap proxy preserves real keymap receiver", async () => { } }) +test("auto-disposes plugin attention sound packs and resolves sound paths", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + const file = path.join(dir, "attention-soundpack-plugin.ts") + const spec = pathToFileURL(file).href + const absolute = path.join(dir, "sounds", "default.mp3") + const url = pathToFileURL(path.join(dir, "sounds", "error.mp3")).href + + await Bun.write( + file, + `export default { + id: "demo.attention.soundpack", + tui: async (api) => { + api.attention.soundboard.registerPack({ + id: "demo.pack", + sounds: { + default: ${JSON.stringify(absolute)}, + question: "sounds/question.mp3", + done: " sounds/done.mp3 ", + subagent_done: "sounds/subagent-done.mp3", + error: ${JSON.stringify(url)}, + nope: "sounds/nope.mp3", + permission: "", + }, + }) + }, +} +`, + ) + + return { spec } + }, + }) + + const packs: TuiAttentionSoundPack[] = [] + let dropped = 0 + const attention = { + soundboard: { + registerPack(pack: TuiAttentionSoundPack) { + packs.push(pack) + return () => { + dropped += 1 + } + }, + }, + } + const wait = spyOn(TuiConfig, "waitForDependencies").mockResolvedValue() + const cwd = spyOn(process, "cwd").mockImplementation(() => tmp.path) + + try { + await TuiPluginRuntime.init({ + api: createTuiPluginApi({ attention }), + config: createTuiResolvedConfig({ + plugin: [tmp.extra.spec], + plugin_origins: [{ spec: tmp.extra.spec, scope: "local", source: path.join(tmp.path, "tui.json") }], + }), + }) + + expect(packs).toEqual([ + { + id: "demo.pack", + sounds: { + default: path.join(tmp.path, "sounds", "default.mp3"), + question: path.join(tmp.path, "sounds", "question.mp3"), + done: path.join(tmp.path, "sounds", "done.mp3"), + subagent_done: path.join(tmp.path, "sounds", "subagent-done.mp3"), + error: path.join(tmp.path, "sounds", "error.mp3"), + }, + }, + ]) + expect(dropped).toBe(0) + } finally { + await TuiPluginRuntime.dispose() + expect(dropped).toBe(1) + cwd.mockRestore() + wait.mockRestore() + } +}) + test("auto-disposes plugin keymap transformers", async () => { await using tmp = await tmpdir({ init: async (dir) => { diff --git a/packages/opencode/test/config/agent-color.test.ts b/packages/opencode/test/config/agent-color.test.ts index 49509156ab..d198080591 100644 --- a/packages/opencode/test/config/agent-color.test.ts +++ b/packages/opencode/test/config/agent-color.test.ts @@ -1,69 +1,47 @@ -import { test, expect } from "bun:test" +import { expect } from "bun:test" import { Effect, Layer } from "effect" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" -import path from "path" -import { provideInstance, tmpdirScoped } from "../fixture/fixture" import { Config } from "@/config/config" import { Agent as AgentSvc } from "../../src/agent/agent" -import { Color } from "@/util/color" -import { AppRuntime } from "../../src/effect/app-runtime" import { testEffect } from "../lib/effect" -const it = testEffect(Layer.mergeAll(AgentSvc.defaultLayer, CrossSpawnSpawner.defaultLayer)) +const it = testEffect(Layer.mergeAll(Config.defaultLayer, AgentSvc.defaultLayer, CrossSpawnSpawner.defaultLayer)) -const writeConfig = (dir: string, agent: Config.Info["agent"]) => - Effect.promise(() => - Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - agent, - }), - ), - ) - -it.live("agent color parsed from project config", () => - Effect.gen(function* () { - const dir = yield* tmpdirScoped() - yield* writeConfig(dir, { - build: { color: "#FFA500" }, - plan: { color: "primary" }, - }) - - yield* Effect.gen(function* () { - const cfg = yield* Effect.promise(() => AppRuntime.runPromise(Config.Service.use((svc) => svc.get()))) +it.instance( + "agent color parsed from project config", + () => + Effect.gen(function* () { + const cfg = yield* Config.Service.use((svc) => svc.get()) expect(cfg.agent?.["build"]?.color).toBe("#FFA500") expect(cfg.agent?.["plan"]?.color).toBe("primary") - }).pipe(provideInstance(dir)) - }), + }), + { + git: true, + config: { + agent: { + build: { color: "#FFA500" }, + plan: { color: "primary" }, + }, + }, + }, ) -it.live("Agent.get includes color from config", () => - Effect.gen(function* () { - const dir = yield* tmpdirScoped() - yield* writeConfig(dir, { - plan: { color: "#A855F7" }, - build: { color: "accent" }, - }) - - yield* Effect.gen(function* () { +it.instance( + "Agent.get includes color from config", + () => + Effect.gen(function* () { const plan = yield* AgentSvc.Service.use((svc) => svc.get("plan")) expect(plan?.color).toBe("#A855F7") const build = yield* AgentSvc.Service.use((svc) => svc.get("build")) expect(build?.color).toBe("accent") - }).pipe(provideInstance(dir)) - }), + }), + { + git: true, + config: { + agent: { + plan: { color: "#A855F7" }, + build: { color: "accent" }, + }, + }, + }, ) - -test("Color.hexToAnsiBold converts valid hex to ANSI", () => { - const result = Color.hexToAnsiBold("#FFA500") - expect(result).toBe("\x1b[38;2;255;165;0m\x1b[1m") -}) - -test("Color.hexToAnsiBold returns undefined for invalid hex", () => { - expect(Color.hexToAnsiBold(undefined)).toBeUndefined() - expect(Color.hexToAnsiBold("")).toBeUndefined() - expect(Color.hexToAnsiBold("#FFF")).toBeUndefined() - expect(Color.hexToAnsiBold("FFA500")).toBeUndefined() - expect(Color.hexToAnsiBold("#GGGGGG")).toBeUndefined() -}) diff --git a/packages/opencode/test/config/tui.test.ts b/packages/opencode/test/config/tui.test.ts index db04568573..30c5a65fbd 100644 --- a/packages/opencode/test/config/tui.test.ts +++ b/packages/opencode/test/config/tui.test.ts @@ -1,113 +1,100 @@ -import { afterEach, beforeEach, expect, test } from "bun:test" +import { expect } from "bun:test" import path from "path" -import fs from "fs/promises" -import { provideTestInstance, tmpdir } from "../fixture/fixture" -import { InstanceRuntime } from "@/project/instance-runtime" -import { TuiConfig } from "../../src/cli/cmd/tui/config/tui" -import { Config } from "@/config/config" -import { Global } from "@opencode-ai/core/global" -import { Filesystem } from "@/util/filesystem" -import { AppRuntime } from "../../src/effect/app-runtime" +import { pathToFileURL } from "url" import { Effect, Layer } from "effect" -import { CurrentWorkingDirectory } from "@/cli/cmd/tui/config/cwd" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { Global } from "@opencode-ai/core/global" +import { Config } from "@/config/config" import { ConfigPlugin } from "@/config/plugin" +import { CurrentWorkingDirectory } from "@/cli/cmd/tui/config/cwd" +import { TuiConfig } from "../../src/cli/cmd/tui/config/tui" +import { TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" -const wintest = process.platform === "win32" ? test : test.skip -const clear = async (wait = false) => { - await AppRuntime.runPromise(Config.Service.use((svc) => svc.invalidate())) - if (wait) await InstanceRuntime.disposeAllInstances() -} -const load = () => AppRuntime.runPromise(Config.Service.use((svc) => svc.get())) +const it = testEffect(Layer.mergeAll(Config.defaultLayer, AppFileSystem.defaultLayer)) +const winIt = process.platform === "win32" ? it.instance : it.instance.skip -beforeEach(async () => { - await clear(true) -}) +const globalConfigFiles = ["opencode.json", "opencode.jsonc", "tui.json", "tui.jsonc"].map((file) => + path.join(Global.Path.config, file), +) -const getTuiConfig = async (directory: string) => - Effect.runPromise( - TuiConfig.Service.use((svc) => svc.get()).pipe( - Effect.provide(TuiConfig.defaultLayer.pipe(Layer.provide(Layer.succeed(CurrentWorkingDirectory, directory)))), - ), - ) - -async function withPlatform(platform: typeof process.platform, fn: () => Promise) { - const original = Object.getOwnPropertyDescriptor(process, "platform") - Object.defineProperty(process, "platform", { - ...original, - value: platform, - }) - try { - return await fn() - } finally { - if (original) Object.defineProperty(process, "platform", original) - } -} - -afterEach(async () => { +const cleanState = Effect.gen(function* () { + const fs = yield* AppFileSystem.Service delete process.env.OPENCODE_CONFIG delete process.env.OPENCODE_TUI_CONFIG - await fs.rm(path.join(Global.Path.config, "opencode.json"), { force: true }).catch(() => {}) - await fs.rm(path.join(Global.Path.config, "opencode.jsonc"), { force: true }).catch(() => {}) - await fs.rm(path.join(Global.Path.config, "tui.json"), { force: true }).catch(() => {}) - await fs.rm(path.join(Global.Path.config, "tui.jsonc"), { force: true }).catch(() => {}) - await clear(true) + yield* Effect.forEach(globalConfigFiles, (file) => fs.remove(file, { force: true }).pipe(Effect.ignore), { + discard: true, + }) }) -test("keeps server and tui plugin merge semantics aligned", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - const local = path.join(dir, ".opencode") - await fs.mkdir(local, { recursive: true }) +const withCleanState = (self: Effect.Effect) => + Effect.acquireUseRelease( + cleanState, + () => self, + () => cleanState, + ) - await Bun.write( - path.join(Global.Path.config, "opencode.json"), - JSON.stringify( - { - plugin: [["shared-plugin@1.0.0", { source: "global" }], "global-only@1.0.0"], - }, - null, - 2, - ), - ) - await Bun.write( - path.join(Global.Path.config, "tui.json"), - JSON.stringify( - { - plugin: [["shared-plugin@1.0.0", { source: "global" }], "global-only@1.0.0"], - }, - null, - 2, - ), - ) +const withEnv = (name: string, value: string | undefined, self: Effect.Effect) => + Effect.acquireUseRelease( + Effect.sync(() => { + const previous = process.env[name] + if (value === undefined) delete process.env[name] + else process.env[name] = value + return previous + }), + () => self, + (previous) => + Effect.sync(() => { + if (previous === undefined) delete process.env[name] + else process.env[name] = previous + }), + ) - await Bun.write( - path.join(local, "opencode.json"), - JSON.stringify( - { - plugin: [["shared-plugin@2.0.0", { source: "local" }], "local-only@1.0.0"], - }, - null, - 2, - ), - ) - await Bun.write( - path.join(local, "tui.json"), - JSON.stringify( - { - plugin: [["shared-plugin@2.0.0", { source: "local" }], "local-only@1.0.0"], - }, - null, - 2, - ), - ) - }, - }) +const withPlatform = (platform: typeof process.platform, self: Effect.Effect) => + Effect.acquireUseRelease( + Effect.sync(() => { + const original = Object.getOwnPropertyDescriptor(process, "platform") + Object.defineProperty(process, "platform", { + ...original, + value: platform, + }) + return original + }), + () => self, + (original) => + Effect.sync(() => { + if (original) Object.defineProperty(process, "platform", original) + }), + ) - await provideTestInstance({ - directory: tmp.path, - fn: async () => { - const server = await load() - const tui = await getTuiConfig(tmp.path) +const getTuiConfig = (directory: string) => + TuiConfig.Service.use((svc) => svc.get()).pipe( + Effect.provide(TuiConfig.defaultLayer.pipe(Layer.provide(Layer.succeed(CurrentWorkingDirectory, directory)))), + ) + +it.instance("keeps server and tui plugin merge semantics aligned", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + const local = path.join(test.directory, ".opencode") + yield* fs.makeDirectory(local, { recursive: true }) + + yield* fs.writeJson(path.join(Global.Path.config, "opencode.json"), { + plugin: [["shared-plugin@1.0.0", { source: "global" }], "global-only@1.0.0"], + }) + yield* fs.writeJson(path.join(Global.Path.config, "tui.json"), { + plugin: [["shared-plugin@1.0.0", { source: "global" }], "global-only@1.0.0"], + }) + yield* fs.writeJson(path.join(local, "opencode.json"), { + plugin: [["shared-plugin@2.0.0", { source: "local" }], "local-only@1.0.0"], + }) + yield* fs.writeJson(path.join(local, "tui.json"), { + plugin: [["shared-plugin@2.0.0", { source: "local" }], "local-only@1.0.0"], + }) + + const server = yield* Config.Service.use((svc) => svc.get()) + const tui = yield* getTuiConfig(test.directory) const serverPlugins = (server.plugin ?? []).map((item) => ConfigPlugin.pluginSpecifier(item)) const tuiPlugins = (tui.plugin ?? []).map((item) => ConfigPlugin.pluginSpecifier(item)) @@ -120,186 +107,228 @@ test("keeps server and tui plugin merge semantics aligned", async () => { expect(serverOrigins.map((item) => ConfigPlugin.pluginSpecifier(item.spec))).toEqual(serverPlugins) expect(tuiOrigins.map((item) => ConfigPlugin.pluginSpecifier(item.spec))).toEqual(tuiPlugins) expect(serverOrigins.map((item) => item.scope)).toEqual(tuiOrigins.map((item) => item.scope)) - }, - }) -}) + }), + ), +) -test("loads tui config with the same precedence order as server config paths", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(Global.Path.config, "tui.json"), JSON.stringify({ theme: "global" }, null, 2)) - await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ theme: "project" }, null, 2)) - await fs.mkdir(path.join(dir, ".opencode"), { recursive: true }) - await Bun.write( - path.join(dir, ".opencode", "tui.json"), +it.instance("loads tui config with the same precedence order as server config paths", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(Global.Path.config, "tui.json"), { theme: "global" }) + yield* fs.writeJson(path.join(test.directory, "tui.json"), { theme: "project" }) + yield* fs.writeWithDirs( + path.join(test.directory, ".opencode", "tui.json"), JSON.stringify({ theme: "local", diff_style: "stacked" }, null, 2), ) - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBe("local") - expect(config.diff_style).toBe("stacked") -}) + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("local") + expect(config.diff_style).toBe("stacked") + }), + ), +) -test("migrates tui-specific keys from opencode.json when tui.json does not exist", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify( - { - theme: "migrated-theme", - tui: { scroll_speed: 5 }, - keybinds: { app_exit: "ctrl+q" }, +it.instance("resolves attention config defaults and overrides", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + + expect((yield* getTuiConfig(test.directory)).attention).toEqual({ + enabled: false, + notifications: true, + sound: true, + volume: 0.4, + sound_pack: "opencode.default", + sounds: {}, + }) + + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + attention: { + enabled: false, + notifications: false, + sound: false, + volume: 0.7, + sound_pack: "acme.soft", + sounds: { + default: path.join(test.directory, "default.mp3"), + question: pathToFileURL(path.join(test.directory, "question.mp3")).href, + error: "./error.mp3", + subagent_done: "./subagent-done.mp3", }, - null, - 2, - ), - ) - }, - }) + }, + }) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBe("migrated-theme") - expect(config.scroll_speed).toBe(5) - expect(config.keybinds.get("app.exit")?.[0]?.key).toBe("ctrl+q") - const text = await Filesystem.readText(path.join(tmp.path, "tui.json")) - expect(JSON.parse(text)).toMatchObject({ - theme: "migrated-theme", - scroll_speed: 5, - }) - const server = JSON.parse(await Filesystem.readText(path.join(tmp.path, "opencode.json"))) - expect(server.theme).toBeUndefined() - expect(server.keybinds).toBeUndefined() - expect(server.tui).toBeUndefined() - expect(await Filesystem.exists(path.join(tmp.path, "opencode.json.tui-migration.bak"))).toBe(true) - expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(true) -}) + expect((yield* getTuiConfig(test.directory)).attention).toEqual({ + enabled: false, + notifications: false, + sound: false, + volume: 0.7, + sound_pack: "acme.soft", + sounds: { + default: path.join(test.directory, "default.mp3"), + question: path.join(test.directory, "question.mp3"), + error: path.join(test.directory, "error.mp3"), + subagent_done: path.join(test.directory, "subagent-done.mp3"), + }, + }) + }), + ), +) -test("migrates project legacy tui keys even when global tui.json already exists", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(Global.Path.config, "tui.json"), JSON.stringify({ theme: "global" }, null, 2)) - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify( - { - theme: "project-migrated", - tui: { scroll_speed: 2 }, - }, - null, - 2, - ), - ) - }, - }) +it.instance("migrates tui-specific keys from opencode.json when tui.json does not exist", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + const source = path.join(test.directory, "opencode.json") + yield* fs.writeJson(source, { + theme: "migrated-theme", + tui: { scroll_speed: 5 }, + keybinds: { app_exit: "ctrl+q" }, + }) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBe("project-migrated") - expect(config.scroll_speed).toBe(2) - expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(true) + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("migrated-theme") + expect(config.scroll_speed).toBe(5) + expect(config.keybinds.get("app.exit")?.[0]?.key).toBe("ctrl+q") + expect(JSON.parse(yield* fs.readFileString(path.join(test.directory, "tui.json")))).toMatchObject({ + theme: "migrated-theme", + scroll_speed: 5, + }) + const server = JSON.parse(yield* fs.readFileString(source)) + expect(server.theme).toBeUndefined() + expect(server.keybinds).toBeUndefined() + expect(server.tui).toBeUndefined() + expect(yield* fs.existsSafe(path.join(test.directory, "opencode.json.tui-migration.bak"))).toBe(true) + expect(yield* fs.existsSafe(path.join(test.directory, "tui.json"))).toBe(true) + }), + ), +) - const server = JSON.parse(await Filesystem.readText(path.join(tmp.path, "opencode.json"))) - expect(server.theme).toBeUndefined() - expect(server.tui).toBeUndefined() -}) +it.instance("migrates project legacy tui keys even when global tui.json already exists", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(Global.Path.config, "tui.json"), { theme: "global" }) + yield* fs.writeJson(path.join(test.directory, "opencode.json"), { + theme: "project-migrated", + tui: { scroll_speed: 2 }, + }) -test("drops unknown legacy tui keys during migration", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify( - { - theme: "migrated-theme", - tui: { scroll_speed: 2, foo: 1 }, - }, - null, - 2, - ), - ) - }, - }) + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("project-migrated") + expect(config.scroll_speed).toBe(2) + expect(yield* fs.existsSafe(path.join(test.directory, "tui.json"))).toBe(true) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBe("migrated-theme") - expect(config.scroll_speed).toBe(2) + const server = JSON.parse(yield* fs.readFileString(path.join(test.directory, "opencode.json"))) + expect(server.theme).toBeUndefined() + expect(server.tui).toBeUndefined() + }), + ), +) - const text = await Filesystem.readText(path.join(tmp.path, "tui.json")) - const migrated = JSON.parse(text) - expect(migrated.scroll_speed).toBe(2) - expect(migrated.foo).toBeUndefined() -}) +it.instance("drops unknown legacy tui keys during migration", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "opencode.json"), { + theme: "migrated-theme", + tui: { scroll_speed: 2, foo: 1 }, + }) -test("skips migration when opencode.jsonc is syntactically invalid", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.jsonc"), + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("migrated-theme") + expect(config.scroll_speed).toBe(2) + + const migrated = JSON.parse(yield* fs.readFileString(path.join(test.directory, "tui.json"))) + expect(migrated.scroll_speed).toBe(2) + expect(migrated.foo).toBeUndefined() + }), + ), +) + +it.instance("skips migration when opencode.jsonc is syntactically invalid", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeFileString( + path.join(test.directory, "opencode.jsonc"), `{ "theme": "broken-theme", "tui": { "scroll_speed": 2 } "username": "still-broken" }`, ) - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBeUndefined() - expect(config.scroll_speed).toBeUndefined() - expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(false) - expect(await Filesystem.exists(path.join(tmp.path, "opencode.jsonc.tui-migration.bak"))).toBe(false) - const source = await Filesystem.readText(path.join(tmp.path, "opencode.jsonc")) - expect(source).toContain('"theme": "broken-theme"') - expect(source).toContain('"tui": { "scroll_speed": 2 }') -}) + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBeUndefined() + expect(config.scroll_speed).toBeUndefined() + expect(yield* fs.existsSafe(path.join(test.directory, "tui.json"))).toBe(false) + expect(yield* fs.existsSafe(path.join(test.directory, "opencode.jsonc.tui-migration.bak"))).toBe(false) + const source = yield* fs.readFileString(path.join(test.directory, "opencode.jsonc")) + expect(source).toContain('"theme": "broken-theme"') + expect(source).toContain('"tui": { "scroll_speed": 2 }') + }), + ), +) -test("skips migration when tui.json already exists", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ theme: "legacy" }, null, 2)) - await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ diff_style: "stacked" }, null, 2)) - }, - }) +it.instance("skips migration when tui.json already exists", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "opencode.json"), { theme: "legacy" }) + yield* fs.writeJson(path.join(test.directory, "tui.json"), { diff_style: "stacked" }) - const config = await getTuiConfig(tmp.path) - expect(config.diff_style).toBe("stacked") - expect(config.theme).toBeUndefined() + const config = yield* getTuiConfig(test.directory) + expect(config.diff_style).toBe("stacked") + expect(config.theme).toBeUndefined() - const server = JSON.parse(await Filesystem.readText(path.join(tmp.path, "opencode.json"))) - expect(server.theme).toBe("legacy") - expect(await Filesystem.exists(path.join(tmp.path, "opencode.json.tui-migration.bak"))).toBe(false) -}) + const server = JSON.parse(yield* fs.readFileString(path.join(test.directory, "opencode.json"))) + expect(server.theme).toBe("legacy") + expect(yield* fs.existsSafe(path.join(test.directory, "opencode.json.tui-migration.bak"))).toBe(false) + }), + ), +) -test("continues loading tui config when legacy source cannot be stripped", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ theme: "readonly-theme" }, null, 2)) - }, - }) +it.instance("continues loading tui config when legacy source cannot be stripped", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + const source = path.join(test.directory, "opencode.json") + yield* fs.writeJson(source, { theme: "readonly-theme" }) - const source = path.join(tmp.path, "opencode.json") - await fs.chmod(source, 0o444) + yield* Effect.acquireUseRelease( + fs.chmod(source, 0o444), + () => + Effect.gen(function* () { + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("readonly-theme") + expect(yield* fs.existsSafe(path.join(test.directory, "tui.json"))).toBe(true) - try { - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBe("readonly-theme") - expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(true) + const server = JSON.parse(yield* fs.readFileString(source)) + expect(server.theme).toBe("readonly-theme") + }), + () => fs.chmod(source, 0o644).pipe(Effect.ignore), + ) + }), + ), +) - const server = JSON.parse(await Filesystem.readText(source)) - expect(server.theme).toBe("readonly-theme") - } finally { - await fs.chmod(source, 0o644) - } -}) - -test("migration backup preserves JSONC comments", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.jsonc"), +it.instance("migration backup preserves JSONC comments", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeFileString( + path.join(test.directory, "opencode.jsonc"), `{ // top-level comment "theme": "jsonc-theme", @@ -309,498 +338,520 @@ test("migration backup preserves JSONC comments", async () => { } }`, ) - }, - }) - await getTuiConfig(tmp.path) - const backup = await Filesystem.readText(path.join(tmp.path, "opencode.jsonc.tui-migration.bak")) - expect(backup).toContain("// top-level comment") - expect(backup).toContain("// nested comment") - expect(backup).toContain('"theme": "jsonc-theme"') - expect(backup).toContain('"scroll_speed": 1.5') -}) + yield* getTuiConfig(test.directory) + const backup = yield* fs.readFileString(path.join(test.directory, "opencode.jsonc.tui-migration.bak")) + expect(backup).toContain("// top-level comment") + expect(backup).toContain("// nested comment") + expect(backup).toContain('"theme": "jsonc-theme"') + expect(backup).toContain('"scroll_speed": 1.5') + }), + ), +) -test("migrates legacy tui keys across multiple opencode.json levels", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - const nested = path.join(dir, "apps", "client") - await fs.mkdir(nested, { recursive: true }) - await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ theme: "root-theme" }, null, 2)) - await Bun.write(path.join(nested, "opencode.json"), JSON.stringify({ theme: "nested-theme" }, null, 2)) - }, - }) - const config = await getTuiConfig(path.join(tmp.path, "apps", "client")) - expect(config.theme).toBe("nested-theme") - expect(await Filesystem.exists(path.join(tmp.path, "tui.json"))).toBe(true) - expect(await Filesystem.exists(path.join(tmp.path, "apps", "client", "tui.json"))).toBe(true) -}) +it.instance("migrates legacy tui keys across multiple opencode.json levels", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + const nested = path.join(test.directory, "apps", "client") + yield* fs.makeDirectory(nested, { recursive: true }) + yield* fs.writeJson(path.join(test.directory, "opencode.json"), { theme: "root-theme" }) + yield* fs.writeJson(path.join(nested, "opencode.json"), { theme: "nested-theme" }) -test("flattens nested tui key inside tui.json", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - theme: "outer", - tui: { scroll_speed: 3, diff_style: "stacked" }, + const config = yield* getTuiConfig(nested) + expect(config.theme).toBe("nested-theme") + expect(yield* fs.existsSafe(path.join(test.directory, "tui.json"))).toBe(true) + expect(yield* fs.existsSafe(path.join(nested, "tui.json"))).toBe(true) + }), + ), +) + +it.instance("flattens nested tui key inside tui.json", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + theme: "outer", + tui: { scroll_speed: 3, diff_style: "stacked" }, + }) + + const config = yield* getTuiConfig(test.directory) + expect(config.scroll_speed).toBe(3) + expect(config.diff_style).toBe("stacked") + expect(config.theme).toBe("outer") + }), + ), +) + +it.instance("top-level keys in tui.json take precedence over nested tui key", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + diff_style: "auto", + tui: { diff_style: "stacked", scroll_speed: 2 }, + }) + + const config = yield* getTuiConfig(test.directory) + expect(config.diff_style).toBe("auto") + expect(config.scroll_speed).toBe(2) + }), + ), +) + +it.instance("project config takes precedence over OPENCODE_TUI_CONFIG (matches OPENCODE_CONFIG)", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + const custom = path.join(test.directory, "custom-tui.json") + yield* fs.writeJson(path.join(test.directory, "tui.json"), { theme: "project", diff_style: "auto" }) + yield* fs.writeJson(custom, { theme: "custom", diff_style: "stacked" }) + + yield* withEnv( + "OPENCODE_TUI_CONFIG", + custom, + Effect.gen(function* () { + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("project") + expect(config.diff_style).toBe("auto") }), ) - }, - }) + }), + ), +) - const config = await getTuiConfig(tmp.path) - expect(config.scroll_speed).toBe(3) - expect(config.diff_style).toBe("stacked") - // top-level keys take precedence over nested tui keys - expect(config.theme).toBe("outer") -}) +it.instance("merges keybind overrides across precedence layers", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(Global.Path.config, "tui.json"), { keybinds: { app_exit: "ctrl+q" } }) + yield* fs.writeJson(path.join(test.directory, "tui.json"), { keybinds: { theme_list: "ctrl+k" } }) -test("top-level keys in tui.json take precedence over nested tui key", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - diff_style: "auto", - tui: { diff_style: "stacked", scroll_speed: 2 }, - }), + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("app.exit")?.[0]?.key).toBe("ctrl+q") + expect(config.keybinds.get("theme.switch")?.[0]?.key).toBe("ctrl+k") + }), + ), +) + +it.instance("resolves keybind lookup from canonical keybinds", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + keybinds: { + leader: { key: { name: "g", ctrl: true } }, + command_list: "alt+p", + which_key_toggle: "alt+k", + editor_open: "ctrl+e", + "prompt.autocomplete.next": "ctrl+j", + "dialog.mcp.toggle": "ctrl+t", + model_favorite_toggle: "ctrl+f", + "dialog.plugins.install": "shift+i", + }, + leader_timeout: 1234, + }) + + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("leader")?.[0]?.key).toEqual({ name: "g", ctrl: true }) + expect(config.leader_timeout).toBe(1234) + expect(config.keybinds.get("command.palette.show")?.[0]?.key).toBe("alt+p") + expect(config.keybinds.get("session.new")?.[0]?.key).toBe("n") + expect(config.keybinds.get("which-key.toggle")?.[0]?.key).toBe("alt+k") + expect(config.keybinds.get("which-key.layout.toggle")?.[0]?.key).toBe("ctrl+alt+shift+k") + expect(config.keybinds.get("which-key.pending.toggle")?.[0]?.key).toBe("ctrl+alt+shift+p") + expect(config.keybinds.get("which-key.group.next")?.[0]?.key).toBe("ctrl+alt+right,ctrl+alt+]") + expect((config.keybinds.get("which-key.toggle")?.[0] as { desc?: unknown } | undefined)?.desc).toBe( + "Toggle which-key panel", ) - }, - }) + expect(config.keybinds.get("prompt.editor")?.[0]?.key).toBe("ctrl+e") + expect(config.keybinds.get("prompt.autocomplete.next")?.[0]?.key).toBe("ctrl+j") + expect(config.keybinds.get("dialog.mcp.toggle")?.[0]?.key).toBe("ctrl+t") + expect(config.keybinds.get("model.dialog.favorite")?.[0]?.key).toBe("ctrl+f") + expect(config.keybinds.get("dialog.plugins.install")?.[0]?.key).toBe("shift+i") + expect( + config.keybinds.gather("plugins.dialog", ["dialog.plugins.install"]).map((binding) => binding.cmd), + ).toEqual(["dialog.plugins.install"]) + }), + ), +) - const config = await getTuiConfig(tmp.path) - expect(config.diff_style).toBe("auto") - expect(config.scroll_speed).toBe(2) -}) +it.instance("keybinds accept OpenTUI binding specs", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + keybinds: { + command_list: [{ key: "alt+p", preventDefault: false }], + editor_open: { key: { name: "e", ctrl: true }, group: "Explicit" }, + "prompt.autocomplete.next": false, + plugin_manager: "ctrl+shift+p", + }, + }) -test("project config takes precedence over OPENCODE_TUI_CONFIG (matches OPENCODE_CONFIG)", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ theme: "project", diff_style: "auto" })) - const custom = path.join(dir, "custom-tui.json") - await Bun.write(custom, JSON.stringify({ theme: "custom", diff_style: "stacked" })) - process.env.OPENCODE_TUI_CONFIG = custom - }, - }) + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("command.palette.show")).toEqual([ + { key: "alt+p", cmd: "command.palette.show", preventDefault: false, desc: "List available commands" }, + ]) + expect(config.keybinds.get("prompt.editor")?.[0]).toMatchObject({ + key: { name: "e", ctrl: true }, + cmd: "prompt.editor", + group: "Explicit", + }) + expect(config.keybinds.get("prompt.autocomplete.next")).toEqual([]) + expect(config.keybinds.get("plugins.list")?.[0]?.key).toBe("ctrl+shift+p") + }), + ), +) - const config = await getTuiConfig(tmp.path) - // project tui.json overrides the custom path, same as server config precedence - expect(config.theme).toBe("project") - // project also set diff_style, so that wins - expect(config.diff_style).toBe("auto") -}) +winIt("defaults Ctrl+Z to input undo on Windows", () => + withCleanState( + Effect.gen(function* () { + const test = yield* TestInstance + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("terminal.suspend")).toEqual([]) + expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+z,ctrl+-,super+z") + }), + ), +) -test("merges keybind overrides across precedence layers", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(Global.Path.config, "tui.json"), JSON.stringify({ keybinds: { app_exit: "ctrl+q" } })) - await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ keybinds: { theme_list: "ctrl+k" } })) - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("app.exit")?.[0]?.key).toBe("ctrl+q") - expect(config.keybinds.get("theme.switch")?.[0]?.key).toBe("ctrl+k") -}) +winIt("keeps explicit input undo overrides on Windows", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { keybinds: { input_undo: "ctrl+y" } }) -test("resolves keybind lookup from canonical keybinds", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("terminal.suspend")).toEqual([]) + expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+y") + }), + ), +) + +winIt("ignores terminal suspend bindings on Windows", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { keybinds: { terminal_suspend: "alt+z" } }) + + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("terminal.suspend")).toEqual([]) + expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+z,ctrl+-,super+z") + }), + ), +) + +it.instance("applies Windows keybind defaults", () => + withCleanState( + withPlatform( + "win32", + Effect.gen(function* () { + const test = yield* TestInstance + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("terminal.suspend")).toEqual([]) + expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+z,ctrl+-,super+z") + }), + ), + ), +) + +it.instance("ignores explicit keybind terminal suspend binding on Windows", () => + withCleanState( + withPlatform( + "win32", + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { keybinds: { - leader: { key: { name: "g", ctrl: true } }, - command_list: "alt+p", - which_key_toggle: "alt+k", - editor_open: "ctrl+e", - "prompt.autocomplete.next": "ctrl+j", - "dialog.mcp.toggle": "ctrl+t", - model_favorite_toggle: "ctrl+f", - "dialog.plugins.install": "shift+i", + terminal_suspend: "alt+z", }, - leader_timeout: 1234, - }), - ) - }, - }) + }) - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("leader")?.[0]?.key).toEqual({ name: "g", ctrl: true }) - expect(config.leader_timeout).toBe(1234) - expect(config.keybinds.get("command.palette.show")?.[0]?.key).toBe("alt+p") - expect(config.keybinds.get("session.new")?.[0]?.key).toBe("n") - expect(config.keybinds.get("which-key.toggle")?.[0]?.key).toBe("alt+k") - expect(config.keybinds.get("which-key.layout.toggle")?.[0]?.key).toBe("ctrl+alt+shift+k") - expect(config.keybinds.get("which-key.pending.toggle")?.[0]?.key).toBe("ctrl+alt+shift+p") - expect(config.keybinds.get("which-key.group.next")?.[0]?.key).toBe("ctrl+alt+right,ctrl+alt+]") - expect((config.keybinds.get("which-key.toggle")?.[0] as { desc?: unknown } | undefined)?.desc).toBe( - "Toggle which-key panel", - ) - expect(config.keybinds.get("prompt.editor")?.[0]?.key).toBe("ctrl+e") - expect(config.keybinds.get("prompt.autocomplete.next")?.[0]?.key).toBe("ctrl+j") - expect(config.keybinds.get("dialog.mcp.toggle")?.[0]?.key).toBe("ctrl+t") - expect(config.keybinds.get("model.dialog.favorite")?.[0]?.key).toBe("ctrl+f") - expect(config.keybinds.get("dialog.plugins.install")?.[0]?.key).toBe("shift+i") - expect(config.keybinds.gather("plugins.dialog", ["dialog.plugins.install"]).map((binding) => binding.cmd)).toEqual([ - "dialog.plugins.install", - ]) -}) + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("terminal.suspend")).toEqual([]) + }), + ), + ), +) -test("keybinds accept OpenTUI binding specs", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ +it.instance("keeps explicit configured keybind input undo on Windows", () => + withCleanState( + withPlatform( + "win32", + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { keybinds: { - command_list: [{ key: "alt+p", preventDefault: false }], - editor_open: { key: { name: "e", ctrl: true }, group: "Explicit" }, - "prompt.autocomplete.next": false, - plugin_manager: "ctrl+shift+p", + input_undo: "ctrl+y", }, + }) + + const config = yield* getTuiConfig(test.directory) + expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+y") + }), + ), + ), +) + +it.instance("OPENCODE_TUI_CONFIG provides settings when no project config exists", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + const custom = path.join(test.directory, "custom-tui.json") + yield* fs.writeJson(custom, { theme: "from-env", diff_style: "stacked" }) + + yield* withEnv( + "OPENCODE_TUI_CONFIG", + custom, + Effect.gen(function* () { + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("from-env") + expect(config.diff_style).toBe("stacked") }), ) - }, - }) + }), + ), +) - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("command.palette.show")).toEqual([ - { key: "alt+p", cmd: "command.palette.show", preventDefault: false, desc: "List available commands" }, - ]) - expect(config.keybinds.get("prompt.editor")?.[0]).toMatchObject({ - key: { name: "e", ctrl: true }, - cmd: "prompt.editor", - group: "Explicit", - }) - expect(config.keybinds.get("prompt.autocomplete.next")).toEqual([]) - expect(config.keybinds.get("plugins.list")?.[0]?.key).toBe("ctrl+shift+p") -}) +it.instance("does not derive tui path from OPENCODE_CONFIG", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + const customDir = path.join(test.directory, "custom") + yield* fs.makeDirectory(customDir, { recursive: true }) + yield* fs.writeJson(path.join(customDir, "opencode.json"), { model: "test/model" }) + yield* fs.writeJson(path.join(customDir, "tui.json"), { theme: "should-not-load" }) -wintest("defaults Ctrl+Z to input undo on Windows", async () => { - await using tmp = await tmpdir() - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("terminal.suspend")).toEqual([]) - expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+z,ctrl+-,super+z") -}) + yield* withEnv( + "OPENCODE_CONFIG", + path.join(customDir, "opencode.json"), + Effect.gen(function* () { + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBeUndefined() + }), + ) + }), + ), +) -wintest("keeps explicit input undo overrides on Windows", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ keybinds: { input_undo: "ctrl+y" } })) - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("terminal.suspend")).toEqual([]) - expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+y") -}) +it.instance("applies env and file substitutions in tui.json", () => + withCleanState( + withEnv( + "TUI_THEME_TEST", + "env-theme", + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeFileString(path.join(test.directory, "keybind.txt"), "ctrl+q") + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + theme: "{env:TUI_THEME_TEST}", + keybinds: { app_exit: "{file:keybind.txt}" }, + }) -wintest("ignores terminal suspend bindings on Windows", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "tui.json"), JSON.stringify({ keybinds: { terminal_suspend: "alt+z" } })) - }, - }) + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("env-theme") + expect(config.keybinds.get("app.exit")?.[0]?.key).toBe("ctrl+q") + }), + ), + ), +) - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("terminal.suspend")).toEqual([]) - expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+z,ctrl+-,super+z") -}) - -test("applies Windows keybind defaults", async () => { - await withPlatform("win32", async () => { - await using tmp = await tmpdir() - - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("terminal.suspend")).toEqual([]) - expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+z,ctrl+-,super+z") - }) -}) - -test("ignores explicit keybind terminal suspend binding on Windows", async () => { - await withPlatform("win32", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - keybinds: { - terminal_suspend: "alt+z", - }, - }), - ) - }, - }) - - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("terminal.suspend")).toEqual([]) - }) -}) - -test("keeps explicit configured keybind input undo on Windows", async () => { - await withPlatform("win32", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - keybinds: { - input_undo: "ctrl+y", - }, - }), - ) - }, - }) - - const config = await getTuiConfig(tmp.path) - expect(config.keybinds.get("input.undo")?.[0]?.key).toBe("ctrl+y") - }) -}) - -test("OPENCODE_TUI_CONFIG provides settings when no project config exists", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - const custom = path.join(dir, "custom-tui.json") - await Bun.write(custom, JSON.stringify({ theme: "from-env", diff_style: "stacked" })) - process.env.OPENCODE_TUI_CONFIG = custom - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBe("from-env") - expect(config.diff_style).toBe("stacked") -}) - -test("does not derive tui path from OPENCODE_CONFIG", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - const customDir = path.join(dir, "custom") - await fs.mkdir(customDir, { recursive: true }) - await Bun.write(path.join(customDir, "opencode.json"), JSON.stringify({ model: "test/model" })) - await Bun.write(path.join(customDir, "tui.json"), JSON.stringify({ theme: "should-not-load" })) - process.env.OPENCODE_CONFIG = path.join(customDir, "opencode.json") - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBeUndefined() -}) - -test("applies env and file substitutions in tui.json", async () => { - const original = process.env.TUI_THEME_TEST - process.env.TUI_THEME_TEST = "env-theme" - try { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "keybind.txt"), "ctrl+q") - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - theme: "{env:TUI_THEME_TEST}", - keybinds: { app_exit: "{file:keybind.txt}" }, - }), - ) - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBe("env-theme") - expect(config.keybinds.get("app.exit")?.[0]?.key).toBe("ctrl+q") - } finally { - if (original === undefined) delete process.env.TUI_THEME_TEST - else process.env.TUI_THEME_TEST = original - } -}) - -test("applies file substitutions when first identical token is in a commented line", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "theme.txt"), "resolved-theme") - await Bun.write( - path.join(dir, "tui.jsonc"), +it.instance("applies file substitutions when first identical token is in a commented line", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeFileString(path.join(test.directory, "theme.txt"), "resolved-theme") + yield* fs.writeFileString( + path.join(test.directory, "tui.jsonc"), `{ // "theme": "{file:theme.txt}", "theme": "{file:theme.txt}" }`, ) - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.theme).toBe("resolved-theme") -}) -test("loads .opencode/tui.json", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await fs.mkdir(path.join(dir, ".opencode"), { recursive: true }) - await Bun.write(path.join(dir, ".opencode", "tui.json"), JSON.stringify({ diff_style: "stacked" }, null, 2)) - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.diff_style).toBe("stacked") -}) + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("resolved-theme") + }), + ), +) -test("supports tuple plugin specs with options in tui.json", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - plugin: [["acme-plugin@1.2.3", { enabled: true, label: "demo" }]], - }), +it.instance("loads .opencode/tui.json", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeWithDirs( + path.join(test.directory, ".opencode", "tui.json"), + JSON.stringify({ diff_style: "stacked" }, null, 2), ) - }, - }) - const config = await getTuiConfig(tmp.path) - expect(config.plugin).toEqual([["acme-plugin@1.2.3", { enabled: true, label: "demo" }]]) - expect(config.plugin_origins).toEqual([ - { - spec: ["acme-plugin@1.2.3", { enabled: true, label: "demo" }], - scope: "local", - source: path.join(tmp.path, "tui.json"), - }, - ]) -}) + const config = yield* getTuiConfig(test.directory) + expect(config.diff_style).toBe("stacked") + }), + ), +) -test("deduplicates tuple plugin specs by name with higher precedence winning", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(Global.Path.config, "tui.json"), - JSON.stringify({ - plugin: [["acme-plugin@1.0.0", { source: "global" }]], - }), - ) - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - plugin: [ - ["acme-plugin@2.0.0", { source: "project" }], - ["second-plugin@3.0.0", { source: "project" }], - ], - }), - ) - }, - }) +it.instance("supports tuple plugin specs with options in tui.json", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + plugin: [["acme-plugin@1.2.3", { enabled: true, label: "demo" }]], + }) - const config = await getTuiConfig(tmp.path) - expect(config.plugin).toEqual([ - ["acme-plugin@2.0.0", { source: "project" }], - ["second-plugin@3.0.0", { source: "project" }], - ]) - expect(config.plugin_origins).toEqual([ - { - spec: ["acme-plugin@2.0.0", { source: "project" }], - scope: "local", - source: path.join(tmp.path, "tui.json"), - }, - { - spec: ["second-plugin@3.0.0", { source: "project" }], - scope: "local", - source: path.join(tmp.path, "tui.json"), - }, - ]) -}) + const config = yield* getTuiConfig(test.directory) + expect(config.plugin).toEqual([["acme-plugin@1.2.3", { enabled: true, label: "demo" }]]) + expect(config.plugin_origins).toEqual([ + { + spec: ["acme-plugin@1.2.3", { enabled: true, label: "demo" }], + scope: "local", + source: path.join(test.directory, "tui.json"), + }, + ]) + }), + ), +) -test("tracks global and local plugin metadata in merged tui config", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(Global.Path.config, "tui.json"), - JSON.stringify({ - plugin: ["global-plugin@1.0.0"], - }), - ) - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - plugin: ["local-plugin@2.0.0"], - }), - ) - }, - }) +it.instance("deduplicates tuple plugin specs by name with higher precedence winning", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(Global.Path.config, "tui.json"), { + plugin: [["acme-plugin@1.0.0", { source: "global" }]], + }) + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + plugin: [ + ["acme-plugin@2.0.0", { source: "project" }], + ["second-plugin@3.0.0", { source: "project" }], + ], + }) - const config = await getTuiConfig(tmp.path) - expect(config.plugin).toEqual(["global-plugin@1.0.0", "local-plugin@2.0.0"]) - expect(config.plugin_origins).toEqual([ - { - spec: "global-plugin@1.0.0", - scope: "global", - source: path.join(Global.Path.config, "tui.json"), - }, - { - spec: "local-plugin@2.0.0", - scope: "local", - source: path.join(tmp.path, "tui.json"), - }, - ]) -}) + const config = yield* getTuiConfig(test.directory) + expect(config.plugin).toEqual([ + ["acme-plugin@2.0.0", { source: "project" }], + ["second-plugin@3.0.0", { source: "project" }], + ]) + expect(config.plugin_origins).toEqual([ + { + spec: ["acme-plugin@2.0.0", { source: "project" }], + scope: "local", + source: path.join(test.directory, "tui.json"), + }, + { + spec: ["second-plugin@3.0.0", { source: "project" }], + scope: "local", + source: path.join(test.directory, "tui.json"), + }, + ]) + }), + ), +) -test("merges plugin_enabled flags across config layers", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(Global.Path.config, "tui.json"), - JSON.stringify({ - plugin_enabled: { - "internal:sidebar-context": false, - "demo.plugin": true, - }, - }), - ) - await Bun.write( - path.join(dir, "tui.json"), - JSON.stringify({ - plugin_enabled: { - "demo.plugin": false, - "local.plugin": true, - }, - }), - ) - }, - }) +it.instance("tracks global and local plugin metadata in merged tui config", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(Global.Path.config, "tui.json"), { plugin: ["global-plugin@1.0.0"] }) + yield* fs.writeJson(path.join(test.directory, "tui.json"), { plugin: ["local-plugin@2.0.0"] }) - const config = await getTuiConfig(tmp.path) - expect(config.plugin_enabled).toEqual({ - "internal:sidebar-context": false, - "demo.plugin": false, - "local.plugin": true, - }) -}) + const config = yield* getTuiConfig(test.directory) + expect(config.plugin).toEqual(["global-plugin@1.0.0", "local-plugin@2.0.0"]) + expect(config.plugin_origins).toEqual([ + { + spec: "global-plugin@1.0.0", + scope: "global", + source: path.join(Global.Path.config, "tui.json"), + }, + { + spec: "local-plugin@2.0.0", + scope: "local", + source: path.join(test.directory, "tui.json"), + }, + ]) + }), + ), +) -test("silently skips malformed tui.json — load failures degrade to {}", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "tui.json"), '{ "theme": "broken",') - await Bun.write(path.join(dir, ".opencode", "tui.json"), JSON.stringify({ theme: "fallback" })) - }, - }) +it.instance("merges plugin_enabled flags across config layers", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeJson(path.join(Global.Path.config, "tui.json"), { + plugin_enabled: { + "internal:sidebar-context": false, + "demo.plugin": true, + }, + }) + yield* fs.writeJson(path.join(test.directory, "tui.json"), { + plugin_enabled: { + "demo.plugin": false, + "local.plugin": true, + }, + }) - const config = await getTuiConfig(tmp.path) - // Project tui.json is malformed → silently skipped (logs a warning) - // .opencode/tui.json (lower precedence in this path) still loads - expect(config.theme).toBe("fallback") -}) + const config = yield* getTuiConfig(test.directory) + expect(config.plugin_enabled).toEqual({ + "internal:sidebar-context": false, + "demo.plugin": false, + "local.plugin": true, + }) + }), + ), +) -test("silently skips non-ENOENT read failures (e.g. tui.json is a directory) — fallback layer still loads", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - // tui.json exists as a DIRECTORY rather than a file → readFileString fails - // with EISDIR (PlatformError reason ≠ NotFound). The fix in this PR routes - // that through catchCause → log + skip, so a fallback layer should still load. - await fs.mkdir(path.join(dir, "tui.json"), { recursive: true }) - await Bun.write(path.join(dir, ".opencode", "tui.json"), JSON.stringify({ theme: "fallback" })) - }, - }) +it.instance("silently skips malformed tui.json - load failures degrade to {}", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.writeFileString(path.join(test.directory, "tui.json"), '{ "theme": "broken",') + yield* fs.writeWithDirs(path.join(test.directory, ".opencode", "tui.json"), JSON.stringify({ theme: "fallback" })) - const config = await getTuiConfig(tmp.path) - // Did NOT crash; .opencode/tui.json (lower precedence) still loads. - expect(config.theme).toBe("fallback") -}) + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("fallback") + }), + ), +) -test("missing tui.json — silently treated as empty (ENOENT path)", async () => { - await using tmp = await tmpdir({}) +it.instance("silently skips non-ENOENT read failures (e.g. tui.json is a directory) - fallback layer still loads", () => + withCleanState( + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const test = yield* TestInstance + yield* fs.makeDirectory(path.join(test.directory, "tui.json"), { recursive: true }) + yield* fs.writeWithDirs(path.join(test.directory, ".opencode", "tui.json"), JSON.stringify({ theme: "fallback" })) - // No tui.json anywhere. Should not throw. - const config = await getTuiConfig(tmp.path) - expect(config).toBeDefined() - // No theme set anywhere. - expect(config.theme).toBeUndefined() -}) + const config = yield* getTuiConfig(test.directory) + expect(config.theme).toBe("fallback") + }), + ), +) + +it.instance("missing tui.json - silently treated as empty (ENOENT path)", () => + withCleanState( + Effect.gen(function* () { + const test = yield* TestInstance + const config = yield* getTuiConfig(test.directory) + expect(config).toBeDefined() + expect(config.theme).toBeUndefined() + }), + ), +) diff --git a/packages/opencode/test/control-plane/workspace.test.ts b/packages/opencode/test/control-plane/workspace.test.ts index 3c4837e318..01304e8050 100644 --- a/packages/opencode/test/control-plane/workspace.test.ts +++ b/packages/opencode/test/control-plane/workspace.test.ts @@ -6,7 +6,7 @@ import path from "node:path" import { setTimeout as delay } from "node:timers/promises" import { NodeHttpServer } from "@effect/platform-node" import { Effect, Layer, Schema } from "effect" -import { HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" +import { FetchHttpClient, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" import { eq } from "drizzle-orm" import * as Log from "@opencode-ai/core/util/log" import { Flag } from "@opencode-ai/core/flag/flag" @@ -16,13 +16,14 @@ import { ProjectID } from "@/project/schema" import { ProjectTable } from "@/project/project.sql" import { Instance } from "@/project/instance" import { WithInstance } from "../../src/project/with-instance" +import { InstanceRef } from "@/effect/instance-ref" import { Session as SessionNs } from "@/session/session" import { SessionID } from "@/session/schema" import { SessionTable } from "@/session/session.sql" import { SyncEvent } from "@/sync" import { EventSequenceTable } from "@/sync/event.sql" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, provideTmpdirInstance, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, provideTmpdirInstance, TestInstance, tmpdir } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { registerAdapter } from "../../src/control-plane/adapters" import { WorkspaceID } from "../../src/control-plane/schema" @@ -32,24 +33,43 @@ import * as Workspace from "../../src/control-plane/workspace" import { AppRuntime } from "@/effect/app-runtime" import { InstanceStore } from "@/project/instance-store" import { InstanceBootstrap } from "@/project/bootstrap" +import { Auth } from "@/auth" +import { SessionPrompt } from "@/session/prompt" +import { Project } from "@/project/project" +import { Vcs } from "@/project/vcs" +import { RuntimeFlags } from "@/effect/runtime-flags" void Log.init({ print: false }) -const testServerLayer = Layer.mergeAll( - NodeHttpServer.layer(Http.createServer, { host: "127.0.0.1", port: 0 }), - Workspace.defaultLayer.pipe(Layer.provide(InstanceStore.defaultLayer), Layer.provide(InstanceBootstrap.defaultLayer)), - SessionNs.defaultLayer, -) -const it = testEffect(testServerLayer) - const originalWorkspacesFlag = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES const originalEnv = { OPENCODE_AUTH_CONTENT: process.env.OPENCODE_AUTH_CONTENT, + OPENCODE_EXPERIMENTAL_WORKSPACES: process.env.OPENCODE_EXPERIMENTAL_WORKSPACES, OTEL_EXPORTER_OTLP_HEADERS: process.env.OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_ENDPOINT: process.env.OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_RESOURCE_ATTRIBUTES: process.env.OTEL_RESOURCE_ATTRIBUTES, } +const workspaceLayer = (experimentalWorkspaces: boolean) => + Workspace.layer.pipe( + Layer.provide(Auth.defaultLayer), + Layer.provide(SessionNs.defaultLayer), + Layer.provide(SyncEvent.defaultLayer), + Layer.provide(SessionPrompt.defaultLayer), + Layer.provide(Project.defaultLayer), + Layer.provide(Vcs.defaultLayer), + Layer.provide(FetchHttpClient.layer), + Layer.provide(RuntimeFlags.layer({ experimentalWorkspaces })), + Layer.provide(InstanceStore.defaultLayer.pipe(Layer.provide(InstanceBootstrap.defaultLayer))), + ) + +const testServerLayer = Layer.mergeAll( + NodeHttpServer.layer(Http.createServer, { host: "127.0.0.1", port: 0 }), + workspaceLayer(true), + SessionNs.defaultLayer, +) +const it = testEffect(testServerLayer) + type RecordedCreate = { info: WorkspaceInfo env: Record @@ -93,6 +113,7 @@ beforeEach(() => { Database.close() Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true restoreEnv() + process.env.OPENCODE_EXPERIMENTAL_WORKSPACES = "true" }) afterEach(async () => { @@ -105,7 +126,7 @@ afterEach(async () => { async function withInstance(fn: (dir: string) => T | Promise) { await using tmp = await tmpdir({ git: true }) - return WithInstance.provide({ + return await WithInstance.provide({ directory: tmp.path, fn: () => fn(tmp.path), }) @@ -140,6 +161,12 @@ const isWorkspaceSyncing = (id: WorkspaceID) => const startWorkspaceSyncing = (projectID: ProjectID) => { void runWorkspace(Workspace.Service.use((workspace) => workspace.startWorkspaceSyncing(projectID))) } +const startWorkspaceSyncingWithFlag = (projectID: ProjectID, experimentalWorkspaces: boolean) => + Effect.runPromise( + Workspace.Service.use((workspace) => workspace.startWorkspaceSyncing(projectID)).pipe( + Effect.provide(workspaceLayer(experimentalWorkspaces)), + ), + ) const waitForWorkspaceSync = (workspaceID: WorkspaceID, state: Record, signal?: AbortSignal) => runWorkspace(Workspace.Service.use((workspace) => workspace.waitForSync(workspaceID, state, signal))) @@ -979,7 +1006,6 @@ describe("workspace CRUD", () => { describe("workspace sync state", () => { test("startWorkspaceSyncing is disabled by the experimental workspace flag", async () => { await withInstance(async (dir) => { - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = false const type = unique("flag-disabled") const info = workspaceInfo(Instance.project.id, type) const session = await AppRuntime.runPromise(SessionNs.Service.use((svc) => svc.create({}))) @@ -987,38 +1013,50 @@ describe("workspace sync state", () => { insertWorkspace(info) registerAdapter(Instance.project.id, type, localAdapter(path.join(dir, "flag-disabled")).adapter) - startWorkspaceSyncing(Instance.project.id) + await startWorkspaceSyncingWithFlag(Instance.project.id, false) await delay(25) expect((await workspaceStatus()).find((item) => item.workspaceID === info.id)?.status).toBeUndefined() }) }) - test("startWorkspaceSyncing starts all workspaces", async () => { - await withInstance(async (dir) => { - const firstType = unique("first") - const secondType = unique("second") - const first = workspaceInfo(Instance.project.id, firstType) - const second = workspaceInfo(Instance.project.id, secondType) - await fs.mkdir(path.join(dir, "first"), { recursive: true }) - await fs.mkdir(path.join(dir, "second"), { recursive: true }) - insertWorkspace(first) - insertWorkspace(second) - registerAdapter(Instance.project.id, firstType, localAdapter(path.join(dir, "first")).adapter) - registerAdapter(Instance.project.id, secondType, localAdapter(path.join(dir, "second")).adapter) + it.instance( + "startWorkspaceSyncing starts all workspaces", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const instance = yield* InstanceRef + if (!instance) return yield* Effect.die(new Error("missing test instance")) + const workspace = yield* Workspace.Service + const projectID = instance.project.id + const firstType = unique("first") + const secondType = unique("second") + const first = workspaceInfo(projectID, firstType) + const second = workspaceInfo(projectID, secondType) + yield* Effect.promise(() => fs.mkdir(path.join(dir, "first"), { recursive: true })) + yield* Effect.promise(() => fs.mkdir(path.join(dir, "second"), { recursive: true })) + yield* Effect.sync(() => { + insertWorkspace(first) + insertWorkspace(second) + registerAdapter(projectID, firstType, localAdapter(path.join(dir, "first")).adapter) + registerAdapter(projectID, secondType, localAdapter(path.join(dir, "second")).adapter) + }) + yield* Effect.addFinalizer(() => + Effect.all([workspace.remove(first.id), workspace.remove(second.id)], { discard: true }).pipe(Effect.ignore), + ) - startWorkspaceSyncing(Instance.project.id) + yield* workspace.startWorkspaceSyncing(projectID) - await eventually(() => - workspaceStatus().then((status) => { - expect(status.find((item) => item.workspaceID === first.id)?.status).toBe("connected") - expect(status.find((item) => item.workspaceID === second.id)?.status).toBe("connected") - }), - ) - await removeWorkspace(first.id) - await removeWorkspace(second.id) - }) - }) + yield* eventuallyEffect( + Effect.gen(function* () { + const status = yield* workspace.status() + expect(status.find((item) => item.workspaceID === first.id)?.status).toBe("connected") + expect(status.find((item) => item.workspaceID === second.id)?.status).toBe("connected") + }), + ) + }), + { git: true }, + ) test("local start reports error when the target directory is missing", async () => { await withInstance(async (dir) => { diff --git a/packages/opencode/test/effect/app-runtime-logger.test.ts b/packages/opencode/test/effect/app-runtime-logger.test.ts index fe9516ef99..e4ce6511dc 100644 --- a/packages/opencode/test/effect/app-runtime-logger.test.ts +++ b/packages/opencode/test/effect/app-runtime-logger.test.ts @@ -1,12 +1,13 @@ import { expect } from "bun:test" -import { Context, Effect, Layer, Logger } from "effect" +import { Context, Deferred, Effect, Fiber, Layer, Logger } from "effect" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" -import { AppRuntime } from "../../src/effect/app-runtime" +import { AppLayer } from "../../src/effect/app-runtime" import { EffectBridge } from "@/effect/bridge" import { InstanceRef } from "../../src/effect/instance-ref" import * as EffectLogger from "@opencode-ai/core/effect/logger" -import { makeRuntime } from "../../src/effect/run-service" -import { provideInstance, tmpdirScoped } from "../fixture/fixture" +import * as Observability from "@opencode-ai/core/effect/observability" +import { attach } from "../../src/effect/run-service" +import { TestInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" const it = testEffect(CrossSpawnSpawner.defaultLayer) @@ -35,17 +36,8 @@ it.live("makeRuntime installs EffectLogger through Observability.layer", () => }), ) - const current = yield* Effect.promise(() => makeRuntime(Dummy, layer).runPromise((svc) => svc.current())) - - expect(current.effectLogger).toBe(true) - expect(current.defaultLogger).toBe(false) - }), -) - -it.live("AppRuntime also installs EffectLogger through Observability.layer", () => - Effect.gen(function* () { - const current = yield* Effect.promise(() => - AppRuntime.runPromise(Effect.map(Effect.service(Logger.CurrentLoggers), check)), + const current = yield* Dummy.use((svc) => svc.current()).pipe( + Effect.provide(Layer.provideMerge(layer, Observability.layer)), ) expect(current.effectLogger).toBe(true) @@ -53,46 +45,61 @@ it.live("AppRuntime also installs EffectLogger through Observability.layer", () }), ) -it.live("AppRuntime attaches InstanceRef from ALS", () => +it.live("AppLayer also installs EffectLogger through Observability.layer", () => Effect.gen(function* () { - const dir = yield* tmpdirScoped({ git: true }) - const current = yield* Effect.promise(() => - AppRuntime.runPromise( + const current = yield* Effect.map(Effect.service(Logger.CurrentLoggers), check).pipe(Effect.provide(AppLayer)) + + expect(current.effectLogger).toBe(true) + expect(current.defaultLogger).toBe(false) + }), +) + +it.instance( + "attach preserves InstanceRef from the current fiber context", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const current = yield* attach( Effect.gen(function* () { return (yield* InstanceRef)?.directory }), - ), - ).pipe(provideInstance(dir)) + ) - expect(current).toBe(dir) - }), + expect(current).toBe(test.directory) + }), + { git: true }, ) -it.live("EffectBridge preserves logger and instance context across async boundaries", () => - Effect.gen(function* () { - const dir = yield* tmpdirScoped({ git: true }) - const result = yield* Effect.promise(() => - AppRuntime.runPromise( - Effect.gen(function* () { - const bridge = yield* EffectBridge.make() - return yield* Effect.promise(() => - Promise.resolve().then(() => - bridge.promise( - Effect.gen(function* () { - return { - directory: (yield* InstanceRef)?.directory, - ...check(yield* Effect.service(Logger.CurrentLoggers)), - } - }), - ), +it.instance( + "EffectBridge preserves logger and instance context across async boundaries", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const bridge = yield* EffectBridge.make() + const started = yield* Deferred.make() + + const fiber = yield* Effect.gen(function* () { + yield* Deferred.succeed(started, undefined) + return yield* Effect.promise(() => + Promise.resolve().then(() => + bridge.promise( + Effect.gen(function* () { + return { + directory: (yield* InstanceRef)?.directory, + ...check(yield* Effect.service(Logger.CurrentLoggers)), + } + }), ), - ) - }), - ), - ).pipe(provideInstance(dir)) + ), + ) + }).pipe(Effect.forkScoped) - expect(result.directory).toBe(dir) - expect(result.effectLogger).toBe(true) - expect(result.defaultLogger).toBe(false) - }), + yield* Deferred.await(started) + const result = yield* Fiber.join(fiber) + + expect(result.directory).toBe(test.directory) + expect(result.effectLogger).toBe(true) + expect(result.defaultLogger).toBe(false) + }).pipe(Effect.provide(Observability.layer)), + { git: true }, ) diff --git a/packages/opencode/test/effect/runner.test.ts b/packages/opencode/test/effect/runner.test.ts index c37cb276b6..3030ca64e0 100644 --- a/packages/opencode/test/effect/runner.test.ts +++ b/packages/opencode/test/effect/runner.test.ts @@ -3,6 +3,11 @@ import { Deferred, Effect, Exit, Fiber, Latch, Ref, Scope } from "effect" import { Runner } from "@/effect/runner" import { it } from "../lib/effect" +const waitForState = (runner: Runner.Runner, tag: Runner.State["_tag"]) => + Effect.gen(function* () { + while (runner.state._tag !== tag) yield* Effect.yieldNow + }).pipe(Effect.timeout("1 second")) + describe("Runner", () => { // --- ensureRunning semantics --- @@ -152,7 +157,7 @@ describe("Runner", () => { const s = yield* Scope.Scope const runner = Runner.make(s, { onInterrupt: Effect.succeed("fallback") }) const fiber = yield* runner.ensureRunning(Effect.never.pipe(Effect.as("never"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Running") yield* runner.cancel @@ -169,9 +174,9 @@ describe("Runner", () => { const runner = Runner.make(s, { onInterrupt: Effect.succeed("fallback") }) const a = yield* runner.ensureRunning(Effect.never.pipe(Effect.as("x"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Running") const b = yield* runner.ensureRunning(Effect.succeed("y")).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* Effect.yieldNow yield* runner.cancel @@ -189,7 +194,7 @@ describe("Runner", () => { const s = yield* Scope.Scope const runner = Runner.make(s) const fiber = yield* runner.ensureRunning(Effect.never.pipe(Effect.as("x"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Running") yield* runner.cancel yield* Fiber.await(fiber) @@ -215,7 +220,7 @@ describe("Runner", () => { ) const a = yield* runner.ensureRunning(first).pipe(Effect.exit, Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Running") const stop = yield* runner.cancel.pipe(Effect.forkChild) yield* Deferred.await(hit).pipe(Effect.timeout("250 millis")) @@ -293,7 +298,7 @@ describe("Runner", () => { const gate = yield* Deferred.make() const sh = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("first"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Shell") const exit = yield* runner.startShell(Effect.succeed("second")).pipe(Effect.exit) expect(Exit.isFailure(exit)).toBe(true) @@ -314,7 +319,7 @@ describe("Runner", () => { }) const sh = yield* runner.startShell(Effect.never.pipe(Effect.as("aborted"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Shell") const exit = yield* runner.startShell(Effect.succeed("second")).pipe(Effect.exit) expect(Exit.isFailure(exit)).toBe(true) @@ -333,7 +338,7 @@ describe("Runner", () => { const gate = yield* Deferred.make() const sh = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("ignored"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Shell") const stop = yield* runner.cancel.pipe(Effect.forkChild) const stopExit = yield* Fiber.await(stop).pipe(Effect.timeout("250 millis")) @@ -380,11 +385,11 @@ describe("Runner", () => { const gate = yield* Deferred.make() const sh = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("shell-result"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Shell") expect(runner.state._tag).toBe("Shell") const run = yield* runner.ensureRunning(Effect.succeed("run-result")).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "ShellThenRun") expect(runner.state._tag).toBe("ShellThenRun") yield* Deferred.succeed(gate, undefined) @@ -406,7 +411,7 @@ describe("Runner", () => { const gate = yield* Deferred.make() const sh = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("shell"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Shell") const work = Effect.gen(function* () { yield* Ref.update(calls, (n) => n + 1) @@ -414,7 +419,7 @@ describe("Runner", () => { }) const a = yield* runner.ensureRunning(work).pipe(Effect.forkChild) const b = yield* runner.ensureRunning(work).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "ShellThenRun") yield* Deferred.succeed(gate, undefined) yield* Fiber.await(sh) @@ -433,10 +438,10 @@ describe("Runner", () => { const runner = Runner.make(s) const sh = yield* runner.startShell(Effect.never.pipe(Effect.as("aborted"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Shell") const run = yield* runner.ensureRunning(Effect.succeed("y")).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "ShellThenRun") expect(runner.state._tag).toBe("ShellThenRun") yield* runner.cancel @@ -472,7 +477,7 @@ describe("Runner", () => { onIdle: Ref.update(count, (n) => n + 1), }) const fiber = yield* runner.ensureRunning(Effect.never.pipe(Effect.as("x"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Running") yield* runner.cancel yield* Fiber.await(fiber) expect(yield* Ref.get(count)).toBeGreaterThanOrEqual(1) @@ -502,7 +507,7 @@ describe("Runner", () => { const gate = yield* Deferred.make() const fiber = yield* runner.ensureRunning(Deferred.await(gate).pipe(Effect.as("ok"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Running") expect(runner.busy).toBe(true) yield* Deferred.succeed(gate, undefined) @@ -519,7 +524,7 @@ describe("Runner", () => { const gate = yield* Deferred.make() const fiber = yield* runner.startShell(Deferred.await(gate).pipe(Effect.as("ok"))).pipe(Effect.forkChild) - yield* Effect.sleep("10 millis") + yield* waitForState(runner, "Shell") expect(runner.busy).toBe(true) yield* Deferred.succeed(gate, undefined) diff --git a/packages/opencode/test/effect/runtime-flags.test.ts b/packages/opencode/test/effect/runtime-flags.test.ts new file mode 100644 index 0000000000..2f5fa25abf --- /dev/null +++ b/packages/opencode/test/effect/runtime-flags.test.ts @@ -0,0 +1,76 @@ +import { describe, expect } from "bun:test" +import { ConfigProvider, Effect, Layer } from "effect" +import { RuntimeFlags } from "../../src/effect/runtime-flags" +import { it } from "../lib/effect" + +const fromConfig = (input: Record) => + RuntimeFlags.defaultLayer.pipe(Layer.provide(ConfigProvider.layer(ConfigProvider.fromUnknown(input)))) + +const readFlags = RuntimeFlags.Service.useSync((flags) => flags) + +describe("RuntimeFlags", () => { + it.effect("defaultLayer parses plugin flags from the active ConfigProvider", () => + Effect.gen(function* () { + const flags = yield* readFlags.pipe( + Effect.provide( + fromConfig({ + OPENCODE_PURE: "true", + OPENCODE_DISABLE_DEFAULT_PLUGINS: "true", + OPENCODE_EXPERIMENTAL: "true", + OPENCODE_ENABLE_EXA: "true", + OPENCODE_ENABLE_PARALLEL: "true", + OPENCODE_ENABLE_QUESTION_TOOL: "true", + OPENCODE_CLIENT: "desktop", + }), + ), + ) + + expect(flags.pure).toBe(true) + expect(flags.disableDefaultPlugins).toBe(true) + expect(flags.enableExa).toBe(true) + expect(flags.enableParallel).toBe(true) + expect(flags.enableQuestionTool).toBe(true) + expect(flags.experimentalScout).toBe(true) + expect(flags.experimentalLspTool).toBe(true) + expect(flags.experimentalPlanMode).toBe(true) + expect(flags.experimentalEventSystem).toBe(true) + expect(flags.experimentalWorkspaces).toBe(true) + expect(flags.client).toBe("desktop") + }), + ) + + it.effect("layer accepts partial test overrides and fills defaults from Config definitions", () => + Effect.gen(function* () { + const flags = yield* readFlags.pipe(Effect.provide(RuntimeFlags.layer({ disableDefaultPlugins: true }))) + + expect(flags.pure).toBe(false) + expect(flags.disableDefaultPlugins).toBe(true) + expect(flags.enableExa).toBe(false) + expect(flags.client).toBe("cli") + }), + ) + + it.effect("layer ignores the active ConfigProvider for omitted test overrides", () => + Effect.gen(function* () { + const flags = yield* readFlags.pipe( + Effect.provide(RuntimeFlags.layer()), + Effect.provide( + ConfigProvider.layer( + ConfigProvider.fromUnknown({ + OPENCODE_PURE: "true", + OPENCODE_DISABLE_DEFAULT_PLUGINS: "true", + OPENCODE_EXPERIMENTAL: "true", + OPENCODE_ENABLE_EXA: "true", + OPENCODE_CLIENT: "desktop", + }), + ), + ), + ) + + expect(flags.pure).toBe(false) + expect(flags.disableDefaultPlugins).toBe(false) + expect(flags.enableExa).toBe(false) + expect(flags.client).toBe("cli") + }), + ) +}) diff --git a/packages/opencode/test/file/fsmonitor.test.ts b/packages/opencode/test/file/fsmonitor.test.ts index f345cd0850..b8d3bd6055 100644 --- a/packages/opencode/test/file/fsmonitor.test.ts +++ b/packages/opencode/test/file/fsmonitor.test.ts @@ -3,67 +3,71 @@ import { describe, expect, test } from "bun:test" import { Effect } from "effect" import fs from "fs/promises" import path from "path" -import { File } from "../../src/file" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" -import { provideInstance, tmpdir } from "../fixture/fixture" -const run = (eff: Effect.Effect) => - Effect.runPromise(provideInstance(Instance.directory)(eff.pipe(Effect.provide(File.defaultLayer)))) -const status = () => run(File.Service.use((svc) => svc.status())) -const read = (file: string) => run(File.Service.use((svc) => svc.read(file))) - -const wintest = process.platform === "win32" ? test : test.skip +const it = + process.platform === "win32" + ? (await import("../lib/effect")).testEffect((await import("../../src/file")).File.defaultLayer) + : undefined describe("file fsmonitor", () => { - wintest("status does not start fsmonitor for readonly git checks", async () => { - await using tmp = await tmpdir({ git: true }) - const target = path.join(tmp.path, "tracked.txt") + if (!it) { + test.skip("status does not start fsmonitor for readonly git checks", () => {}) + test.skip("read does not start fsmonitor for git diffs", () => {}) + return + } - await fs.writeFile(target, "base\n") - await $`git add tracked.txt`.cwd(tmp.path).quiet() - await $`git commit -m init`.cwd(tmp.path).quiet() - await $`git config core.fsmonitor true`.cwd(tmp.path).quiet() - await $`git fsmonitor--daemon stop`.cwd(tmp.path).quiet().nothrow() - await fs.writeFile(target, "next\n") - await fs.writeFile(path.join(tmp.path, "new.txt"), "new\n") + it.instance( + "status does not start fsmonitor for readonly git checks", + () => + Effect.gen(function* () { + const { File } = yield* Effect.promise(() => import("../../src/file")) + const { TestInstance } = yield* Effect.promise(() => import("../fixture/fixture")) + const directory = (yield* TestInstance).directory + const target = path.join(directory, "tracked.txt") - const before = await $`git fsmonitor--daemon status`.cwd(tmp.path).quiet().nothrow() - expect(before.exitCode).not.toBe(0) + yield* Effect.promise(() => fs.writeFile(target, "base\n")) + yield* Effect.promise(() => $`git add tracked.txt`.cwd(directory).quiet()) + yield* Effect.promise(() => $`git commit -m init`.cwd(directory).quiet()) + yield* Effect.promise(() => $`git config core.fsmonitor true`.cwd(directory).quiet()) + yield* Effect.promise(() => $`git fsmonitor--daemon stop`.cwd(directory).quiet().nothrow()) + yield* Effect.promise(() => fs.writeFile(target, "next\n")) + yield* Effect.promise(() => fs.writeFile(path.join(directory, "new.txt"), "new\n")) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await status() - }, - }) + const before = yield* Effect.promise(() => $`git fsmonitor--daemon status`.cwd(directory).quiet().nothrow()) + expect(before.exitCode).not.toBe(0) - const after = await $`git fsmonitor--daemon status`.cwd(tmp.path).quiet().nothrow() - expect(after.exitCode).not.toBe(0) - }) + yield* File.Service.use((svc) => svc.status()) - wintest("read does not start fsmonitor for git diffs", async () => { - await using tmp = await tmpdir({ git: true }) - const target = path.join(tmp.path, "tracked.txt") + const after = yield* Effect.promise(() => $`git fsmonitor--daemon status`.cwd(directory).quiet().nothrow()) + expect(after.exitCode).not.toBe(0) + }), + { git: true }, + ) - await fs.writeFile(target, "base\n") - await $`git add tracked.txt`.cwd(tmp.path).quiet() - await $`git commit -m init`.cwd(tmp.path).quiet() - await $`git config core.fsmonitor true`.cwd(tmp.path).quiet() - await $`git fsmonitor--daemon stop`.cwd(tmp.path).quiet().nothrow() - await fs.writeFile(target, "next\n") + it.instance( + "read does not start fsmonitor for git diffs", + () => + Effect.gen(function* () { + const { File } = yield* Effect.promise(() => import("../../src/file")) + const { TestInstance } = yield* Effect.promise(() => import("../fixture/fixture")) + const directory = (yield* TestInstance).directory + const target = path.join(directory, "tracked.txt") - const before = await $`git fsmonitor--daemon status`.cwd(tmp.path).quiet().nothrow() - expect(before.exitCode).not.toBe(0) + yield* Effect.promise(() => fs.writeFile(target, "base\n")) + yield* Effect.promise(() => $`git add tracked.txt`.cwd(directory).quiet()) + yield* Effect.promise(() => $`git commit -m init`.cwd(directory).quiet()) + yield* Effect.promise(() => $`git config core.fsmonitor true`.cwd(directory).quiet()) + yield* Effect.promise(() => $`git fsmonitor--daemon stop`.cwd(directory).quiet().nothrow()) + yield* Effect.promise(() => fs.writeFile(target, "next\n")) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await read("tracked.txt") - }, - }) + const before = yield* Effect.promise(() => $`git fsmonitor--daemon status`.cwd(directory).quiet().nothrow()) + expect(before.exitCode).not.toBe(0) - const after = await $`git fsmonitor--daemon status`.cwd(tmp.path).quiet().nothrow() - expect(after.exitCode).not.toBe(0) - }) + yield* File.Service.use((svc) => svc.read("tracked.txt")) + + const after = yield* Effect.promise(() => $`git fsmonitor--daemon status`.cwd(directory).quiet().nothrow()) + expect(after.exitCode).not.toBe(0) + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/file/path-traversal.test.ts b/packages/opencode/test/file/path-traversal.test.ts index 5b59929ea5..336f214d1a 100644 --- a/packages/opencode/test/file/path-traversal.test.ts +++ b/packages/opencode/test/file/path-traversal.test.ts @@ -1,42 +1,55 @@ -import { test, expect, describe } from "bun:test" -import { Effect } from "effect" +import { expect, describe } from "bun:test" +import { Cause, Effect, Exit } from "effect" import path from "path" import fs from "fs/promises" import { Filesystem } from "@/util/filesystem" import { File } from "../../src/file" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" +import { InstanceState } from "../../src/effect/instance-state" import { containsPath } from "../../src/project/instance-context" -import { provideInstance, tmpdir } from "../fixture/fixture" +import { TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" -const run = (eff: Effect.Effect) => - Effect.runPromise(provideInstance(Instance.directory)(eff.pipe(Effect.provide(File.defaultLayer)))) -const read = (file: string) => run(File.Service.use((svc) => svc.read(file))) -const list = (dir?: string) => run(File.Service.use((svc) => svc.list(dir))) +const it = testEffect(File.defaultLayer) +const read = (file: string) => File.Service.use((svc) => svc.read(file)) +const list = (dir?: string) => File.Service.use((svc) => svc.list(dir)) +const expectAccessDenied = (effect: Effect.Effect) => + Effect.gen(function* () { + const exit = yield* effect.pipe(Effect.exit) + if (Exit.isSuccess(exit)) throw new Error("expected access denied") + expect(Cause.squash(exit.cause)).toHaveProperty("message", "Access denied: path escapes project directory") + }) describe("Filesystem.contains", () => { - test("allows paths within project", () => { - expect(Filesystem.contains("/project", "/project/src")).toBe(true) - expect(Filesystem.contains("/project", "/project/src/file.ts")).toBe(true) - expect(Filesystem.contains("/project", "/project")).toBe(true) - }) + it.effect("allows paths within project", () => + Effect.sync(() => { + expect(Filesystem.contains("/project", "/project/src")).toBe(true) + expect(Filesystem.contains("/project", "/project/src/file.ts")).toBe(true) + expect(Filesystem.contains("/project", "/project")).toBe(true) + }), + ) - test("blocks ../ traversal", () => { - expect(Filesystem.contains("/project", "/project/../etc")).toBe(false) - expect(Filesystem.contains("/project", "/project/src/../../etc")).toBe(false) - expect(Filesystem.contains("/project", "/etc/passwd")).toBe(false) - }) + it.effect("blocks ../ traversal", () => + Effect.sync(() => { + expect(Filesystem.contains("/project", "/project/../etc")).toBe(false) + expect(Filesystem.contains("/project", "/project/src/../../etc")).toBe(false) + expect(Filesystem.contains("/project", "/etc/passwd")).toBe(false) + }), + ) - test("blocks absolute paths outside project", () => { - expect(Filesystem.contains("/project", "/etc/passwd")).toBe(false) - expect(Filesystem.contains("/project", "/tmp/file")).toBe(false) - expect(Filesystem.contains("/home/user/project", "/home/user/other")).toBe(false) - }) + it.effect("blocks absolute paths outside project", () => + Effect.sync(() => { + expect(Filesystem.contains("/project", "/etc/passwd")).toBe(false) + expect(Filesystem.contains("/project", "/tmp/file")).toBe(false) + expect(Filesystem.contains("/home/user/project", "/home/user/other")).toBe(false) + }), + ) - test("handles prefix collision edge cases", () => { - expect(Filesystem.contains("/project", "/project-other/file")).toBe(false) - expect(Filesystem.contains("/project", "/projectfile")).toBe(false) - }) + it.effect("handles prefix collision edge cases", () => + Effect.sync(() => { + expect(Filesystem.contains("/project", "/project-other/file")).toBe(false) + expect(Filesystem.contains("/project", "/projectfile")).toBe(false) + }), + ) }) /* @@ -49,158 +62,124 @@ describe("Filesystem.contains", () => { * This is a SEPARATE code path from ReadTool, which has its own checks. */ describe("File.read path traversal protection", () => { - test("rejects ../ traversal attempting to read /etc/passwd", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "allowed.txt"), "allowed content") - }, - }) + it.instance("rejects ../ traversal attempting to read /etc/passwd", () => + Effect.gen(function* () { + const test = yield* TestInstance + yield* Effect.promise(() => Bun.write(path.join(test.directory, "allowed.txt"), "allowed content")) + yield* expectAccessDenied(read("../../../etc/passwd")) + }), + ) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await expect(read("../../../etc/passwd")).rejects.toThrow("Access denied: path escapes project directory") - }, - }) - }) + it.instance("rejects deeply nested traversal", () => + Effect.gen(function* () { + yield* expectAccessDenied(read("src/nested/../../../../../../../etc/passwd")) + }), + ) - test("rejects deeply nested traversal", async () => { - await using tmp = await tmpdir() + it.instance("allows valid paths within project", () => + Effect.gen(function* () { + const test = yield* TestInstance + yield* Effect.promise(() => Bun.write(path.join(test.directory, "valid.txt"), "valid content")) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await expect(read("src/nested/../../../../../../../etc/passwd")).rejects.toThrow( - "Access denied: path escapes project directory", - ) - }, - }) - }) - - test("allows valid paths within project", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "valid.txt"), "valid content") - }, - }) - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const result = await read("valid.txt") - expect(result.content).toBe("valid content") - }, - }) - }) + const result = yield* read("valid.txt") + expect(result.content).toBe("valid content") + }), + ) }) describe("File.list path traversal protection", () => { - test("rejects ../ traversal attempting to list /etc", async () => { - await using tmp = await tmpdir() + it.instance("rejects ../ traversal attempting to list /etc", () => + Effect.gen(function* () { + yield* expectAccessDenied(list("../../../etc")) + }), + ) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await expect(list("../../../etc")).rejects.toThrow("Access denied: path escapes project directory") - }, - }) - }) + it.instance("allows valid subdirectory listing", () => + Effect.gen(function* () { + const test = yield* TestInstance + yield* Effect.promise(() => Bun.write(path.join(test.directory, "subdir", "file.txt"), "content")) - test("allows valid subdirectory listing", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "subdir", "file.txt"), "content") - }, - }) - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const result = await list("subdir") - expect(Array.isArray(result)).toBe(true) - }, - }) - }) + const result = yield* list("subdir") + expect(Array.isArray(result)).toBe(true) + }), + ) }) describe("containsPath", () => { - test("returns true for path inside directory", async () => { - await using tmp = await tmpdir({ git: true }) + it.instance( + "returns true for path inside directory", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const ctx = yield* InstanceState.context + expect(containsPath(path.join(test.directory, "foo.txt"), ctx)).toBe(true) + expect(containsPath(path.join(test.directory, "src", "file.ts"), ctx)).toBe(true) + }), + { git: true }, + ) - await WithInstance.provide({ - directory: tmp.path, - fn: () => { - expect(containsPath(path.join(tmp.path, "foo.txt"), Instance.current)).toBe(true) - expect(containsPath(path.join(tmp.path, "src", "file.ts"), Instance.current)).toBe(true) - }, - }) - }) + it.instance( + "returns true for path inside worktree but outside directory (monorepo subdirectory scenario)", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const subdir = path.join(test.directory, "packages", "lib") + yield* Effect.promise(() => fs.mkdir(subdir, { recursive: true })) + const ctx = { ...(yield* InstanceState.context), directory: subdir } - test("returns true for path inside worktree but outside directory (monorepo subdirectory scenario)", async () => { - await using tmp = await tmpdir({ git: true }) - const subdir = path.join(tmp.path, "packages", "lib") - await fs.mkdir(subdir, { recursive: true }) - - await WithInstance.provide({ - directory: subdir, - fn: () => { // .opencode at worktree root, but we're running from packages/lib - expect(containsPath(path.join(tmp.path, ".opencode", "state"), Instance.current)).toBe(true) + expect(containsPath(path.join(test.directory, ".opencode", "state"), ctx)).toBe(true) // sibling package should also be accessible - expect(containsPath(path.join(tmp.path, "packages", "other", "file.ts"), Instance.current)).toBe(true) + expect(containsPath(path.join(test.directory, "packages", "other", "file.ts"), ctx)).toBe(true) // worktree root itself - expect(containsPath(tmp.path, Instance.current)).toBe(true) - }, - }) - }) + expect(containsPath(test.directory, ctx)).toBe(true) + }), + { git: true }, + ) - test("returns false for path outside both directory and worktree", async () => { - await using tmp = await tmpdir({ git: true }) + it.instance( + "returns false for path outside both directory and worktree", + () => + Effect.gen(function* () { + const ctx = yield* InstanceState.context + expect(containsPath("/etc/passwd", ctx)).toBe(false) + expect(containsPath("/tmp/other-project", ctx)).toBe(false) + }), + { git: true }, + ) - await WithInstance.provide({ - directory: tmp.path, - fn: () => { - expect(containsPath("/etc/passwd", Instance.current)).toBe(false) - expect(containsPath("/tmp/other-project", Instance.current)).toBe(false) - }, - }) - }) + it.instance( + "returns false for path with .. escaping worktree", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const ctx = yield* InstanceState.context + expect(containsPath(path.join(test.directory, "..", "escape.txt"), ctx)).toBe(false) + }), + { git: true }, + ) - test("returns false for path with .. escaping worktree", async () => { - await using tmp = await tmpdir({ git: true }) + it.instance( + "handles directory === worktree (running from repo root)", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const ctx = yield* InstanceState.context + expect(ctx.directory).toBe(ctx.worktree) + expect(containsPath(path.join(test.directory, "file.txt"), ctx)).toBe(true) + expect(containsPath("/etc/passwd", ctx)).toBe(false) + }), + { git: true }, + ) - await WithInstance.provide({ - directory: tmp.path, - fn: () => { - expect(containsPath(path.join(tmp.path, "..", "escape.txt"), Instance.current)).toBe(false) - }, - }) - }) - - test("handles directory === worktree (running from repo root)", async () => { - await using tmp = await tmpdir({ git: true }) - - await WithInstance.provide({ - directory: tmp.path, - fn: () => { - expect(Instance.directory).toBe(Instance.worktree) - expect(containsPath(path.join(tmp.path, "file.txt"), Instance.current)).toBe(true) - expect(containsPath("/etc/passwd", Instance.current)).toBe(false) - }, - }) - }) - - test("non-git project does not allow arbitrary paths via worktree='/'", async () => { - await using tmp = await tmpdir() // no git: true - - await WithInstance.provide({ - directory: tmp.path, - fn: () => { - // worktree is "/" for non-git projects, but containsPath should NOT allow all paths - expect(containsPath(path.join(tmp.path, "file.txt"), Instance.current)).toBe(true) - expect(containsPath("/etc/passwd", Instance.current)).toBe(false) - expect(containsPath("/tmp/other", Instance.current)).toBe(false) - }, - }) - }) + it.instance("non-git project does not allow arbitrary paths via worktree='/'", () => + Effect.gen(function* () { + const test = yield* TestInstance + const ctx = yield* InstanceState.context + // worktree is "/" for non-git projects, but containsPath should NOT allow all paths + expect(containsPath(path.join(test.directory, "file.txt"), ctx)).toBe(true) + expect(containsPath("/etc/passwd", ctx)).toBe(false) + expect(containsPath("/tmp/other", ctx)).toBe(false) + }), + ) }) diff --git a/packages/opencode/test/file/ripgrep.test.ts b/packages/opencode/test/file/ripgrep.test.ts index a76c7ebe26..d71ce205ea 100644 --- a/packages/opencode/test/file/ripgrep.test.ts +++ b/packages/opencode/test/file/ripgrep.test.ts @@ -1,214 +1,220 @@ -import { describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import { Effect } from "effect" import * as Stream from "effect/Stream" import fs from "fs/promises" +import os from "os" import path from "path" -import { tmpdir } from "../fixture/fixture" import { Ripgrep } from "../../src/file/ripgrep" +import { testEffect } from "../lib/effect" -const run = (effect: Effect.Effect) => - effect.pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise) +const it = testEffect(Ripgrep.defaultLayer) + +const tmpdir = (init?: (dir: string) => Effect.Effect) => + Effect.acquireRelease( + Effect.promise(async () => fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), "opencode-test-")))), + (dir) => + Effect.promise(() => + fs.rm(dir, { + recursive: true, + force: true, + maxRetries: 5, + retryDelay: 100, + }), + ).pipe(Effect.ignore), + ).pipe(Effect.tap((dir) => init?.(dir) ?? Effect.void)) + +const write = (file: string, data: string) => Effect.promise(() => Bun.write(file, data)) +const mkdir = (dir: string) => Effect.promise(() => fs.mkdir(dir, { recursive: true })) +const collectFiles = (input: Ripgrep.FilesInput) => + Ripgrep.Service.use((rg) => + rg.files(input).pipe( + Stream.runCollect, + Effect.map((c) => [...c]), + ), + ) + +const withRipgrepConfig = (value: string, effect: Effect.Effect) => + Effect.acquireUseRelease( + Effect.sync(() => { + const prev = process.env["RIPGREP_CONFIG_PATH"] + process.env["RIPGREP_CONFIG_PATH"] = value + return prev + }), + () => effect, + (prev) => + Effect.sync(() => { + if (prev === undefined) delete process.env["RIPGREP_CONFIG_PATH"] + else process.env["RIPGREP_CONFIG_PATH"] = prev + }), + ) describe("file.ripgrep", () => { - test("defaults to include hidden", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "visible.txt"), "hello") - await fs.mkdir(path.join(dir, ".opencode"), { recursive: true }) - await Bun.write(path.join(dir, ".opencode", "thing.json"), "{}") - }, - }) + it.live("defaults to include hidden", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => + Effect.gen(function* () { + yield* write(path.join(dir, "visible.txt"), "hello") + yield* mkdir(path.join(dir, ".opencode")) + yield* write(path.join(dir, ".opencode", "thing.json"), "{}") + }), + ) - const files = await run( - Ripgrep.Service.use((rg) => - rg.files({ cwd: tmp.path }).pipe( - Stream.runCollect, - Effect.map((c) => [...c]), - ), - ), - ) - expect(files.includes("visible.txt")).toBe(true) - expect(files.includes(path.join(".opencode", "thing.json"))).toBe(true) - }) + const files = yield* collectFiles({ cwd: dir }) + expect(files.includes("visible.txt")).toBe(true) + expect(files.includes(path.join(".opencode", "thing.json"))).toBe(true) + }), + ) - test("hidden false excludes hidden", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "visible.txt"), "hello") - await fs.mkdir(path.join(dir, ".opencode"), { recursive: true }) - await Bun.write(path.join(dir, ".opencode", "thing.json"), "{}") - }, - }) + it.live("hidden false excludes hidden", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => + Effect.gen(function* () { + yield* write(path.join(dir, "visible.txt"), "hello") + yield* mkdir(path.join(dir, ".opencode")) + yield* write(path.join(dir, ".opencode", "thing.json"), "{}") + }), + ) - const files = await run( - Ripgrep.Service.use((rg) => - rg.files({ cwd: tmp.path, hidden: false }).pipe( - Stream.runCollect, - Effect.map((c) => [...c]), - ), - ), - ) - expect(files.includes("visible.txt")).toBe(true) - expect(files.includes(path.join(".opencode", "thing.json"))).toBe(false) - }) + const files = yield* collectFiles({ cwd: dir, hidden: false }) + expect(files.includes("visible.txt")).toBe(true) + expect(files.includes(path.join(".opencode", "thing.json"))).toBe(false) + }), + ) - test("search returns empty when nothing matches", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "match.ts"), "const value = 'other'\n") - }, - }) + it.live("search returns empty when nothing matches", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => write(path.join(dir, "match.ts"), "const value = 'other'\n")) - const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle" }))) - expect(result.partial).toBe(false) - expect(result.items).toEqual([]) - }) + const result = yield* Ripgrep.Service.use((rg) => rg.search({ cwd: dir, pattern: "needle" })) + expect(result.partial).toBe(false) + expect(result.items).toEqual([]) + }), + ) - test("search returns match metadata with normalized path", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await fs.mkdir(path.join(dir, "src"), { recursive: true }) - await Bun.write(path.join(dir, "src", "match.ts"), "const needle = 1\n") - }, - }) + it.live("search returns match metadata with normalized path", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => + Effect.gen(function* () { + yield* mkdir(path.join(dir, "src")) + yield* write(path.join(dir, "src", "match.ts"), "const needle = 1\n") + }), + ) - const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle" }))) - expect(result.partial).toBe(false) - expect(result.items).toHaveLength(1) - expect(result.items[0]?.path.text).toBe(path.join("src", "match.ts")) - expect(result.items[0]?.line_number).toBe(1) - expect(result.items[0]?.lines.text).toContain("needle") - }) - - test("search returns matched rows with glob filter", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "match.ts"), "const value = 'needle'\n") - await Bun.write(path.join(dir, "skip.txt"), "const value = 'other'\n") - }, - }) - - const result = await run( - Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle", glob: ["*.ts"] })), - ) - expect(result.partial).toBe(false) - expect(result.items).toHaveLength(1) - expect(result.items[0]?.path.text).toContain("match.ts") - expect(result.items[0]?.lines.text).toContain("needle") - }) - - test("search supports explicit file targets", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "match.ts"), "const value = 'needle'\n") - await Bun.write(path.join(dir, "skip.ts"), "const value = 'needle'\n") - }, - }) - - const file = path.join(tmp.path, "match.ts") - const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle", file: [file] }))) - expect(result.partial).toBe(false) - expect(result.items).toHaveLength(1) - expect(result.items[0]?.path.text).toBe(file) - }) - - test("files returns empty when glob matches no files", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await fs.mkdir(path.join(dir, "packages", "console"), { recursive: true }) - await Bun.write(path.join(dir, "packages", "console", "package.json"), "{}") - }, - }) - - const files = await run( - Ripgrep.Service.use((rg) => - rg.files({ cwd: tmp.path, glob: ["packages/*"] }).pipe( - Stream.runCollect, - Effect.map((c) => [...c]), - ), - ), - ) - expect(files).toEqual([]) - }) - - test("files returns stream of filenames", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "a.txt"), "hello") - await Bun.write(path.join(dir, "b.txt"), "world") - }, - }) - - const files = await run( - Ripgrep.Service.use((rg) => - rg.files({ cwd: tmp.path }).pipe( - Stream.runCollect, - Effect.map((c) => [...c].sort()), - ), - ), - ) - expect(files).toEqual(["a.txt", "b.txt"]) - }) - - test("files respects glob filter", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "keep.ts"), "yes") - await Bun.write(path.join(dir, "skip.txt"), "no") - }, - }) - - const files = await run( - Ripgrep.Service.use((rg) => - rg.files({ cwd: tmp.path, glob: ["*.ts"] }).pipe( - Stream.runCollect, - Effect.map((c) => [...c]), - ), - ), - ) - expect(files).toEqual(["keep.ts"]) - }) - - test("files dies on nonexistent directory", async () => { - const exit = await Ripgrep.Service.use((rg) => - rg.files({ cwd: "/tmp/nonexistent-dir-12345" }).pipe(Stream.runCollect), - ).pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromiseExit) - expect(exit._tag).toBe("Failure") - }) - - test("ignores RIPGREP_CONFIG_PATH in direct mode", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "match.ts"), "const needle = 1\n") - }, - }) - - const prev = process.env["RIPGREP_CONFIG_PATH"] - process.env["RIPGREP_CONFIG_PATH"] = path.join(tmp.path, "missing-ripgreprc") - try { - const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle" }))) + const result = yield* Ripgrep.Service.use((rg) => rg.search({ cwd: dir, pattern: "needle" })) + expect(result.partial).toBe(false) expect(result.items).toHaveLength(1) - } finally { - if (prev === undefined) delete process.env["RIPGREP_CONFIG_PATH"] - else process.env["RIPGREP_CONFIG_PATH"] = prev - } - }) + expect(result.items[0]?.path.text).toBe(path.join("src", "match.ts")) + expect(result.items[0]?.line_number).toBe(1) + expect(result.items[0]?.lines.text).toContain("needle") + }), + ) - test("ignores RIPGREP_CONFIG_PATH in worker mode", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "match.ts"), "const needle = 1\n") - }, - }) + it.live("search returns matched rows with glob filter", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => + Effect.gen(function* () { + yield* write(path.join(dir, "match.ts"), "const value = 'needle'\n") + yield* write(path.join(dir, "skip.txt"), "const value = 'other'\n") + }), + ) - const prev = process.env["RIPGREP_CONFIG_PATH"] - process.env["RIPGREP_CONFIG_PATH"] = path.join(tmp.path, "missing-ripgreprc") - try { - const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle" }))) + const result = yield* Ripgrep.Service.use((rg) => rg.search({ cwd: dir, pattern: "needle", glob: ["*.ts"] })) + expect(result.partial).toBe(false) expect(result.items).toHaveLength(1) - } finally { - if (prev === undefined) delete process.env["RIPGREP_CONFIG_PATH"] - else process.env["RIPGREP_CONFIG_PATH"] = prev - } - }) + expect(result.items[0]?.path.text).toContain("match.ts") + expect(result.items[0]?.lines.text).toContain("needle") + }), + ) + + it.live("search supports explicit file targets", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => + Effect.gen(function* () { + yield* write(path.join(dir, "match.ts"), "const value = 'needle'\n") + yield* write(path.join(dir, "skip.ts"), "const value = 'needle'\n") + }), + ) + + const file = path.join(dir, "match.ts") + const result = yield* Ripgrep.Service.use((rg) => rg.search({ cwd: dir, pattern: "needle", file: [file] })) + expect(result.partial).toBe(false) + expect(result.items).toHaveLength(1) + expect(result.items[0]?.path.text).toBe(file) + }), + ) + + it.live("files returns empty when glob matches no files", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => + Effect.gen(function* () { + yield* mkdir(path.join(dir, "packages", "console")) + yield* write(path.join(dir, "packages", "console", "package.json"), "{}") + }), + ) + + const files = yield* collectFiles({ cwd: dir, glob: ["packages/*"] }) + expect(files).toEqual([]) + }), + ) + + it.live("files returns stream of filenames", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => + Effect.gen(function* () { + yield* write(path.join(dir, "a.txt"), "hello") + yield* write(path.join(dir, "b.txt"), "world") + }), + ) + + const files = yield* collectFiles({ cwd: dir }).pipe(Effect.map((files) => files.sort())) + expect(files).toEqual(["a.txt", "b.txt"]) + }), + ) + + it.live("files respects glob filter", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => + Effect.gen(function* () { + yield* write(path.join(dir, "keep.ts"), "yes") + yield* write(path.join(dir, "skip.txt"), "no") + }), + ) + + const files = yield* collectFiles({ cwd: dir, glob: ["*.ts"] }) + expect(files).toEqual(["keep.ts"]) + }), + ) + + it.live("files dies on nonexistent directory", () => + Effect.gen(function* () { + const exit = yield* Ripgrep.Service.use((rg) => + rg.files({ cwd: "/tmp/nonexistent-dir-12345" }).pipe(Stream.runCollect), + ).pipe(Effect.exit) + expect(exit._tag).toBe("Failure") + }), + ) + + it.live("ignores RIPGREP_CONFIG_PATH in direct mode", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => write(path.join(dir, "match.ts"), "const needle = 1\n")) + + const result = yield* withRipgrepConfig( + path.join(dir, "missing-ripgreprc"), + Ripgrep.Service.use((rg) => rg.search({ cwd: dir, pattern: "needle" })), + ) + expect(result.items).toHaveLength(1) + }), + ) + + it.live("ignores RIPGREP_CONFIG_PATH in worker mode", () => + Effect.gen(function* () { + const dir = yield* tmpdir((dir) => write(path.join(dir, "match.ts"), "const needle = 1\n")) + + const result = yield* withRipgrepConfig( + path.join(dir, "missing-ripgreprc"), + Ripgrep.Service.use((rg) => rg.search({ cwd: dir, pattern: "needle" })), + ) + expect(result.items).toHaveLength(1) + }), + ) }) diff --git a/packages/opencode/test/file/watcher.test.ts b/packages/opencode/test/file/watcher.test.ts index 7e47c51351..6276e58f29 100644 --- a/packages/opencode/test/file/watcher.test.ts +++ b/packages/opencode/test/file/watcher.test.ts @@ -1,15 +1,13 @@ -import { $ } from "bun" -import { afterEach, describe, expect, test } from "bun:test" -import fs from "fs/promises" +import { describe, expect } from "bun:test" import path from "path" -import { ConfigProvider, Deferred, Effect, Layer, ManagedRuntime, Option } from "effect" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { Bus } from "../../src/bus" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { ConfigProvider, Deferred, Effect, Layer, Option } from "effect" +import { TestInstance, provideInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" +import { GlobalBus, type GlobalEvent } from "../../src/bus/global" import { Config } from "@/config/config" import { FileWatcher } from "../../src/file/watcher" import { Git } from "../../src/git" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" // Native @parcel/watcher bindings aren't reliably available in CI (missing on Linux, flaky on Windows) const describeWatcher = FileWatcher.hasNativeBinding() && !process.env.CI ? describe : describe.skip @@ -25,43 +23,43 @@ const watcherConfigLayer = ConfigProvider.layer( }), ) +const watcherLayer = FileWatcher.layer.pipe( + Layer.provide(Config.defaultLayer), + Layer.provide(Git.defaultLayer), + Layer.provide(watcherConfigLayer), +) + +const it = testEffect(Layer.mergeAll(AppFileSystem.defaultLayer, Git.defaultLayer)) + type WatcherEvent = { file: string; event: "add" | "change" | "unlink" } /** Run `body` with a live FileWatcher service. */ -function withWatcher(directory: string, body: Effect.Effect) { - return WithInstance.provide({ - directory, - fn: async () => { - const layer: Layer.Layer = FileWatcher.layer.pipe( - Layer.provide(Config.defaultLayer), - Layer.provide(Git.defaultLayer), - Layer.provide(watcherConfigLayer), - ) - const rt = ManagedRuntime.make(layer) - try { - await rt.runPromise(FileWatcher.Service.use((s) => s.init())) - await Effect.runPromise(ready(directory)) - await Effect.runPromise(body) - } finally { - await rt.dispose() - } - }, - }) +function withWatcher(directory: string, body: Effect.Effect) { + return Effect.gen(function* () { + const watcher = yield* FileWatcher.Service + yield* watcher.init() + yield* ready(directory) + return yield* body + }).pipe(Effect.provide(watcherLayer), provideInstance(directory), Effect.scoped) } function listen(directory: string, check: (evt: WatcherEvent) => boolean, hit: (evt: WatcherEvent) => void) { let done = false - const unsub = Bus.subscribe(FileWatcher.Event.Updated, (evt) => { + const on = (evt: GlobalEvent) => { if (done) return - if (!check(evt.properties)) return - hit(evt.properties) - }) + if (evt.directory !== directory) return + if (evt.payload.type !== FileWatcher.Event.Updated.type) return + if (!check(evt.payload.properties)) return + hit(evt.payload.properties) + } + + GlobalBus.on("event", on) return () => { if (done) return done = true - unsub() + GlobalBus.off("event", on) } } @@ -72,7 +70,7 @@ function wait(directory: string, check: (evt: WatcherEvent) => boolean) { let off = () => {} off = listen(directory, check, (evt) => { off() - Deferred.doneUnsafe(deferred, Effect.succeed(evt)) + Effect.runFork(Deferred.succeed(deferred, evt)) }) return off }) @@ -86,7 +84,12 @@ function nextUpdate(directory: string, check: (evt: WatcherEvent) => boolean, ({ deferred }) => Effect.gen(function* () { yield* trigger - return yield* Deferred.await(deferred).pipe(Effect.timeout("5 seconds")) + return yield* Deferred.await(deferred).pipe( + Effect.timeoutOrElse({ + duration: "5 seconds", + orElse: () => Effect.fail(new Error("timed out waiting for file watcher update")), + }), + ) }), ({ cleanup }) => Effect.sync(cleanup), ) @@ -104,7 +107,11 @@ function noUpdate( ({ deferred }) => Effect.gen(function* () { yield* trigger - expect(yield* Deferred.await(deferred).pipe(Effect.timeoutOption(`${ms} millis`))).toEqual(Option.none()) + const result = yield* Deferred.await(deferred).pipe( + Effect.map((evt) => Option.some(evt)), + Effect.timeoutOrElse({ duration: `${ms} millis`, orElse: () => Effect.succeed(Option.none()) }), + ) + expect(result).toEqual(Option.none()) }), ({ cleanup }) => Effect.sync(cleanup), ) @@ -115,29 +122,25 @@ function ready(directory: string) { const head = path.join(directory, ".git", "HEAD") return Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const git = yield* Git.Service + yield* nextUpdate( directory, (evt) => evt.file === file && evt.event === "add", - Effect.promise(() => fs.writeFile(file, "ready")), - ).pipe(Effect.ensuring(Effect.promise(() => fs.rm(file, { force: true }).catch(() => undefined))), Effect.asVoid) + fs.writeFileString(file, "ready"), + ).pipe(Effect.ensuring(fs.remove(file, { force: true }).pipe(Effect.ignore)), Effect.asVoid) - const git = yield* Effect.promise(() => - fs - .stat(head) - .then(() => true) - .catch(() => false), - ) - if (!git) return + if (!(yield* fs.existsSafe(head))) return const branch = `watch-${Math.random().toString(36).slice(2)}` - const hash = yield* Effect.promise(() => $`git rev-parse HEAD`.cwd(directory).quiet().text()) + const hash = (yield* git.run(["rev-parse", "HEAD"], { cwd: directory })).text() yield* nextUpdate( directory, (evt) => evt.file === head && evt.event !== "unlink", - Effect.promise(async () => { - await fs.writeFile(path.join(directory, ".git", "refs", "heads", branch), hash.trim() + "\n") - await fs.writeFile(head, `ref: refs/heads/${branch}\n`) - }), + fs + .writeFileString(path.join(directory, ".git", "refs", "heads", branch), hash.trim() + "\n") + .pipe(Effect.andThen(fs.writeFileString(head, `ref: refs/heads/${branch}\n`))), ).pipe(Effect.asVoid) }) } @@ -147,104 +150,114 @@ function ready(directory: string) { // --------------------------------------------------------------------------- describeWatcher("FileWatcher", () => { - afterEach(async () => { - await disposeAllInstances() - }) + it.instance( + "publishes root create, update, and delete events", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const fs = yield* AppFileSystem.Service + const file = path.join(test.directory, "watch.txt") + const cases = [ + { event: "add" as const, trigger: fs.writeFileString(file, "a") }, + { event: "change" as const, trigger: fs.writeFileString(file, "b") }, + { event: "unlink" as const, trigger: fs.remove(file) }, + ] - test("publishes root create, update, and delete events", async () => { - await using tmp = await tmpdir({ git: true }) - const file = path.join(tmp.path, "watch.txt") - const dir = tmp.path - const cases = [ - { event: "add" as const, trigger: Effect.promise(() => fs.writeFile(file, "a")) }, - { event: "change" as const, trigger: Effect.promise(() => fs.writeFile(file, "b")) }, - { event: "unlink" as const, trigger: Effect.promise(() => fs.unlink(file)) }, - ] - - await withWatcher( - dir, - Effect.forEach(cases, ({ event, trigger }) => - nextUpdate(dir, (evt) => evt.file === file && evt.event === event, trigger).pipe( - Effect.tap((evt) => Effect.sync(() => expect(evt).toEqual({ file, event }))), - ), - ), - ) - }) - - test("watches non-git roots", async () => { - await using tmp = await tmpdir() - const file = path.join(tmp.path, "plain.txt") - const dir = tmp.path - - await withWatcher( - dir, - nextUpdate( - dir, - (e) => e.file === file && e.event === "add", - Effect.promise(() => fs.writeFile(file, "plain")), - ).pipe(Effect.tap((evt) => Effect.sync(() => expect(evt).toEqual({ file, event: "add" })))), - ) - }) - - test("cleanup stops publishing events", async () => { - await using tmp = await tmpdir({ git: true }) - const file = path.join(tmp.path, "after-dispose.txt") - - // Start and immediately stop the watcher (withWatcher disposes on exit) - await withWatcher(tmp.path, Effect.void) - - // Now write a file — no watcher should be listening - await WithInstance.provide({ - directory: tmp.path, - fn: () => - Effect.runPromise( - noUpdate( - tmp.path, - (e) => e.file === file, - Effect.promise(() => fs.writeFile(file, "gone")), + yield* withWatcher( + test.directory, + Effect.forEach(cases, ({ event, trigger }) => + nextUpdate(test.directory, (evt) => evt.file === file && evt.event === event, trigger).pipe( + Effect.tap((evt) => Effect.sync(() => expect(evt).toEqual({ file, event }))), + ), ), + ) + }), + { git: true }, + ) + + it.instance("watches non-git roots", () => + Effect.gen(function* () { + const test = yield* TestInstance + const fs = yield* AppFileSystem.Service + const file = path.join(test.directory, "plain.txt") + + yield* withWatcher( + test.directory, + nextUpdate(test.directory, (e) => e.file === file && e.event === "add", fs.writeFileString(file, "plain")).pipe( + Effect.tap((evt) => Effect.sync(() => expect(evt).toEqual({ file, event: "add" }))), ), - }) - }) + ) + }), + ) - test("ignores .git/index changes", async () => { - await using tmp = await tmpdir({ git: true }) - const gitIndex = path.join(tmp.path, ".git", "index") - const edit = path.join(tmp.path, "tracked.txt") + it.instance( + "cleanup stops publishing events", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const fs = yield* AppFileSystem.Service + const file = path.join(test.directory, "after-dispose.txt") - await withWatcher( - tmp.path, - noUpdate( - tmp.path, - (e) => e.file === gitIndex, - Effect.promise(async () => { - await fs.writeFile(edit, "a") - await $`git add .`.cwd(tmp.path).quiet().nothrow() - }), - ), - ) - }) + // Start and immediately stop the watcher (withWatcher disposes on exit). + yield* withWatcher(test.directory, Effect.void) - test("publishes .git/HEAD events", async () => { - await using tmp = await tmpdir({ git: true }) - const head = path.join(tmp.path, ".git", "HEAD") - const branch = `watch-${Math.random().toString(36).slice(2)}` - await $`git branch ${branch}`.cwd(tmp.path).quiet() + // Now write a file - no watcher should be listening. + yield* noUpdate(test.directory, (e) => e.file === file, fs.writeFileString(file, "gone")).pipe( + provideInstance(test.directory), + ) + }), + { git: true }, + ) - await withWatcher( - tmp.path, - nextUpdate( - tmp.path, - (evt) => evt.file === head && evt.event !== "unlink", - Effect.promise(() => fs.writeFile(head, `ref: refs/heads/${branch}\n`)), - ).pipe( - Effect.tap((evt) => - Effect.sync(() => { - expect(evt.file).toBe(head) - expect(["add", "change"]).toContain(evt.event) - }), - ), - ), - ) - }) + it.instance( + "ignores .git/index changes", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const fs = yield* AppFileSystem.Service + const git = yield* Git.Service + const gitIndex = path.join(test.directory, ".git", "index") + const edit = path.join(test.directory, "tracked.txt") + + yield* withWatcher( + test.directory, + noUpdate( + test.directory, + (e) => e.file === gitIndex, + fs.writeFileString(edit, "a").pipe(Effect.andThen(git.run(["add", "."], { cwd: test.directory }))), + ), + ) + }), + { git: true }, + ) + + it.instance( + "publishes .git/HEAD events", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const fs = yield* AppFileSystem.Service + const git = yield* Git.Service + const head = path.join(test.directory, ".git", "HEAD") + const branch = `watch-${Math.random().toString(36).slice(2)}` + yield* git.run(["branch", branch], { cwd: test.directory }) + + yield* withWatcher( + test.directory, + nextUpdate( + test.directory, + (evt) => evt.file === head && evt.event !== "unlink", + fs.writeFileString(head, `ref: refs/heads/${branch}\n`), + ).pipe( + Effect.tap((evt) => + Effect.sync(() => { + expect(evt.file).toBe(head) + expect(["add", "change"]).toContain(evt.event) + }), + ), + ), + ) + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/fixture/fixture.ts b/packages/opencode/test/fixture/fixture.ts index d47620f623..fedbc246bc 100644 --- a/packages/opencode/test/fixture/fixture.ts +++ b/packages/opencode/test/fixture/fixture.ts @@ -135,7 +135,7 @@ export function tmpdirScoped(options?: { git?: boolean; config?: Partial> & { + soundboard?: Partial +} + function themeCurrent(): HostPluginApi["theme"]["current"] { const a = RGBA.fromInts(0, 120, 240) const b = RGBA.fromInts(120, 120, 120) @@ -83,6 +87,8 @@ function themeCurrent(): HostPluginApi["theme"]["current"] { type Opts = { client?: HostPluginApi["client"] | (() => HostPluginApi["client"]) renderer?: HostPluginApi["renderer"] + attention?: AttentionOpts + event?: HostPluginApi["event"] count?: Count keymap?: HostPluginApi["keymap"] tuiConfig?: Partial @@ -183,6 +189,17 @@ export function createTuiPluginApi(opts: Opts = {}): HostPluginApi { return opts.app?.version ?? "0.0.0-test" }, }, + attention: { + async notify(input) { + return opts.attention?.notify?.(input) ?? { ok: false, notification: false, sound: false } + }, + soundboard: { + registerPack: (pack) => opts.attention?.soundboard?.registerPack?.(pack) ?? (() => {}), + activate: (id, options) => opts.attention?.soundboard?.activate?.(id, options) ?? false, + current: () => opts.attention?.soundboard?.current?.() ?? "opencode.default", + list: () => opts.attention?.soundboard?.list?.() ?? [], + }, + }, keys: { formatSequence: () => "", formatBindings: () => undefined, @@ -190,7 +207,7 @@ export function createTuiPluginApi(opts: Opts = {}): HostPluginApi { get client() { return client() }, - event: { + event: opts.event ?? { on: () => { if (count) count.event_add += 1 return () => { diff --git a/packages/opencode/test/fixture/tui-runtime.ts b/packages/opencode/test/fixture/tui-runtime.ts index 64537b6c50..75fc2fdc44 100644 --- a/packages/opencode/test/fixture/tui-runtime.ts +++ b/packages/opencode/test/fixture/tui-runtime.ts @@ -5,7 +5,8 @@ import { TuiConfig } from "../../src/cli/cmd/tui/config/tui" import { TuiKeybind } from "../../src/cli/cmd/tui/config/keybind" type PluginSpec = string | [string, Record] -type ResolvedInput = Omit & { +type ResolvedInput = Omit & { + attention?: Partial keybinds?: Partial leader_timeout?: number } @@ -22,6 +23,15 @@ export function createTuiResolvedConfig(input: ResolvedInput = {}): TuiConfig.Re const keybinds = TuiKeybind.Keybinds.parse(input.keybinds ?? {}) return { ...input, + attention: { + enabled: false, + notifications: true, + sound: true, + volume: 0.4, + sound_pack: "opencode.default", + sounds: {}, + ...input.attention, + }, keybinds: createTuiResolvedKeybinds(keybinds), leader_timeout: input.leader_timeout ?? 2000, } diff --git a/packages/opencode/test/git/git.test.ts b/packages/opencode/test/git/git.test.ts index 1e56865d72..e80b8fa906 100644 --- a/packages/opencode/test/git/git.test.ts +++ b/packages/opencode/test/git/git.test.ts @@ -1,71 +1,70 @@ import { $ } from "bun" -import { describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import fs from "fs/promises" import path from "path" -import { ManagedRuntime } from "effect" +import { Effect } from "effect" import { Git } from "../../src/git" import { tmpdir } from "../fixture/fixture" +import { testEffect } from "../lib/effect" const weird = process.platform === "win32" ? "space file.txt" : "tab\tfile.txt" +const it = testEffect(Git.defaultLayer) -async function withGit(body: (rt: ManagedRuntime.ManagedRuntime) => Promise) { - const rt = ManagedRuntime.make(Git.defaultLayer) - try { - return await body(rt) - } finally { - await rt.dispose() - } -} +const scopedTmpdir = (options?: Parameters[0]) => + Effect.acquireRelease( + Effect.promise(() => tmpdir(options)), + (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), + ) describe("Git", () => { - test("branch() returns current branch name", async () => { - await using tmp = await tmpdir({ git: true }) - - await withGit(async (rt) => { - const branch = await rt.runPromise(Git.Service.use((git) => git.branch(tmp.path))) + it.live("branch() returns current branch name", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir({ git: true }) + const git = yield* Git.Service + const branch = yield* git.branch(tmp.path) expect(branch).toBeDefined() expect(typeof branch).toBe("string") - }) - }) + }), + ) - test("branch() returns undefined for non-git directories", async () => { - await using tmp = await tmpdir() - - await withGit(async (rt) => { - const branch = await rt.runPromise(Git.Service.use((git) => git.branch(tmp.path))) + it.live("branch() returns undefined for non-git directories", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir() + const git = yield* Git.Service + const branch = yield* git.branch(tmp.path) expect(branch).toBeUndefined() - }) - }) + }), + ) - test("branch() returns undefined for detached HEAD", async () => { - await using tmp = await tmpdir({ git: true }) - const hash = (await $`git rev-parse HEAD`.cwd(tmp.path).quiet().text()).trim() - await $`git checkout --detach ${hash}`.cwd(tmp.path).quiet() - - await withGit(async (rt) => { - const branch = await rt.runPromise(Git.Service.use((git) => git.branch(tmp.path))) + it.live("branch() returns undefined for detached HEAD", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir({ git: true }) + const hash = (yield* Effect.promise(() => $`git rev-parse HEAD`.cwd(tmp.path).quiet().text())).trim() + yield* Effect.promise(() => $`git checkout --detach ${hash}`.cwd(tmp.path).quiet()) + const git = yield* Git.Service + const branch = yield* git.branch(tmp.path) expect(branch).toBeUndefined() - }) - }) + }), + ) - test("defaultBranch() uses init.defaultBranch when available", async () => { - await using tmp = await tmpdir({ git: true }) - await $`git branch -M trunk`.cwd(tmp.path).quiet() - await $`git config init.defaultBranch trunk`.cwd(tmp.path).quiet() - - await withGit(async (rt) => { - const branch = await rt.runPromise(Git.Service.use((git) => git.defaultBranch(tmp.path))) + it.live("defaultBranch() uses init.defaultBranch when available", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir({ git: true }) + yield* Effect.promise(() => $`git branch -M trunk`.cwd(tmp.path).quiet()) + yield* Effect.promise(() => $`git config init.defaultBranch trunk`.cwd(tmp.path).quiet()) + const git = yield* Git.Service + const branch = yield* git.defaultBranch(tmp.path) expect(branch?.name).toBe("trunk") expect(branch?.ref).toBe("trunk") - }) - }) + }), + ) - test("status() handles special filenames", async () => { - await using tmp = await tmpdir({ git: true }) - await fs.writeFile(path.join(tmp.path, weird), "hello\n", "utf-8") - - await withGit(async (rt) => { - const status = await rt.runPromise(Git.Service.use((git) => git.status(tmp.path))) + it.live("status() handles special filenames", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir({ git: true }) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "hello\n", "utf-8")) + const git = yield* Git.Service + const status = yield* git.status(tmp.path) expect(status).toEqual( expect.arrayContaining([ expect.objectContaining({ @@ -74,23 +73,24 @@ describe("Git", () => { }), ]), ) - }) - }) + }), + ) - test("diff(), stats(), and mergeBase() parse tracked changes", async () => { - await using tmp = await tmpdir({ git: true }) - await $`git branch -M main`.cwd(tmp.path).quiet() - await fs.writeFile(path.join(tmp.path, weird), "before\n", "utf-8") - await $`git add .`.cwd(tmp.path).quiet() - await $`git commit --no-gpg-sign -m "add file"`.cwd(tmp.path).quiet() - await $`git checkout -b feature/test`.cwd(tmp.path).quiet() - await fs.writeFile(path.join(tmp.path, weird), "after\n", "utf-8") + it.live("diff(), stats(), and mergeBase() parse tracked changes", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir({ git: true }) + yield* Effect.promise(() => $`git branch -M main`.cwd(tmp.path).quiet()) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "before\n", "utf-8")) + yield* Effect.promise(() => $`git add .`.cwd(tmp.path).quiet()) + yield* Effect.promise(() => $`git commit --no-gpg-sign -m "add file"`.cwd(tmp.path).quiet()) + yield* Effect.promise(() => $`git checkout -b feature/test`.cwd(tmp.path).quiet()) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "after\n", "utf-8")) - await withGit(async (rt) => { - const [base, diff, stats] = await Promise.all([ - rt.runPromise(Git.Service.use((git) => git.mergeBase(tmp.path, "main"))), - rt.runPromise(Git.Service.use((git) => git.diff(tmp.path, "HEAD"))), - rt.runPromise(Git.Service.use((git) => git.stats(tmp.path, "HEAD"))), + const git = yield* Git.Service + const [base, diff, stats] = yield* Effect.all([ + git.mergeBase(tmp.path, "main"), + git.diff(tmp.path, "HEAD"), + git.stats(tmp.path, "HEAD"), ]) expect(base).toBeTruthy() @@ -111,23 +111,24 @@ describe("Git", () => { }), ]), ) - }) - }) + }), + ) - test("patch() returns capped native patch output", async () => { - await using tmp = await tmpdir({ git: true }) - await fs.writeFile(path.join(tmp.path, weird), "before\n", "utf-8") - await fs.writeFile(path.join(tmp.path, "other.txt"), "old\n", "utf-8") - await $`git add .`.cwd(tmp.path).quiet() - await $`git commit --no-gpg-sign -m "add file"`.cwd(tmp.path).quiet() - await fs.writeFile(path.join(tmp.path, weird), "after\n", "utf-8") - await fs.writeFile(path.join(tmp.path, "other.txt"), "new\n", "utf-8") + it.live("patch() returns capped native patch output", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir({ git: true }) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "before\n", "utf-8")) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "other.txt"), "old\n", "utf-8")) + yield* Effect.promise(() => $`git add .`.cwd(tmp.path).quiet()) + yield* Effect.promise(() => $`git commit --no-gpg-sign -m "add file"`.cwd(tmp.path).quiet()) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "after\n", "utf-8")) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "other.txt"), "new\n", "utf-8")) - await withGit(async (rt) => { - const [patch, all, capped] = await Promise.all([ - rt.runPromise(Git.Service.use((git) => git.patch(tmp.path, "HEAD", weird, { context: 2_147_483_647 }))), - rt.runPromise(Git.Service.use((git) => git.patchAll(tmp.path, "HEAD", { context: 2_147_483_647 }))), - rt.runPromise(Git.Service.use((git) => git.patch(tmp.path, "HEAD", weird, { maxOutputBytes: 1 }))), + const git = yield* Git.Service + const [patch, all, capped] = yield* Effect.all([ + git.patch(tmp.path, "HEAD", weird, { context: 2_147_483_647 }), + git.patchAll(tmp.path, "HEAD", { context: 2_147_483_647 }), + git.patch(tmp.path, "HEAD", weird, { maxOutputBytes: 1 }), ]) expect(patch.truncated).toBe(false) @@ -140,17 +141,18 @@ describe("Git", () => { expect(all.text).toContain("+new") expect(capped.truncated).toBe(true) expect(capped.text).toBe("") - }) - }) + }), + ) - test("patchUntracked() and statUntracked() handle added files", async () => { - await using tmp = await tmpdir({ git: true }) - await fs.writeFile(path.join(tmp.path, weird), "one\ntwo\n", "utf-8") + it.live("patchUntracked() and statUntracked() handle added files", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir({ git: true }) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "one\ntwo\n", "utf-8")) - await withGit(async (rt) => { - const [patch, stat] = await Promise.all([ - rt.runPromise(Git.Service.use((git) => git.patchUntracked(tmp.path, weird, { context: 2_147_483_647 }))), - rt.runPromise(Git.Service.use((git) => git.statUntracked(tmp.path, weird))), + const git = yield* Git.Service + const [patch, stat] = yield* Effect.all([ + git.patchUntracked(tmp.path, weird, { context: 2_147_483_647 }), + git.statUntracked(tmp.path, weird), ]) expect(patch.truncated).toBe(false) @@ -158,18 +160,19 @@ describe("Git", () => { expect(patch.text).toContain("+one") expect(patch.text).toContain("+two") expect(stat).toEqual(expect.objectContaining({ file: weird, additions: 2, deletions: 0 })) - }) - }) + }), + ) - test("show() returns empty text for binary blobs", async () => { - await using tmp = await tmpdir({ git: true }) - await fs.writeFile(path.join(tmp.path, "bin.dat"), new Uint8Array([0, 1, 2, 3])) - await $`git add .`.cwd(tmp.path).quiet() - await $`git commit --no-gpg-sign -m "add binary"`.cwd(tmp.path).quiet() + it.live("show() returns empty text for binary blobs", () => + Effect.gen(function* () { + const tmp = yield* scopedTmpdir({ git: true }) + yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "bin.dat"), new Uint8Array([0, 1, 2, 3]))) + yield* Effect.promise(() => $`git add .`.cwd(tmp.path).quiet()) + yield* Effect.promise(() => $`git commit --no-gpg-sign -m "add binary"`.cwd(tmp.path).quiet()) - await withGit(async (rt) => { - const text = await rt.runPromise(Git.Service.use((git) => git.show(tmp.path, "HEAD", "bin.dat"))) + const git = yield* Git.Service + const text = yield* git.show(tmp.path, "HEAD", "bin.dat") expect(text).toBe("") - }) - }) + }), + ) }) diff --git a/packages/opencode/test/installation/installation.test.ts b/packages/opencode/test/installation/installation.test.ts index 5b26b05655..8193ab8d10 100644 --- a/packages/opencode/test/installation/installation.test.ts +++ b/packages/opencode/test/installation/installation.test.ts @@ -1,9 +1,11 @@ -import { describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import { Effect, Layer, Stream } from "effect" import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { Installation } from "../../src/installation" import { InstallationChannel } from "@opencode-ai/core/installation/version" +import { AppProcess } from "@opencode-ai/core/process" +import { testEffect } from "../lib/effect" const encoder = new TextEncoder() @@ -46,91 +48,90 @@ function testLayer( httpHandler: (request: HttpClientRequest.HttpClientRequest) => Response, spawnHandler?: (cmd: string, args: readonly string[]) => string, ) { - return Installation.layer.pipe(Layer.provide(mockHttpClient(httpHandler)), Layer.provide(mockSpawner(spawnHandler))) + const appProcess = AppProcess.layer.pipe(Layer.provide(mockSpawner(spawnHandler))) + return Installation.layer.pipe(Layer.provide(mockHttpClient(httpHandler)), Layer.provide(appProcess)) } describe("installation", () => { describe("latest", () => { - test("reads release version from GitHub releases", async () => { - const layer = testLayer(() => jsonResponse({ tag_name: "v1.2.3" })) + testEffect(testLayer(() => jsonResponse({ tag_name: "v1.2.3" }))).effect( + "reads release version from GitHub releases", + () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("unknown")) + expect(result).toBe("1.2.3") + }), + ) - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("unknown")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("1.2.3") - }) + testEffect(testLayer(() => jsonResponse({ tag_name: "v4.0.0-beta.1" }))).effect( + "strips v prefix from GitHub release tag", + () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("curl")) + expect(result).toBe("4.0.0-beta.1") + }), + ) - test("strips v prefix from GitHub release tag", async () => { - const layer = testLayer(() => jsonResponse({ tag_name: "v4.0.0-beta.1" })) - - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("curl")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("4.0.0-beta.1") - }) - - test("reads npm versions via registry", async () => { - const calls: string[] = [] - const layer = testLayer((request) => { - calls.push(request.url) + const npmCalls: string[] = [] + testEffect( + testLayer((request) => { + npmCalls.push(request.url) return jsonResponse({ version: "1.5.0" }) - }) + }), + ).effect("reads npm versions via registry", () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("npm")) + expect(result).toBe("1.5.0") + expect(npmCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) + }), + ) - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("npm")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("1.5.0") - expect(calls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) - }) - - test("reads bun versions via registry", async () => { - const calls: string[] = [] - const layer = testLayer((request) => { - calls.push(request.url) + const bunCalls: string[] = [] + testEffect( + testLayer((request) => { + bunCalls.push(request.url) return jsonResponse({ version: "1.6.0" }) - }) + }), + ).effect("reads bun versions via registry", () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("bun")) + expect(result).toBe("1.6.0") + expect(bunCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) + }), + ) - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("bun")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("1.6.0") - expect(calls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) - }) - - test("reads pnpm versions via registry", async () => { - const calls: string[] = [] - const layer = testLayer((request) => { - calls.push(request.url) + const pnpmCalls: string[] = [] + testEffect( + testLayer((request) => { + pnpmCalls.push(request.url) return jsonResponse({ version: "1.7.0" }) - }) + }), + ).effect("reads pnpm versions via registry", () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("pnpm")) + expect(result).toBe("1.7.0") + expect(pnpmCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) + }), + ) - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("pnpm")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("1.7.0") - expect(calls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) - }) + testEffect(testLayer(() => jsonResponse({ version: "2.3.4" }))).effect("reads scoop manifest versions", () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("scoop")) + expect(result).toBe("2.3.4") + }), + ) - test("reads scoop manifest versions", async () => { - const layer = testLayer(() => jsonResponse({ version: "2.3.4" })) + testEffect(testLayer(() => jsonResponse({ d: { results: [{ Version: "3.4.5" }] } }))).effect( + "reads chocolatey feed versions", + () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("choco")) + expect(result).toBe("3.4.5") + }), + ) - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("scoop")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("2.3.4") - }) - - test("reads chocolatey feed versions", async () => { - const layer = testLayer(() => jsonResponse({ d: { results: [{ Version: "3.4.5" }] } })) - - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("choco")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("3.4.5") - }) - - test("reads brew formulae API versions", async () => { - const layer = testLayer( + testEffect( + testLayer( () => jsonResponse({ versions: { stable: "2.0.0" } }), (cmd, args) => { // getBrewFormula: return core formula (no tap) @@ -138,31 +139,31 @@ describe("installation", () => { if (cmd === "brew" && args.includes("--formula") && args.includes("opencode")) return "opencode" return "" }, - ) + ), + ).effect("reads brew formulae API versions", () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("brew")) + expect(result).toBe("2.0.0") + }), + ) - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("brew")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("2.0.0") + const brewInfoJson = JSON.stringify({ + formulae: [{ versions: { stable: "2.1.0" } }], }) - - test("reads brew tap info JSON via CLI", async () => { - const brewInfoJson = JSON.stringify({ - formulae: [{ versions: { stable: "2.1.0" } }], - }) - const layer = testLayer( + testEffect( + testLayer( () => jsonResponse({}), // HTTP not used for tap formula (cmd, args) => { if (cmd === "brew" && args.includes("anomalyco/tap/opencode") && args.includes("--formula")) return "opencode" if (cmd === "brew" && args.includes("--json=v2")) return brewInfoJson return "" }, - ) - - const result = await Effect.runPromise( - Installation.Service.use((svc) => svc.latest("brew")).pipe(Effect.provide(layer)), - ) - expect(result).toBe("2.1.0") - }) + ), + ).effect("reads brew tap info JSON via CLI", () => + Effect.gen(function* () { + const result = yield* Installation.Service.use((svc) => svc.latest("brew")) + expect(result).toBe("2.1.0") + }), + ) }) }) diff --git a/packages/opencode/test/mcp/headers.test.ts b/packages/opencode/test/mcp/headers.test.ts index 5bc8f803d2..c51ed00d32 100644 --- a/packages/opencode/test/mcp/headers.test.ts +++ b/packages/opencode/test/mcp/headers.test.ts @@ -1,6 +1,6 @@ -import { test, expect, mock, beforeEach } from "bun:test" +import { describe, expect, mock, beforeEach } from "bun:test" import { Effect } from "effect" -import type { MCP as MCPNS } from "../../src/mcp/index" +import { testEffect } from "../lib/effect" // Track what options were passed to each transport constructor const transportCalls: Array<{ @@ -46,53 +46,22 @@ beforeEach(() => { // Import MCP after mocking const { MCP } = await import("../../src/mcp/index") -const { AppRuntime } = await import("../../src/effect/app-runtime") -const { Instance } = await import("../../src/project/instance") -const { WithInstance } = await import("../../src/project/with-instance") -const { tmpdir } = await import("../fixture/fixture") -const service = MCP.Service as unknown as Effect.Effect +const it = testEffect(MCP.defaultLayer) -test("headers are passed to transports when oauth is enabled (default)", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - `${dir}/opencode.json`, - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - mcp: { - "test-server": { - type: "remote", - url: "https://example.com/mcp", - headers: { - Authorization: "Bearer test-token", - "X-Custom-Header": "custom-value", - }, - }, +describe("mcp.headers", () => { + it.instance("headers are passed to transports when oauth is enabled (default)", () => + Effect.gen(function* () { + const mcp = yield* MCP.Service + yield* mcp + .add("test-server", { + type: "remote", + url: "https://example.com/mcp", + headers: { + Authorization: "Bearer test-token", + "X-Custom-Header": "custom-value", }, - }), - ) - }, - }) - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - // Trigger MCP initialization - it will fail to connect but we can check the transport options - await AppRuntime.runPromise( - Effect.gen(function* () { - const mcp = yield* service - yield* mcp - .add("test-server", { - type: "remote", - url: "https://example.com/mcp", - headers: { - Authorization: "Bearer test-token", - "X-Custom-Header": "custom-value", - }, - }) - .pipe(Effect.catch(() => Effect.void)) - }), - ) + }) + .pipe(Effect.catch(() => Effect.void)) // Both transports should have been created with headers expect(transportCalls.length).toBeGreaterThanOrEqual(1) @@ -106,33 +75,22 @@ test("headers are passed to transports when oauth is enabled (default)", async ( // OAuth should be enabled by default, so authProvider should exist expect(call.options.authProvider).toBeDefined() } - }, - }) -}) + }), + ) -test("headers are passed to transports when oauth is explicitly disabled", async () => { - await using tmp = await tmpdir() - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - transportCalls.length = 0 - - await AppRuntime.runPromise( - Effect.gen(function* () { - const mcp = yield* service - yield* mcp - .add("test-server-no-oauth", { - type: "remote", - url: "https://example.com/mcp", - oauth: false, - headers: { - Authorization: "Bearer test-token", - }, - }) - .pipe(Effect.catch(() => Effect.void)) - }), - ) + it.instance("headers are passed to transports when oauth is explicitly disabled", () => + Effect.gen(function* () { + const mcp = yield* MCP.Service + yield* mcp + .add("test-server-no-oauth", { + type: "remote", + url: "https://example.com/mcp", + oauth: false, + headers: { + Authorization: "Bearer test-token", + }, + }) + .pipe(Effect.catch(() => Effect.void)) expect(transportCalls.length).toBeGreaterThanOrEqual(1) @@ -144,29 +102,18 @@ test("headers are passed to transports when oauth is explicitly disabled", async // OAuth is disabled, so no authProvider expect(call.options.authProvider).toBeUndefined() } - }, - }) -}) + }), + ) -test("no requestInit when headers are not provided", async () => { - await using tmp = await tmpdir() - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - transportCalls.length = 0 - - await AppRuntime.runPromise( - Effect.gen(function* () { - const mcp = yield* service - yield* mcp - .add("test-server-no-headers", { - type: "remote", - url: "https://example.com/mcp", - }) - .pipe(Effect.catch(() => Effect.void)) - }), - ) + it.instance("no requestInit when headers are not provided", () => + Effect.gen(function* () { + const mcp = yield* MCP.Service + yield* mcp + .add("test-server-no-headers", { + type: "remote", + url: "https://example.com/mcp", + }) + .pipe(Effect.catch(() => Effect.void)) expect(transportCalls.length).toBeGreaterThanOrEqual(1) @@ -174,6 +121,6 @@ test("no requestInit when headers are not provided", async () => { // No headers means requestInit should be undefined expect(call.options.requestInit).toBeUndefined() } - }, - }) + }), + ) }) diff --git a/packages/opencode/test/mcp/lifecycle.test.ts b/packages/opencode/test/mcp/lifecycle.test.ts index 5afc85e3b5..185086fe60 100644 --- a/packages/opencode/test/mcp/lifecycle.test.ts +++ b/packages/opencode/test/mcp/lifecycle.test.ts @@ -1,7 +1,7 @@ -import { test, expect, mock, beforeEach } from "bun:test" -import { InstanceRuntime } from "../../src/project/instance-runtime" -import { Effect } from "effect" +import { expect, mock, beforeEach } from "bun:test" +import { Effect, Exit } from "effect" import type { MCP as MCPNS } from "../../src/mcp/index" +import { testEffect } from "../lib/effect" // --- Mock infrastructure --- @@ -179,39 +179,9 @@ beforeEach(() => { // Import after mocks const { MCP } = await import("../../src/mcp/index") -const { Instance } = await import("../../src/project/instance") -const { WithInstance } = await import("../../src/project/with-instance") -const { tmpdir } = await import("../fixture/fixture") +const { McpOAuthCallback } = await import("../../src/mcp/oauth-callback") -// --- Helper --- - -function withInstance( - config: Record, - fn: (mcp: MCPNS.Interface) => Effect.Effect, -) { - return async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - `${dir}/opencode.json`, - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - mcp: config, - }), - ) - }, - }) - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await Effect.runPromise(MCP.Service.use(fn).pipe(Effect.provide(MCP.defaultLayer))) - // dispose instance to clean up state between tests - await InstanceRuntime.disposeInstance(Instance.current) - }, - }) - } -} +const it = testEffect(MCP.defaultLayer) function statusName(status: Record | MCPNS.Status, server: string) { if ("status" in status) return status.status @@ -222,82 +192,82 @@ function statusName(status: Record | MCPNS.Status, server: // Test: tools() are cached after connect // ======================================================================== -test( +it.instance( "tools() reuses cached tool definitions after connect", - withInstance({}, (mcp) => - Effect.gen(function* () { - lastCreatedClientName = "my-server" - const serverState = getOrCreateClientState("my-server") - serverState.tools = [ - { name: "do_thing", description: "does a thing", inputSchema: { type: "object", properties: {} } }, - ] + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + lastCreatedClientName = "my-server" + const serverState = getOrCreateClientState("my-server") + serverState.tools = [ + { name: "do_thing", description: "does a thing", inputSchema: { type: "object", properties: {} } }, + ] - // First: add the server successfully - const addResult = yield* mcp.add("my-server", { - type: "local", - command: ["echo", "test"], - }) - expect((addResult.status as any)["my-server"]?.status ?? (addResult.status as any).status).toBe("connected") + // First: add the server successfully + const addResult = yield* mcp.add("my-server", { + type: "local", + command: ["echo", "test"], + }) + expect((addResult.status as any)["my-server"]?.status ?? (addResult.status as any).status).toBe("connected") - expect(serverState.listToolsCalls).toBe(1) + expect(serverState.listToolsCalls).toBe(1) - const toolsA = yield* mcp.tools() - const toolsB = yield* mcp.tools() - expect(Object.keys(toolsA).length).toBeGreaterThan(0) - expect(Object.keys(toolsB).length).toBeGreaterThan(0) - expect(serverState.listToolsCalls).toBe(1) - }), - ), + const toolsA = yield* mcp.tools() + const toolsB = yield* mcp.tools() + expect(Object.keys(toolsA).length).toBeGreaterThan(0) + expect(Object.keys(toolsB).length).toBeGreaterThan(0) + expect(serverState.listToolsCalls).toBe(1) + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: tool change notifications refresh the cache // ======================================================================== -test( +it.instance( "tool change notifications refresh cached tool definitions", - withInstance({}, (mcp) => - Effect.gen(function* () { - lastCreatedClientName = "status-server" - const serverState = getOrCreateClientState("status-server") + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + lastCreatedClientName = "status-server" + const serverState = getOrCreateClientState("status-server") - yield* mcp.add("status-server", { - type: "local", - command: ["echo", "test"], - }) + yield* mcp.add("status-server", { + type: "local", + command: ["echo", "test"], + }) - const before = yield* mcp.tools() - expect(Object.keys(before).some((key) => key.includes("test_tool"))).toBe(true) - expect(serverState.listToolsCalls).toBe(1) + const before = yield* mcp.tools() + expect(Object.keys(before).some((key) => key.includes("test_tool"))).toBe(true) + expect(serverState.listToolsCalls).toBe(1) - serverState.tools = [{ name: "next_tool", description: "next", inputSchema: { type: "object", properties: {} } }] + serverState.tools = [ + { name: "next_tool", description: "next", inputSchema: { type: "object", properties: {} } }, + ] - const handler = Array.from(serverState.notificationHandlers.values())[0] - expect(handler).toBeDefined() - yield* Effect.promise(() => handler?.()) + const handler = Array.from(serverState.notificationHandlers.values())[0] + expect(handler).toBeDefined() + yield* Effect.promise(() => handler?.()) - const after = yield* mcp.tools() - expect(Object.keys(after).some((key) => key.includes("next_tool"))).toBe(true) - expect(Object.keys(after).some((key) => key.includes("test_tool"))).toBe(false) - expect(serverState.listToolsCalls).toBe(2) - }), - ), + const after = yield* mcp.tools() + expect(Object.keys(after).some((key) => key.includes("next_tool"))).toBe(true) + expect(Object.keys(after).some((key) => key.includes("test_tool"))).toBe(false) + expect(serverState.listToolsCalls).toBe(2) + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: connect() / disconnect() lifecycle // ======================================================================== -test( +it.instance( "disconnect sets status to disabled and removes client", - withInstance( - { - "disc-server": { - type: "local", - command: ["echo", "test"], - }, - }, - (mcp) => + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { lastCreatedClientName = "disc-server" getOrCreateClientState("disc-server") @@ -315,24 +285,27 @@ test( const statusAfter = yield* mcp.status() expect(statusAfter["disc-server"]?.status).toBe("disabled") - // Tools should be empty after disconnect const tools = yield* mcp.tools() const serverTools = Object.keys(tools).filter((k) => k.startsWith("disc-server")) expect(serverTools.length).toBe(0) }), - ), -) - -test( - "connect() after disconnect() re-establishes the server", - withInstance( - { - "reconn-server": { - type: "local", - command: ["echo", "test"], + ), + { + config: { + mcp: { + "disc-server": { + type: "local", + command: ["echo", "test"], + }, }, }, - (mcp) => + }, +) + +it.instance( + "connect() after disconnect() re-establishes the server", + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { lastCreatedClientName = "reconn-server" const serverState = getOrCreateClientState("reconn-server") @@ -348,70 +321,71 @@ test( yield* mcp.disconnect("reconn-server") expect((yield* mcp.status())["reconn-server"]?.status).toBe("disabled") - // Reconnect yield* mcp.connect("reconn-server") expect((yield* mcp.status())["reconn-server"]?.status).toBe("connected") const tools = yield* mcp.tools() expect(Object.keys(tools).some((k) => k.includes("my_tool"))).toBe(true) }), - ), + ), + { + config: { + mcp: { + "reconn-server": { + type: "local", + command: ["echo", "test"], + }, + }, + }, + }, ) // ======================================================================== // Test: add() closes existing client before replacing // ======================================================================== -test( +it.instance( "add() closes the old client when replacing a server", // Don't put the server in config — add it dynamically so we control // exactly which client instance is "first" vs "second". - withInstance({}, (mcp) => - Effect.gen(function* () { - lastCreatedClientName = "replace-server" - const firstState = getOrCreateClientState("replace-server") + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + lastCreatedClientName = "replace-server" + const firstState = getOrCreateClientState("replace-server") - yield* mcp.add("replace-server", { - type: "local", - command: ["echo", "test"], - }) + yield* mcp.add("replace-server", { + type: "local", + command: ["echo", "test"], + }) - expect(firstState.closed).toBe(false) + expect(firstState.closed).toBe(false) - // Create new state for second client - clientStates.delete("replace-server") - const secondState = getOrCreateClientState("replace-server") + // Create new state for second client + clientStates.delete("replace-server") + const secondState = getOrCreateClientState("replace-server") - // Re-add should close the first client - yield* mcp.add("replace-server", { - type: "local", - command: ["echo", "test"], - }) + // Re-add should close the first client + yield* mcp.add("replace-server", { + type: "local", + command: ["echo", "test"], + }) - expect(firstState.closed).toBe(true) - expect(secondState.closed).toBe(false) - }), - ), + expect(firstState.closed).toBe(true) + expect(secondState.closed).toBe(false) + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: state init with mixed success/failure // ======================================================================== -test( +it.instance( "init connects available servers even when one fails", - withInstance( - { - "good-server": { - type: "local", - command: ["echo", "good"], - }, - "bad-server": { - type: "local", - command: ["echo", "bad"], - }, - }, - (mcp) => + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { // Set up good server const goodState = getOrCreateClientState("good-server") @@ -443,77 +417,88 @@ test( const tools = yield* mcp.tools() expect(Object.keys(tools).some((k) => k.includes("good_tool"))).toBe(true) }), - ), -) - -test( - "falls back when MCP output schema refs fail SDK tool discovery", - withInstance({}, (mcp) => - Effect.gen(function* () { - lastCreatedClientName = "stitch-like-server" - const serverState = getOrCreateClientState("stitch-like-server") - serverState.listToolsShouldFail = true - serverState.listToolsError = "can't resolve reference #/$defs/ScreenInstance from id #" - serverState.tools = [ - { - name: "render_screen", - description: "renders a screen", - inputSchema: { type: "object", properties: { prompt: { type: "string" } }, required: ["prompt"] }, - outputSchema: { type: "object", properties: { screen: { $ref: "#/$defs/ScreenInstance" } } }, + ), + { + config: { + mcp: { + "good-server": { + type: "local", + command: ["echo", "good"], }, - ] - - const addResult = yield* mcp.add("stitch-like-server", { - type: "local", - command: ["echo", "test"], - }) - - expect(statusName(addResult.status, "stitch-like-server")).toBe("connected") - - const tools = yield* mcp.tools() - expect(Object.keys(tools).some((key) => key.includes("render_screen"))).toBe(true) - expect(serverState.listToolsCalls).toBe(1) - expect(serverState.requestCalls).toBe(1) - }), - ), + "bad-server": { + type: "local", + command: ["echo", "bad"], + }, + }, + }, + }, ) -test( +it.instance( + "falls back when MCP output schema refs fail SDK tool discovery", + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + lastCreatedClientName = "stitch-like-server" + const serverState = getOrCreateClientState("stitch-like-server") + serverState.listToolsShouldFail = true + serverState.listToolsError = "can't resolve reference #/$defs/ScreenInstance from id #" + serverState.tools = [ + { + name: "render_screen", + description: "renders a screen", + inputSchema: { type: "object", properties: { prompt: { type: "string" } }, required: ["prompt"] }, + outputSchema: { type: "object", properties: { screen: { $ref: "#/$defs/ScreenInstance" } } }, + }, + ] + + const addResult = yield* mcp.add("stitch-like-server", { + type: "local", + command: ["echo", "test"], + }) + + expect(statusName(addResult.status, "stitch-like-server")).toBe("connected") + + const tools = yield* mcp.tools() + expect(Object.keys(tools).some((key) => key.includes("render_screen"))).toBe(true) + expect(serverState.listToolsCalls).toBe(1) + expect(serverState.requestCalls).toBe(1) + }), + ), + { config: { mcp: {} } }, +) + +it.instance( "does not fall back for non-schema MCP tool discovery errors", - withInstance({}, (mcp) => - Effect.gen(function* () { - lastCreatedClientName = "broken-server" - const serverState = getOrCreateClientState("broken-server") - serverState.listToolsShouldFail = true - serverState.listToolsError = "transport closed" + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + lastCreatedClientName = "broken-server" + const serverState = getOrCreateClientState("broken-server") + serverState.listToolsShouldFail = true + serverState.listToolsError = "transport closed" - const addResult = yield* mcp.add("broken-server", { - type: "local", - command: ["echo", "test"], - }) + const addResult = yield* mcp.add("broken-server", { + type: "local", + command: ["echo", "test"], + }) - expect(statusName(addResult.status, "broken-server")).toBe("failed") - expect(serverState.listToolsCalls).toBe(1) - expect(serverState.requestCalls).toBe(0) - }), - ), + expect(statusName(addResult.status, "broken-server")).toBe("failed") + expect(serverState.listToolsCalls).toBe(1) + expect(serverState.requestCalls).toBe(0) + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: disabled server via config // ======================================================================== -test( +it.instance( "disabled server is marked as disabled without attempting connection", - withInstance( - { - "disabled-server": { - type: "local", - command: ["echo", "test"], - enabled: false, - }, - }, - (mcp) => + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { const countBefore = clientCreateCount @@ -529,23 +514,28 @@ test( const status = yield* mcp.status() expect(status["disabled-server"]?.status).toBe("disabled") }), - ), + ), + { + config: { + mcp: { + "disabled-server": { + type: "local", + command: ["echo", "test"], + enabled: false, + }, + }, + }, + }, ) // ======================================================================== // Test: prompts() and resources() // ======================================================================== -test( +it.instance( "prompts() returns prompts from connected servers", - withInstance( - { - "prompt-server": { - type: "local", - command: ["echo", "test"], - }, - }, - (mcp) => + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { lastCreatedClientName = "prompt-server" const serverState = getOrCreateClientState("prompt-server") @@ -562,19 +552,23 @@ test( expect(key).toContain("prompt-server") expect(key).toContain("my-prompt") }), - ), -) - -test( - "resources() returns resources from connected servers", - withInstance( - { - "resource-server": { - type: "local", - command: ["echo", "test"], + ), + { + config: { + mcp: { + "prompt-server": { + type: "local", + command: ["echo", "test"], + }, }, }, - (mcp) => + }, +) + +it.instance( + "resources() returns resources from connected servers", + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { lastCreatedClientName = "resource-server" const serverState = getOrCreateClientState("resource-server") @@ -591,19 +585,23 @@ test( expect(key).toContain("resource-server") expect(key).toContain("my-resource") }), - ), -) - -test( - "prompts() skips disconnected servers", - withInstance( - { - "prompt-disc-server": { - type: "local", - command: ["echo", "test"], + ), + { + config: { + mcp: { + "resource-server": { + type: "local", + command: ["echo", "test"], + }, }, }, - (mcp) => + }, +) + +it.instance( + "prompts() skips disconnected servers", + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { lastCreatedClientName = "prompt-disc-server" const serverState = getOrCreateClientState("prompt-disc-server") @@ -619,67 +617,77 @@ test( const prompts = yield* mcp.prompts() expect(Object.keys(prompts).length).toBe(0) }), - ), + ), + { + config: { + mcp: { + "prompt-disc-server": { + type: "local", + command: ["echo", "test"], + }, + }, + }, + }, ) // ======================================================================== // Test: connect() on nonexistent server // ======================================================================== -test( +it.instance( "connect() on nonexistent server does not throw", - withInstance({}, (mcp) => - Effect.gen(function* () { - // Should not throw - yield* mcp.connect("nonexistent") - const status = yield* mcp.status() - expect(status["nonexistent"]).toBeUndefined() - }), - ), + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + // Should not throw + yield* mcp.connect("nonexistent") + const status = yield* mcp.status() + expect(status["nonexistent"]).toBeUndefined() + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: disconnect() on nonexistent server // ======================================================================== -test( +it.instance( "disconnect() on nonexistent server does not throw", - withInstance({}, (mcp) => - Effect.gen(function* () { - yield* mcp.disconnect("nonexistent") - // Should complete without error - }), - ), + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + yield* mcp.disconnect("nonexistent") + // Should complete without error + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: tools() with no MCP servers configured // ======================================================================== -test( +it.instance( "tools() returns empty when no MCP servers are configured", - withInstance({}, (mcp) => - Effect.gen(function* () { - const tools = yield* mcp.tools() - expect(Object.keys(tools).length).toBe(0) - }), - ), + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + const tools = yield* mcp.tools() + expect(Object.keys(tools).length).toBe(0) + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: connect failure during create() // ======================================================================== -test( +it.instance( "server that fails to connect is marked as failed", - withInstance( - { - "fail-connect": { - type: "local", - command: ["echo", "test"], - }, - }, - (mcp) => + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { lastCreatedClientName = "fail-connect" getOrCreateClientState("fail-connect") @@ -701,51 +709,55 @@ test( const tools = yield* mcp.tools() expect(Object.keys(tools).length).toBe(0) }), - ), + ), + { + config: { + mcp: { + "fail-connect": { + type: "local", + command: ["echo", "test"], + }, + }, + }, + }, ) // ======================================================================== // Bug #5: McpOAuthCallback.cancelPending uses wrong key // ======================================================================== -test("McpOAuthCallback.cancelPending is keyed by mcpName but pendingAuths uses oauthState", async () => { - const { McpOAuthCallback } = await import("../../src/mcp/oauth-callback") +it.live("McpOAuthCallback.cancelPending is keyed by mcpName but pendingAuths uses oauthState", () => + Effect.acquireUseRelease( + Effect.sync(() => McpOAuthCallback.waitForCallback("abc123hexstate", "my-mcp-server")), + (callback) => + Effect.gen(function* () { + McpOAuthCallback.cancelPending("my-mcp-server") - // Register a pending auth with an oauthState key, associated to an mcpName - const oauthState = "abc123hexstate" - const callbackPromise = McpOAuthCallback.waitForCallback(oauthState, "my-mcp-server") + const exit = yield* Effect.tryPromise({ + try: () => callback, + catch: (error) => (error instanceof Error ? error : new Error(String(error))), + }).pipe( + Effect.timeoutOrElse({ + duration: "1 second", + orElse: () => Effect.fail(new Error("timed out waiting for OAuth cancellation")), + }), + Effect.exit, + ) - // cancelPending is called with mcpName — should find the entry via reverse index - McpOAuthCallback.cancelPending("my-mcp-server") - - // The callback should still be pending because cancelPending looked up - // "my-mcp-server" in a map keyed by "abc123hexstate" - let rejected = false - callbackPromise.then(() => {}).catch(() => (rejected = true)) - - // Give it a tick - await new Promise((r) => setTimeout(r, 50)) - - // cancelPending("my-mcp-server") should have rejected the pending callback - expect(rejected).toBe(true) - - await McpOAuthCallback.stop() -}) + expect(Exit.isFailure(exit)).toBe(true) + }), + () => Effect.promise(() => McpOAuthCallback.stop()).pipe(Effect.ignore), + ), +) // ======================================================================== // Test: multiple tools from same server get correct name prefixes // ======================================================================== -test( +it.instance( "tools() prefixes tool names with sanitized server name", - withInstance( - { - "my.special-server": { - type: "local", - command: ["echo", "test"], - }, - }, - (mcp) => + () => + MCP.Service.use((mcp: MCPNS.Interface) => Effect.gen(function* () { lastCreatedClientName = "my.special-server" const serverState = getOrCreateClientState("my.special-server") @@ -768,87 +780,103 @@ test( expect(keys.some((k) => k.endsWith("tool_b"))).toBe(true) expect(keys.length).toBe(2) }), - ), + ), + { + config: { + mcp: { + "my.special-server": { + type: "local", + command: ["echo", "test"], + }, + }, + }, + }, ) // ======================================================================== // Test: transport leak — local stdio timeout (#19168) // ======================================================================== -test( +it.instance( "local stdio transport is closed when connect times out (no process leak)", - withInstance({}, (mcp) => - Effect.gen(function* () { - lastCreatedClientName = "hanging-server" - getOrCreateClientState("hanging-server") - connectShouldHang = true + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + lastCreatedClientName = "hanging-server" + getOrCreateClientState("hanging-server") + connectShouldHang = true - const addResult = yield* mcp.add("hanging-server", { - type: "local", - command: ["node", "fake.js"], - timeout: 100, - }) + const addResult = yield* mcp.add("hanging-server", { + type: "local", + command: ["node", "fake.js"], + timeout: 100, + }) - const serverStatus = (addResult.status as any)["hanging-server"] ?? addResult.status - expect(serverStatus.status).toBe("failed") - expect(serverStatus.error).toContain("timed out") - // Transport must be closed to avoid orphaned child process - expect(transportCloseCount).toBeGreaterThanOrEqual(1) - }), - ), + const serverStatus = (addResult.status as any)["hanging-server"] ?? addResult.status + expect(serverStatus.status).toBe("failed") + expect(serverStatus.error).toContain("timed out") + // Transport must be closed to avoid orphaned child process + expect(transportCloseCount).toBeGreaterThanOrEqual(1) + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: transport leak — remote timeout (#19168) // ======================================================================== -test( +it.instance( "remote transport is closed when connect times out", - withInstance({}, (mcp) => - Effect.gen(function* () { - lastCreatedClientName = "hanging-remote" - getOrCreateClientState("hanging-remote") - connectShouldHang = true + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + lastCreatedClientName = "hanging-remote" + getOrCreateClientState("hanging-remote") + connectShouldHang = true - const addResult = yield* mcp.add("hanging-remote", { - type: "remote", - url: "http://localhost:9999/mcp", - timeout: 100, - oauth: false, - }) + const addResult = yield* mcp.add("hanging-remote", { + type: "remote", + url: "http://localhost:9999/mcp", + timeout: 100, + oauth: false, + }) - const serverStatus = (addResult.status as any)["hanging-remote"] ?? addResult.status - expect(serverStatus.status).toBe("failed") - // Transport must be closed to avoid leaked HTTP connections - expect(transportCloseCount).toBeGreaterThanOrEqual(1) - }), - ), + const serverStatus = (addResult.status as any)["hanging-remote"] ?? addResult.status + expect(serverStatus.status).toBe("failed") + // Transport must be closed to avoid leaked HTTP connections + expect(transportCloseCount).toBeGreaterThanOrEqual(1) + }), + ), + { config: { mcp: {} } }, ) // ======================================================================== // Test: transport leak — failed remote transports not closed (#19168) // ======================================================================== -test( +it.instance( "failed remote transport is closed before trying next transport", - withInstance({}, (mcp) => - Effect.gen(function* () { - lastCreatedClientName = "fail-remote" - getOrCreateClientState("fail-remote") - connectShouldFail = true - connectError = "Connection refused" + () => + MCP.Service.use((mcp: MCPNS.Interface) => + Effect.gen(function* () { + lastCreatedClientName = "fail-remote" + getOrCreateClientState("fail-remote") + connectShouldFail = true + connectError = "Connection refused" - const addResult = yield* mcp.add("fail-remote", { - type: "remote", - url: "http://localhost:9999/mcp", - timeout: 5000, - oauth: false, - }) + const addResult = yield* mcp.add("fail-remote", { + type: "remote", + url: "http://localhost:9999/mcp", + timeout: 5000, + oauth: false, + }) - const serverStatus = (addResult.status as any)["fail-remote"] ?? addResult.status - expect(serverStatus.status).toBe("failed") - // Both StreamableHTTP and SSE transports should be closed - expect(transportCloseCount).toBeGreaterThanOrEqual(2) - }), - ), + const serverStatus = (addResult.status as any)["fail-remote"] ?? addResult.status + expect(serverStatus.status).toBe("failed") + // Both StreamableHTTP and SSE transports should be closed + expect(transportCloseCount).toBeGreaterThanOrEqual(2) + }), + ), + { config: { mcp: {} } }, ) diff --git a/packages/opencode/test/mcp/oauth-auto-connect.test.ts b/packages/opencode/test/mcp/oauth-auto-connect.test.ts index 3cf6774215..6fb15c4594 100644 --- a/packages/opencode/test/mcp/oauth-auto-connect.test.ts +++ b/packages/opencode/test/mcp/oauth-auto-connect.test.ts @@ -1,5 +1,6 @@ -import { test, expect, mock, beforeEach } from "bun:test" -import { Effect } from "effect" +import { expect, mock, beforeEach } from "bun:test" +import { Effect, Layer } from "effect" +import { testEffect } from "../lib/effect" // Mock UnauthorizedError to match the SDK's class class MockUnauthorizedError extends Error { @@ -111,172 +112,125 @@ beforeEach(() => { // Import modules after mocking const { MCP } = await import("../../src/mcp/index") -const { Instance } = await import("../../src/project/instance") -const { WithInstance } = await import("../../src/project/with-instance") -const { tmpdir } = await import("../fixture/fixture") +const { Bus } = await import("../../src/bus") +const { Config } = await import("../../src/config/config") +const { McpAuth } = await import("../../src/mcp/auth") +const { McpOAuthProvider } = await import("../../src/mcp/oauth-provider") +const { AppFileSystem } = await import("@opencode-ai/core/filesystem") +const { CrossSpawnSpawner } = await import("@opencode-ai/core/cross-spawn-spawner") -test("first connect to OAuth server shows needs_auth instead of failed", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - `${dir}/opencode.json`, - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - mcp: { - "test-oauth": { - type: "remote", - url: "https://example.com/mcp", - }, - }, - }), - ) +const mcpTest = testEffect( + Layer.mergeAll( + MCP.layer.pipe( + Layer.provide(McpAuth.defaultLayer), + Layer.provideMerge(Bus.layer), + Layer.provide(Config.defaultLayer), + Layer.provide(CrossSpawnSpawner.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + ), + McpAuth.defaultLayer, + ), +) + +const config = (name: string) => ({ + mcp: { + [name]: { + type: "remote" as const, + url: "https://example.com/mcp", }, - }) - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const result = await Effect.runPromise( - MCP.Service.use((mcp) => - mcp.add("test-oauth", { - type: "remote", - url: "https://example.com/mcp", - }), - ).pipe(Effect.provide(MCP.defaultLayer)), - ) - - const serverStatus = result.status as Record - - // The server should be detected as needing auth, NOT as failed. - // Before the fix, provider.state() would throw a plain Error - // ("No OAuth state saved for MCP server: test-oauth") which was - // not caught as UnauthorizedError, causing status to be "failed". - expect(serverStatus["test-oauth"]).toBeDefined() - expect(serverStatus["test-oauth"].status).toBe("needs_auth") - }, - }) + }, }) -test("state() generates a new state when none is saved", async () => { - const { McpOAuthProvider } = await import("../../src/mcp/oauth-provider") - const { McpAuth } = await import("../../src/mcp/auth") +mcpTest.instance( + "first connect to OAuth server shows needs_auth instead of failed", + () => + MCP.Service.use((mcp) => + Effect.gen(function* () { + const result = yield* mcp.add("test-oauth", { + type: "remote", + url: "https://example.com/mcp", + }) - await using tmp = await tmpdir() + const serverStatus = result.status as Record - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const auth = await Effect.runPromise( - Effect.gen(function* () { - return yield* McpAuth.Service - }).pipe(Effect.provide(McpAuth.defaultLayer)), - ) - const provider = new McpOAuthProvider( - "test-state-gen", - "https://example.com/mcp", - {}, - { onRedirect: async () => {} }, - auth, - ) + // The server should be detected as needing auth, NOT as failed. + // Before the fix, provider.state() would throw a plain Error + // ("No OAuth state saved for MCP server: test-oauth") which was + // not caught as UnauthorizedError, causing status to be "failed". + expect(serverStatus["test-oauth"]).toBeDefined() + expect(serverStatus["test-oauth"].status).toBe("needs_auth") + }), + ), + { config: config("test-oauth") }, +) - const entryBefore = await Effect.runPromise( - McpAuth.Service.use((auth) => auth.get("test-state-gen")).pipe(Effect.provide(McpAuth.defaultLayer)), - ) - expect(entryBefore?.oauthState).toBeUndefined() +mcpTest.instance("state() generates a new state when none is saved", () => + Effect.gen(function* () { + const auth = yield* McpAuth.Service + const provider = new McpOAuthProvider( + "test-state-gen", + "https://example.com/mcp", + {}, + { onRedirect: async () => {} }, + auth, + ) - // state() should generate and return a new state, not throw - const state = await provider.state() - expect(typeof state).toBe("string") - expect(state.length).toBe(64) // 32 bytes as hex + const entryBefore = yield* McpAuth.Service.use((auth) => auth.get("test-state-gen")) + expect(entryBefore?.oauthState).toBeUndefined() - // The generated state should be persisted - const entryAfter = await Effect.runPromise( - McpAuth.Service.use((auth) => auth.get("test-state-gen")).pipe(Effect.provide(McpAuth.defaultLayer)), - ) - expect(entryAfter?.oauthState).toBe(state) - }, - }) -}) + // state() should generate and return a new state, not throw + const state = yield* Effect.promise(() => provider.state()) + expect(typeof state).toBe("string") + expect(state.length).toBe(64) // 32 bytes as hex -test("state() returns existing state when one is saved", async () => { - const { McpOAuthProvider } = await import("../../src/mcp/oauth-provider") - const { McpAuth } = await import("../../src/mcp/auth") + // The generated state should be persisted + const entryAfter = yield* McpAuth.Service.use((auth) => auth.get("test-state-gen")) + expect(entryAfter?.oauthState).toBe(state) + }), +) - await using tmp = await tmpdir() +mcpTest.instance("state() returns existing state when one is saved", () => + Effect.gen(function* () { + const auth = yield* McpAuth.Service + const provider = new McpOAuthProvider( + "test-state-existing", + "https://example.com/mcp", + {}, + { onRedirect: async () => {} }, + auth, + ) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const auth = await Effect.runPromise( - Effect.gen(function* () { - return yield* McpAuth.Service - }).pipe(Effect.provide(McpAuth.defaultLayer)), - ) - const provider = new McpOAuthProvider( - "test-state-existing", - "https://example.com/mcp", - {}, - { onRedirect: async () => {} }, - auth, - ) + // Pre-save a state + const existingState = "pre-saved-state-value" + yield* McpAuth.Service.use((auth) => auth.updateOAuthState("test-state-existing", existingState)) - // Pre-save a state - const existingState = "pre-saved-state-value" - await Effect.runPromise( - McpAuth.Service.use((auth) => auth.updateOAuthState("test-state-existing", existingState)).pipe( - Effect.provide(McpAuth.defaultLayer), - ), - ) + // state() should return the existing state + const state = yield* Effect.promise(() => provider.state()) + expect(state).toBe(existingState) + }), +) - // state() should return the existing state - const state = await provider.state() - expect(state).toBe(existingState) - }, - }) -}) +mcpTest.instance( + "authenticate() stores a connected client when auth completes without redirect", + () => + MCP.Service.use((mcp) => + Effect.gen(function* () { + const added = yield* mcp.add("test-oauth-connect", { + type: "remote", + url: "https://example.com/mcp", + }) + const before = added.status as Record + expect(before["test-oauth-connect"]?.status).toBe("needs_auth") -test("authenticate() stores a connected client when auth completes without redirect", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - `${dir}/opencode.json`, - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - mcp: { - "test-oauth-connect": { - type: "remote", - url: "https://example.com/mcp", - }, - }, - }), - ) - }, - }) + simulateAuthFlow = false + connectSucceedsImmediately = true - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await Effect.runPromise( - MCP.Service.use((mcp) => - Effect.gen(function* () { - const added = yield* mcp.add("test-oauth-connect", { - type: "remote", - url: "https://example.com/mcp", - }) - const before = added.status as Record - expect(before["test-oauth-connect"]?.status).toBe("needs_auth") + const result = yield* mcp.authenticate("test-oauth-connect") + expect(result.status).toBe("connected") - simulateAuthFlow = false - connectSucceedsImmediately = true - - const result = yield* mcp.authenticate("test-oauth-connect") - expect(result.status).toBe("connected") - - const after = yield* mcp.status() - expect(after["test-oauth-connect"]?.status).toBe("connected") - }), - ).pipe(Effect.provide(MCP.defaultLayer)), - ) - }, - }) -}) + const after = yield* mcp.status() + expect(after["test-oauth-connect"]?.status).toBe("connected") + }), + ), + { config: config("test-oauth-connect") }, +) diff --git a/packages/opencode/test/mcp/oauth-browser.test.ts b/packages/opencode/test/mcp/oauth-browser.test.ts index 20cb90a18e..f6222de43d 100644 --- a/packages/opencode/test/mcp/oauth-browser.test.ts +++ b/packages/opencode/test/mcp/oauth-browser.test.ts @@ -1,15 +1,19 @@ -import { test, expect, mock, beforeEach } from "bun:test" +import { expect, mock, beforeEach } from "bun:test" import { EventEmitter } from "events" -import { Effect } from "effect" +import { Deferred, Effect, Layer, Option } from "effect" +import type { Duration } from "effect" +import { testEffect } from "../lib/effect" import type { MCP as MCPNS } from "../../src/mcp/index" // Track open() calls and control failure behavior let openShouldFail = false let openCalledWith: string | undefined +let openDeferred: Deferred.Deferred | undefined void mock.module("open", () => ({ default: async (url: string) => { openCalledWith = url + if (openDeferred) Effect.runSync(Deferred.succeed(openDeferred, url).pipe(Effect.ignore)) // Return a mock subprocess that emits an error if openShouldFail is true const subprocess = new EventEmitter() @@ -97,173 +101,135 @@ void mock.module("@modelcontextprotocol/sdk/client/auth.js", () => ({ beforeEach(() => { openShouldFail = false openCalledWith = undefined + openDeferred = undefined transportCalls.length = 0 }) // Import modules after mocking const { MCP } = await import("../../src/mcp/index") -const { AppRuntime } = await import("../../src/effect/app-runtime") const { Bus } = await import("../../src/bus") +const { Config } = await import("../../src/config/config") +const { McpAuth } = await import("../../src/mcp/auth") const { McpOAuthCallback } = await import("../../src/mcp/oauth-callback") -const { Instance } = await import("../../src/project/instance") -const { WithInstance } = await import("../../src/project/with-instance") -const { tmpdir } = await import("../fixture/fixture") +const { AppFileSystem } = await import("@opencode-ai/core/filesystem") +const { CrossSpawnSpawner } = await import("@opencode-ai/core/cross-spawn-spawner") +const mcpTest = testEffect( + MCP.layer.pipe( + Layer.provide(McpAuth.defaultLayer), + Layer.provideMerge(Bus.layer), + Layer.provide(Config.defaultLayer), + Layer.provide(CrossSpawnSpawner.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + ), +) const service = MCP.Service as unknown as Effect.Effect -test("BrowserOpenFailed event is published when open() throws", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - `${dir}/opencode.json`, - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - mcp: { - "test-oauth-server": { - type: "remote", - url: "https://example.com/mcp", - }, - }, - }), - ) +const config = (name: string) => ({ + mcp: { + [name]: { + type: "remote" as const, + url: "https://example.com/mcp", }, + }, +}) + +const withCallbackStop = Effect.addFinalizer(() => Effect.promise(() => McpOAuthCallback.stop()).pipe(Effect.ignore)) + +const awaitWithTimeout = ( + self: Effect.Effect, + message: string, + duration: Duration.Input = "5 seconds", +) => + self.pipe( + Effect.timeoutOrElse({ + duration, + orElse: () => Effect.fail(new Error(message)), + }), + ) + +const trackBrowserOpen = Effect.gen(function* () { + const opened = yield* Deferred.make() + openDeferred = opened + yield* Effect.addFinalizer(() => Effect.sync(() => (openDeferred = undefined))) + return opened +}) + +const trackBrowserOpenFailed = Effect.gen(function* () { + const bus = yield* Bus.Service + const event = yield* Deferred.make<{ mcpName: string; url: string }>() + const unsubscribe = yield* bus.subscribeCallback(MCP.BrowserOpenFailed, (evt) => { + Effect.runSync(Deferred.succeed(event, evt.properties).pipe(Effect.ignore)) + }) + yield* Effect.addFinalizer(() => Effect.sync(unsubscribe)) + return event +}) + +const authenticateScoped = (name: string) => + Effect.gen(function* () { + const mcp = yield* service + yield* mcp.authenticate(name).pipe( + Effect.ignore, + Effect.catchCause(() => Effect.void), + Effect.forkScoped, + ) }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { +mcpTest.instance( + "BrowserOpenFailed event is published when open() throws", + () => + Effect.gen(function* () { + yield* withCallbackStop openShouldFail = true - const events: Array<{ mcpName: string; url: string }> = [] - const unsubscribe = Bus.subscribe(MCP.BrowserOpenFailed, (evt) => { - events.push(evt.properties) - }) + const event = yield* trackBrowserOpenFailed + yield* authenticateScoped("test-oauth-server") - // Run authenticate with a timeout to avoid waiting forever for the callback - // Attach a handler immediately so callback shutdown rejections - // don't show up as unhandled between tests. - const authPromise = AppRuntime.runPromise( - Effect.gen(function* () { - const mcp = yield* service - return yield* mcp.authenticate("test-oauth-server") - }), - ).catch(() => undefined) + const failure = yield* awaitWithTimeout(Deferred.await(event), "Timed out waiting for BrowserOpenFailed event") - // Config.get() can be slow in tests, so give it plenty of time. - await new Promise((resolve) => setTimeout(resolve, 2_000)) + expect(failure.mcpName).toBe("test-oauth-server") + expect(failure.url).toContain("https://") + }), + { config: config("test-oauth-server") }, +) - // Stop the callback server and cancel any pending auth - await McpOAuthCallback.stop() - - await authPromise - - unsubscribe() - - // Verify the BrowserOpenFailed event was published - expect(events.length).toBe(1) - expect(events[0].mcpName).toBe("test-oauth-server") - expect(events[0].url).toContain("https://") - }, - }) -}) - -test("BrowserOpenFailed event is NOT published when open() succeeds", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - `${dir}/opencode.json`, - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - mcp: { - "test-oauth-server-2": { - type: "remote", - url: "https://example.com/mcp", - }, - }, - }), - ) - }, - }) - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { +mcpTest.instance( + "BrowserOpenFailed event is NOT published when open() succeeds", + () => + Effect.gen(function* () { + yield* withCallbackStop openShouldFail = false - const events: Array<{ mcpName: string; url: string }> = [] - const unsubscribe = Bus.subscribe(MCP.BrowserOpenFailed, (evt) => { - events.push(evt.properties) - }) + const opened = yield* trackBrowserOpen + const event = yield* trackBrowserOpenFailed + yield* authenticateScoped("test-oauth-server-2") - // Run authenticate with a timeout to avoid waiting forever for the callback - const authPromise = AppRuntime.runPromise( - Effect.gen(function* () { - const mcp = yield* service - return yield* mcp.authenticate("test-oauth-server-2") - }), - ).catch(() => undefined) + yield* awaitWithTimeout(Deferred.await(opened), "Timed out waiting for open()") + const failure = yield* Deferred.await(event).pipe(Effect.timeoutOption("700 millis")) - // Config.get() can be slow in tests; also covers the ~500ms open() error-detection window. - await new Promise((resolve) => setTimeout(resolve, 2_000)) - - // Stop the callback server and cancel any pending auth - await McpOAuthCallback.stop() - - await authPromise - - unsubscribe() - - // Verify NO BrowserOpenFailed event was published - expect(events.length).toBe(0) - // Verify open() was still called + expect(failure).toEqual(Option.none()) expect(openCalledWith).toBeDefined() - }, - }) -}) + }), + { config: config("test-oauth-server-2") }, +) -test("open() is called with the authorization URL", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - `${dir}/opencode.json`, - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - mcp: { - "test-oauth-server-3": { - type: "remote", - url: "https://example.com/mcp", - }, - }, - }), - ) - }, - }) - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { +mcpTest.instance( + "open() is called with the authorization URL", + () => + Effect.gen(function* () { + yield* withCallbackStop openShouldFail = false openCalledWith = undefined - // Run authenticate with a timeout to avoid waiting forever for the callback - const authPromise = AppRuntime.runPromise( - Effect.gen(function* () { - const mcp = yield* service - return yield* mcp.authenticate("test-oauth-server-3") - }), - ).catch(() => undefined) + const opened = yield* trackBrowserOpen + const event = yield* trackBrowserOpenFailed + yield* authenticateScoped("test-oauth-server-3") - // Config.get() can be slow in tests; also covers the ~500ms open() error-detection window. - await new Promise((resolve) => setTimeout(resolve, 2_000)) + const url = yield* awaitWithTimeout(Deferred.await(opened), "Timed out waiting for open()") + const failure = yield* Deferred.await(event).pipe(Effect.timeoutOption("700 millis")) - // Stop the callback server and cancel any pending auth - await McpOAuthCallback.stop() - - await authPromise - - // Verify open was called with a URL - expect(openCalledWith).toBeDefined() - expect(typeof openCalledWith).toBe("string") - expect(openCalledWith!).toContain("https://") - }, - }) -}) + expect(failure).toEqual(Option.none()) + expect(typeof url).toBe("string") + expect(url).toContain("https://") + }), + { config: config("test-oauth-server-3") }, +) diff --git a/packages/opencode/test/memory/abort-leak-webfetch.ts b/packages/opencode/test/memory/abort-leak-webfetch.ts deleted file mode 100644 index c3197f8dd5..0000000000 --- a/packages/opencode/test/memory/abort-leak-webfetch.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { abortAfterAny } from "../../src/util/abort" - -const MB = 1024 * 1024 -const ITERATIONS = 50 - -const heap = () => { - Bun.gc(true) - return process.memoryUsage().heapUsed / MB -} - -const server = Bun.serve({ - port: 0, - fetch() { - return new Response("hello from local", { - headers: { - "content-type": "text/plain", - }, - }) - }, -}) - -const url = `http://127.0.0.1:${server.port}` - -async function run() { - const { signal, clearTimeout } = abortAfterAny(30000, new AbortController().signal) - try { - const response = await fetch(url, { signal }) - await response.text() - } finally { - clearTimeout() - } -} - -try { - await run() - Bun.sleepSync(100) - const baseline = heap() - - for (let i = 0; i < ITERATIONS; i++) { - await run() - } - - Bun.sleepSync(100) - const after = heap() - process.stdout.write(JSON.stringify({ baseline, after, growth: after - baseline })) -} finally { - void server.stop(true) - process.exit(0) -} diff --git a/packages/opencode/test/memory/abort-leak.test.ts b/packages/opencode/test/memory/abort-leak.test.ts deleted file mode 100644 index d30ad45e46..0000000000 --- a/packages/opencode/test/memory/abort-leak.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { describe, test, expect } from "bun:test" -import path from "path" - -const projectRoot = path.join(import.meta.dir, "../..") -const worker = path.join(import.meta.dir, "abort-leak-webfetch.ts") - -const MB = 1024 * 1024 -const ITERATIONS = 50 - -const getHeapMB = () => { - Bun.gc(true) - return process.memoryUsage().heapUsed / MB -} - -describe("memory: abort controller leak", () => { - test("webfetch does not leak memory over many invocations", async () => { - // Measure the abort-timed fetch path in a fresh process so shared tool - // runtime state does not dominate the heap signal. - const proc = Bun.spawn({ - cmd: [process.execPath, worker], - cwd: projectRoot, - stdout: "pipe", - stderr: "pipe", - env: process.env, - }) - - const [code, stdout, stderr] = await Promise.all([ - proc.exited, - new Response(proc.stdout).text(), - new Response(proc.stderr).text(), - ]) - - if (code !== 0) { - throw new Error(stderr.trim() || stdout.trim() || `worker exited with code ${code}`) - } - - const result = JSON.parse(stdout.trim()) as { - baseline: number - after: number - growth: number - } - - console.log(`Baseline: ${result.baseline.toFixed(2)} MB`) - console.log(`After ${ITERATIONS} fetches: ${result.after.toFixed(2)} MB`) - console.log(`Growth: ${result.growth.toFixed(2)} MB`) - - // Memory growth should be minimal - less than 1MB per 10 requests. - expect(result.growth).toBeLessThan(ITERATIONS / 10) - }, 60000) - - test("compare closure vs bind pattern directly", async () => { - const ITERATIONS = 500 - - // Test OLD pattern: arrow function closure - // Store closures in a map keyed by content to force retention - const closureMap = new Map void>() - const timers: Timer[] = [] - const controllers: AbortController[] = [] - - Bun.gc(true) - Bun.sleepSync(100) - const baseline = getHeapMB() - - for (let i = 0; i < ITERATIONS; i++) { - // Simulate large response body like webfetch would have - const content = `${i}:${"x".repeat(50 * 1024)}` // 50KB unique per iteration - const controller = new AbortController() - controllers.push(controller) - - // OLD pattern - closure captures `content` - const handler = () => { - // Actually use content so it can't be optimized away - if (content.length > 1000000000) controller.abort() - } - closureMap.set(content, handler) - const timeoutId = setTimeout(handler, 30000) - timers.push(timeoutId) - } - - Bun.gc(true) - Bun.sleepSync(100) - const after = getHeapMB() - const oldGrowth = after - baseline - - console.log(`OLD pattern (closure): ${oldGrowth.toFixed(2)} MB growth (${closureMap.size} closures)`) - - // Cleanup after measuring - timers.forEach(clearTimeout) - controllers.forEach((c) => c.abort()) - closureMap.clear() - - // Test NEW pattern: bind - Bun.gc(true) - Bun.sleepSync(100) - const baseline2 = getHeapMB() - const handlers2: (() => void)[] = [] - const timers2: Timer[] = [] - const controllers2: AbortController[] = [] - - for (let i = 0; i < ITERATIONS; i++) { - const _content = `${i}:${"x".repeat(50 * 1024)}` // 50KB - won't be captured - const controller = new AbortController() - controllers2.push(controller) - - // NEW pattern - bind doesn't capture surrounding scope - const handler = controller.abort.bind(controller) - handlers2.push(handler) - const timeoutId = setTimeout(handler, 30000) - timers2.push(timeoutId) - } - - Bun.gc(true) - Bun.sleepSync(100) - const after2 = getHeapMB() - const newGrowth = after2 - baseline2 - - // Cleanup after measuring - timers2.forEach(clearTimeout) - controllers2.forEach((c) => c.abort()) - handlers2.length = 0 - - console.log(`NEW pattern (bind): ${newGrowth.toFixed(2)} MB growth`) - console.log(`Improvement: ${(oldGrowth - newGrowth).toFixed(2)} MB saved`) - - expect(newGrowth).toBeLessThanOrEqual(oldGrowth) - }) -}) diff --git a/packages/opencode/test/permission-task.test.ts b/packages/opencode/test/permission-task.test.ts index 64b93bb8bc..f2084b095d 100644 --- a/packages/opencode/test/permission-task.test.ts +++ b/packages/opencode/test/permission-task.test.ts @@ -1,16 +1,12 @@ -import { afterEach, describe, test, expect } from "bun:test" +import { describe, test, expect } from "bun:test" +import { Effect } from "effect" import { Permission } from "../src/permission" import { Config } from "@/config/config" -import { Instance } from "../src/project/instance" -import { WithInstance } from "../src/project/with-instance" -import { disposeAllInstances, tmpdir } from "./fixture/fixture" -import { AppRuntime } from "../src/effect/app-runtime" +import { testEffect } from "./lib/effect" -const load = () => AppRuntime.runPromise(Config.Service.use((svc) => svc.get())) +const it = testEffect(Config.defaultLayer) -afterEach(async () => { - await disposeAllInstances() -}) +const load = Config.Service.use((svc) => svc.get()) describe("Permission.evaluate for permission.task", () => { const createRuleset = (rules: Record): Permission.Ruleset => @@ -147,8 +143,18 @@ describe("Permission.disabled for task tool", () => { // Integration tests that load permissions from real config files describe("permission.task with real config files", () => { - test("loads task permissions from opencode.json config", async () => { - await using tmp = await tmpdir({ + it.instance( + "loads task permissions from opencode.json config", + () => + Effect.gen(function* () { + const config = yield* load + const ruleset = Permission.fromConfig(config.permission ?? {}) + // general and orchestrator-fast should be allowed, code-reviewer denied + expect(Permission.evaluate("task", "general", ruleset).action).toBe("allow") + expect(Permission.evaluate("task", "orchestrator-fast", ruleset).action).toBe("allow") + expect(Permission.evaluate("task", "code-reviewer", ruleset).action).toBe("deny") + }), + { git: true, config: { permission: { @@ -158,22 +164,21 @@ describe("permission.task with real config files", () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const config = await load() - const ruleset = Permission.fromConfig(config.permission ?? {}) - // general and orchestrator-fast should be allowed, code-reviewer denied - expect(Permission.evaluate("task", "general", ruleset).action).toBe("allow") - expect(Permission.evaluate("task", "orchestrator-fast", ruleset).action).toBe("allow") - expect(Permission.evaluate("task", "code-reviewer", ruleset).action).toBe("deny") - }, - }) - }) + }, + ) - test("loads task permissions with wildcard patterns from config", async () => { - await using tmp = await tmpdir({ + it.instance( + "loads task permissions with wildcard patterns from config", + () => + Effect.gen(function* () { + const config = yield* load + const ruleset = Permission.fromConfig(config.permission ?? {}) + // general and code-reviewer should be ask, orchestrator-* denied + expect(Permission.evaluate("task", "general", ruleset).action).toBe("ask") + expect(Permission.evaluate("task", "code-reviewer", ruleset).action).toBe("ask") + expect(Permission.evaluate("task", "orchestrator-fast", ruleset).action).toBe("deny") + }), + { git: true, config: { permission: { @@ -183,22 +188,21 @@ describe("permission.task with real config files", () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const config = await load() - const ruleset = Permission.fromConfig(config.permission ?? {}) - // general and code-reviewer should be ask, orchestrator-* denied - expect(Permission.evaluate("task", "general", ruleset).action).toBe("ask") - expect(Permission.evaluate("task", "code-reviewer", ruleset).action).toBe("ask") - expect(Permission.evaluate("task", "orchestrator-fast", ruleset).action).toBe("deny") - }, - }) - }) + }, + ) - test("evaluate respects task permission from config", async () => { - await using tmp = await tmpdir({ + it.instance( + "evaluate respects task permission from config", + () => + Effect.gen(function* () { + const config = yield* load + const ruleset = Permission.fromConfig(config.permission ?? {}) + expect(Permission.evaluate("task", "general", ruleset).action).toBe("allow") + expect(Permission.evaluate("task", "code-reviewer", ruleset).action).toBe("deny") + // Unspecified agents default to "ask" + expect(Permission.evaluate("task", "unknown-agent", ruleset).action).toBe("ask") + }), + { git: true, config: { permission: { @@ -208,38 +212,14 @@ describe("permission.task with real config files", () => { }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const config = await load() - const ruleset = Permission.fromConfig(config.permission ?? {}) - expect(Permission.evaluate("task", "general", ruleset).action).toBe("allow") - expect(Permission.evaluate("task", "code-reviewer", ruleset).action).toBe("deny") - // Unspecified agents default to "ask" - expect(Permission.evaluate("task", "unknown-agent", ruleset).action).toBe("ask") - }, - }) - }) + }, + ) - test("mixed permission config with task and other tools", async () => { - await using tmp = await tmpdir({ - git: true, - config: { - permission: { - bash: "allow", - edit: "ask", - task: { - "*": "deny", - general: "allow", - }, - }, - }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const config = await load() + it.instance( + "mixed permission config with task and other tools", + () => + Effect.gen(function* () { + const config = yield* load const ruleset = Permission.fromConfig(config.permission ?? {}) // Verify task permissions @@ -257,27 +237,27 @@ describe("permission.task with real config files", () => { // task is NOT disabled because disabled() uses findLast, and the last rule // matching "task" permission is {pattern: "general", action: "allow"}, not pattern: "*" expect(disabled.has("task")).toBe(false) - }, - }) - }) - - test("task tool disabled when global deny comes last in config", async () => { - await using tmp = await tmpdir({ + }), + { git: true, config: { permission: { + bash: "allow", + edit: "ask", task: { - general: "allow", - "code-reviewer": "allow", "*": "deny", + general: "allow", }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const config = await load() + }, + ) + + it.instance( + "task tool disabled when global deny comes last in config", + () => + Effect.gen(function* () { + const config = yield* load const ruleset = Permission.fromConfig(config.permission ?? {}) // Last matching rule wins - "*" deny is last, so all agents are denied @@ -289,26 +269,26 @@ describe("permission.task with real config files", () => { // and sees pattern: "*" with action: "deny", so task is disabled const disabled = Permission.disabled(["task"], ruleset) expect(disabled.has("task")).toBe(true) - }, - }) - }) - - test("task tool NOT disabled when specific allow comes last in config", async () => { - await using tmp = await tmpdir({ + }), + { git: true, config: { permission: { task: { - "*": "deny", general: "allow", + "code-reviewer": "allow", + "*": "deny", }, }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const config = await load() + }, + ) + + it.instance( + "task tool NOT disabled when specific allow comes last in config", + () => + Effect.gen(function* () { + const config = yield* load const ruleset = Permission.fromConfig(config.permission ?? {}) // Evaluate uses findLast - "general" allow comes after "*" deny @@ -321,7 +301,17 @@ describe("permission.task with real config files", () => { // So the task tool is NOT disabled (even though most subagents are denied) const disabled = Permission.disabled(["task"], ruleset) expect(disabled.has("task")).toBe(false) + }), + { + git: true, + config: { + permission: { + task: { + "*": "deny", + general: "allow", + }, + }, }, - }) - }) + }, + ) }) diff --git a/packages/opencode/test/permission/next.test.ts b/packages/opencode/test/permission/next.test.ts index 1c3d6fc563..1b09c36afd 100644 --- a/packages/opencode/test/permission/next.test.ts +++ b/packages/opencode/test/permission/next.test.ts @@ -1,31 +1,26 @@ -import { afterEach, test, expect } from "bun:test" +import { test, expect } from "bun:test" import os from "os" -import { Cause, Effect, Exit, Fiber, Layer } from "effect" +import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect" import { Bus } from "../../src/bus" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { Permission } from "../../src/permission" import { PermissionID } from "../../src/permission/schema" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" -import { InstanceRuntime } from "../../src/project/instance-runtime" -import { - disposeAllInstances, - provideInstance, - provideTmpdirInstance, - reloadTestInstance, - tmpdirScoped, -} from "../fixture/fixture" +import { InstanceBootstrap } from "../../src/project/bootstrap-service" +import { InstanceStore } from "../../src/project/instance-store" +import { TestInstance, tmpdirScoped } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { MessageID, SessionID } from "../../src/session/schema" const bus = Bus.layer -const env = Layer.mergeAll(Permission.layer.pipe(Layer.provide(bus)), bus, CrossSpawnSpawner.defaultLayer) +const noopBootstrap = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void })) +const env = Layer.mergeAll( + Permission.layer.pipe(Layer.provide(bus)), + bus, + CrossSpawnSpawner.defaultLayer, + InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrap)), +) const it = testEffect(env) -afterEach(async () => { - await disposeAllInstances() -}) - const rejectAll = (message?: string) => Effect.gen(function* () { const permission = yield* Permission.Service @@ -41,12 +36,18 @@ const rejectAll = (message?: string) => const waitForPending = (count: number) => Effect.gen(function* () { const permission = yield* Permission.Service - for (let i = 0; i < 100; i++) { - const list = yield* permission.list() - if (list.length === count) return list - yield* Effect.sleep("10 millis") - } - return yield* Effect.fail(new Error(`timed out waiting for ${count} pending permission request(s)`)) + return yield* Effect.gen(function* () { + while (true) { + const list = yield* permission.list() + if (list.length === count) return list + yield* Effect.sleep("10 millis") + } + }).pipe( + Effect.timeoutOrElse({ + duration: "1 second", + orElse: () => Effect.fail(new Error(`timed out waiting for ${count} pending permission request(s)`)), + }), + ) }) const fail = (self: Effect.Effect) => @@ -74,14 +75,6 @@ const list = () => return yield* permission.list() }) -function withDir(options: { git?: boolean } | undefined, self: (dir: string) => Effect.Effect) { - return provideTmpdirInstance(self, options) -} - -function withProvided(dir: string) { - return (self: Effect.Effect) => self.pipe(provideInstance(dir)) -} - // fromConfig tests test("fromConfig - string value becomes wildcard rule", () => { @@ -563,8 +556,9 @@ test("disabled - specific allow overrides wildcard deny", () => { // ask tests -it.live("ask - resolves immediately when action is allow", () => - withDir({ git: true }, () => +it.instance( + "ask - resolves immediately when action is allow", + () => Effect.gen(function* () { const result = yield* ask({ sessionID: SessionID.make("session_test"), @@ -576,11 +570,12 @@ it.live("ask - resolves immediately when action is allow", () => }) expect(result).toBeUndefined() }), - ), + { git: true }, ) -it.live("ask - throws DeniedError when action is deny", () => - withDir({ git: true }, () => +it.instance( + "ask - throws DeniedError when action is deny", + () => Effect.gen(function* () { const err = yield* fail( ask({ @@ -594,11 +589,12 @@ it.live("ask - throws DeniedError when action is deny", () => ) expect(err).toBeInstanceOf(Permission.DeniedError) }), - ), + { git: true }, ) -it.live("ask - stays pending when action is ask", () => - withDir({ git: true }, () => +it.instance( + "ask - stays pending when action is ask", + () => Effect.gen(function* () { const fiber = yield* ask({ sessionID: SessionID.make("session_test"), @@ -613,11 +609,12 @@ it.live("ask - stays pending when action is ask", () => yield* rejectAll() yield* Fiber.await(fiber) }), - ), + { git: true }, ) -it.live("ask - adds request to pending list", () => - withDir({ git: true }, () => +it.instance( + "ask - adds request to pending list", + () => Effect.gen(function* () { const fiber = yield* ask({ sessionID: SessionID.make("session_test"), @@ -649,53 +646,58 @@ it.live("ask - adds request to pending list", () => yield* rejectAll() yield* Fiber.await(fiber) }), - ), + { git: true }, ) -it.live("ask - publishes asked event", () => - withDir({ git: true }, () => +it.instance( + "ask - publishes asked event", + () => Effect.gen(function* () { const bus = yield* Bus.Service - let seen: Permission.Request | undefined + const seen = yield* Deferred.make() const unsub = yield* bus.subscribeCallback(Permission.Event.Asked, (event) => { - seen = event.properties + Deferred.doneUnsafe(seen, Effect.succeed(event.properties)) + }) + yield* Effect.addFinalizer(() => Effect.sync(unsub)) + + const fiber = yield* ask({ + sessionID: SessionID.make("session_test"), + permission: "bash", + patterns: ["ls"], + metadata: { cmd: "ls" }, + always: ["ls"], + tool: { + messageID: MessageID.make("msg_test"), + callID: "call_test", + }, + ruleset: [], + }).pipe(Effect.forkScoped) + + expect(yield* waitForPending(1)).toHaveLength(1) + expect( + yield* Deferred.await(seen).pipe( + Effect.timeoutOrElse({ + duration: "1 second", + orElse: () => Effect.fail(new Error("timed out waiting for permission asked event")), + }), + ), + ).toMatchObject({ + sessionID: SessionID.make("session_test"), + permission: "bash", + patterns: ["ls"], }) - try { - const fiber = yield* ask({ - sessionID: SessionID.make("session_test"), - permission: "bash", - patterns: ["ls"], - metadata: { cmd: "ls" }, - always: ["ls"], - tool: { - messageID: MessageID.make("msg_test"), - callID: "call_test", - }, - ruleset: [], - }).pipe(Effect.forkScoped) - - expect(yield* waitForPending(1)).toHaveLength(1) - expect(seen).toBeDefined() - expect(seen).toMatchObject({ - sessionID: SessionID.make("session_test"), - permission: "bash", - patterns: ["ls"], - }) - - yield* rejectAll() - yield* Fiber.await(fiber) - } finally { - unsub() - } + yield* rejectAll() + yield* Fiber.await(fiber) }), - ), + { git: true }, ) // reply tests -it.live("reply - once resolves the pending ask", () => - withDir({ git: true }, () => +it.instance( + "reply - once resolves the pending ask", + () => Effect.gen(function* () { const fiber = yield* ask({ id: PermissionID.make("per_test1"), @@ -711,11 +713,12 @@ it.live("reply - once resolves the pending ask", () => yield* reply({ requestID: PermissionID.make("per_test1"), reply: "once" }) yield* Fiber.join(fiber) }), - ), + { git: true }, ) -it.live("reply - reject throws RejectedError", () => - withDir({ git: true }, () => +it.instance( + "reply - reject throws RejectedError", + () => Effect.gen(function* () { const fiber = yield* ask({ id: PermissionID.make("per_test2"), @@ -734,11 +737,12 @@ it.live("reply - reject throws RejectedError", () => expect(Exit.isFailure(exit)).toBe(true) if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError) }), - ), + { git: true }, ) -it.live("reply - reject with message throws CorrectedError", () => - withDir({ git: true }, () => +it.instance( + "reply - reject with message throws CorrectedError", + () => Effect.gen(function* () { const fiber = yield* ask({ id: PermissionID.make("per_test2b"), @@ -765,41 +769,43 @@ it.live("reply - reject with message throws CorrectedError", () => expect(String(err)).toContain("Use a safer command") } }), - ), + { git: true }, ) -it.live("reply - always persists approval and resolves", () => - Effect.gen(function* () { - const dir = yield* tmpdirScoped({ git: true }) - const run = withProvided(dir) - const fiber = yield* ask({ - id: PermissionID.make("per_test3"), - sessionID: SessionID.make("session_test"), - permission: "bash", - patterns: ["ls"], - metadata: {}, - always: ["ls"], - ruleset: [], - }).pipe(run, Effect.forkScoped) +it.instance( + "reply - always persists approval and resolves", + () => + Effect.gen(function* () { + const fiber = yield* ask({ + id: PermissionID.make("per_test3"), + sessionID: SessionID.make("session_test"), + permission: "bash", + patterns: ["ls"], + metadata: {}, + always: ["ls"], + ruleset: [], + }).pipe(Effect.forkScoped) - yield* waitForPending(1).pipe(run) - yield* reply({ requestID: PermissionID.make("per_test3"), reply: "always" }).pipe(run) - yield* Fiber.join(fiber) + yield* waitForPending(1) + yield* reply({ requestID: PermissionID.make("per_test3"), reply: "always" }) + yield* Fiber.join(fiber) - const result = yield* ask({ - sessionID: SessionID.make("session_test2"), - permission: "bash", - patterns: ["ls"], - metadata: {}, - always: [], - ruleset: [], - }).pipe(run) - expect(result).toBeUndefined() - }), + const result = yield* ask({ + sessionID: SessionID.make("session_test2"), + permission: "bash", + patterns: ["ls"], + metadata: {}, + always: [], + ruleset: [], + }) + expect(result).toBeUndefined() + }), + { git: true }, ) -it.live("reply - reject cancels all pending for same session", () => - withDir({ git: true }, () => +it.instance( + "reply - reject cancels all pending for same session", + () => Effect.gen(function* () { const a = yield* ask({ id: PermissionID.make("per_test4a"), @@ -830,11 +836,12 @@ it.live("reply - reject cancels all pending for same session", () => if (Exit.isFailure(ea)) expect(Cause.squash(ea.cause)).toBeInstanceOf(Permission.RejectedError) if (Exit.isFailure(eb)) expect(Cause.squash(eb.cause)).toBeInstanceOf(Permission.RejectedError) }), - ), + { git: true }, ) -it.live("reply - always resolves matching pending requests in same session", () => - withDir({ git: true }, () => +it.instance( + "reply - always resolves matching pending requests in same session", + () => Effect.gen(function* () { const a = yield* ask({ id: PermissionID.make("per_test5a"), @@ -863,11 +870,12 @@ it.live("reply - always resolves matching pending requests in same session", () yield* Fiber.join(b) expect(yield* list()).toHaveLength(0) }), - ), + { git: true }, ) -it.live("reply - always keeps other session pending", () => - withDir({ git: true }, () => +it.instance( + "reply - always keeps other session pending", + () => Effect.gen(function* () { const a = yield* ask({ id: PermissionID.make("per_test6a"), @@ -898,24 +906,15 @@ it.live("reply - always keeps other session pending", () => yield* rejectAll() yield* Fiber.await(b) }), - ), + { git: true }, ) -it.live("reply - publishes replied event", () => - withDir({ git: true }, () => +it.instance( + "reply - publishes replied event", + () => Effect.gen(function* () { const bus = yield* Bus.Service - let resolve!: (value: { sessionID: SessionID; requestID: PermissionID; reply: Permission.Reply }) => void - const seen = Effect.promise<{ - sessionID: SessionID - requestID: PermissionID - reply: Permission.Reply - }>( - () => - new Promise((res) => { - resolve = res - }), - ) + const seen = yield* Deferred.make<{ sessionID: SessionID; requestID: PermissionID; reply: Permission.Reply }>() const fiber = yield* ask({ id: PermissionID.make("per_test7"), @@ -930,126 +929,146 @@ it.live("reply - publishes replied event", () => yield* waitForPending(1) const unsub = yield* bus.subscribeCallback(Permission.Event.Replied, (event) => { - resolve(event.properties) + Deferred.doneUnsafe(seen, Effect.succeed(event.properties)) }) + yield* Effect.addFinalizer(() => Effect.sync(unsub)) - try { - yield* reply({ requestID: PermissionID.make("per_test7"), reply: "once" }) - yield* Fiber.join(fiber) - expect(yield* seen).toEqual({ - sessionID: SessionID.make("session_test"), - requestID: PermissionID.make("per_test7"), - reply: "once", - }) - } finally { - unsub() - } + yield* reply({ requestID: PermissionID.make("per_test7"), reply: "once" }) + yield* Fiber.join(fiber) + expect( + yield* Deferred.await(seen).pipe( + Effect.timeoutOrElse({ + duration: "1 second", + orElse: () => Effect.fail(new Error("timed out waiting for permission replied event")), + }), + ), + ).toEqual({ + sessionID: SessionID.make("session_test"), + requestID: PermissionID.make("per_test7"), + reply: "once", + }) }), - ), + { git: true }, ) it.live("permission requests stay isolated by directory", () => Effect.gen(function* () { const one = yield* tmpdirScoped({ git: true }) const two = yield* tmpdirScoped({ git: true }) - const runOne = withProvided(one) - const runTwo = withProvided(two) + const store = yield* InstanceStore.Service - const a = yield* ask({ - id: PermissionID.make("per_dir_a"), - sessionID: SessionID.make("session_dir_a"), - permission: "bash", - patterns: ["ls"], - metadata: {}, - always: [], - ruleset: [], - }).pipe(runOne, Effect.forkScoped) + const a = yield* store + .provide( + { directory: one }, + ask({ + id: PermissionID.make("per_dir_a"), + sessionID: SessionID.make("session_dir_a"), + permission: "bash", + patterns: ["ls"], + metadata: {}, + always: [], + ruleset: [], + }), + ) + .pipe(Effect.forkScoped) - const b = yield* ask({ - id: PermissionID.make("per_dir_b"), - sessionID: SessionID.make("session_dir_b"), - permission: "bash", - patterns: ["pwd"], - metadata: {}, - always: [], - ruleset: [], - }).pipe(runTwo, Effect.forkScoped) + const b = yield* store + .provide( + { directory: two }, + ask({ + id: PermissionID.make("per_dir_b"), + sessionID: SessionID.make("session_dir_b"), + permission: "bash", + patterns: ["pwd"], + metadata: {}, + always: [], + ruleset: [], + }), + ) + .pipe(Effect.forkScoped) - const onePending = yield* waitForPending(1).pipe(runOne) - const twoPending = yield* waitForPending(1).pipe(runTwo) + const onePending = yield* store.provide({ directory: one }, waitForPending(1)) + const twoPending = yield* store.provide({ directory: two }, waitForPending(1)) expect(onePending).toHaveLength(1) expect(twoPending).toHaveLength(1) expect(onePending[0].id).toBe(PermissionID.make("per_dir_a")) expect(twoPending[0].id).toBe(PermissionID.make("per_dir_b")) - yield* reply({ requestID: onePending[0].id, reply: "reject" }).pipe(runOne) - yield* reply({ requestID: twoPending[0].id, reply: "reject" }).pipe(runTwo) + yield* store.provide({ directory: one }, reply({ requestID: onePending[0].id, reply: "reject" })) + yield* store.provide({ directory: two }, reply({ requestID: twoPending[0].id, reply: "reject" })) yield* Fiber.await(a) yield* Fiber.await(b) }), ) -it.live("pending permission rejects on instance dispose", () => - Effect.gen(function* () { - const dir = yield* tmpdirScoped({ git: true }) - const run = withProvided(dir) - const fiber = yield* ask({ - id: PermissionID.make("per_dispose"), - sessionID: SessionID.make("session_dispose"), - permission: "bash", - patterns: ["ls"], - metadata: {}, - always: [], - ruleset: [], - }).pipe(run, Effect.forkScoped) +it.instance( + "pending permission rejects on instance dispose", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const store = yield* InstanceStore.Service + const fiber = yield* ask({ + id: PermissionID.make("per_dispose"), + sessionID: SessionID.make("session_dispose"), + permission: "bash", + patterns: ["ls"], + metadata: {}, + always: [], + ruleset: [], + }).pipe(Effect.forkScoped) - expect(yield* waitForPending(1).pipe(run)).toHaveLength(1) - yield* Effect.promise(() => - WithInstance.provide({ directory: dir, fn: () => void InstanceRuntime.disposeInstance(Instance.current) }), - ) + expect(yield* waitForPending(1)).toHaveLength(1) + const ctx = yield* store.load({ directory: test.directory }) + yield* store.dispose(ctx) - const exit = yield* Fiber.await(fiber) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError) - }), + const exit = yield* Fiber.await(fiber) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError) + }), + { git: true }, ) -it.live("pending permission rejects on instance reload", () => - Effect.gen(function* () { - const dir = yield* tmpdirScoped({ git: true }) - const run = withProvided(dir) - const fiber = yield* ask({ - id: PermissionID.make("per_reload"), - sessionID: SessionID.make("session_reload"), - permission: "bash", - patterns: ["ls"], - metadata: {}, - always: [], - ruleset: [], - }).pipe(run, Effect.forkScoped) +it.instance( + "pending permission rejects on instance reload", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const store = yield* InstanceStore.Service + const fiber = yield* ask({ + id: PermissionID.make("per_reload"), + sessionID: SessionID.make("session_reload"), + permission: "bash", + patterns: ["ls"], + metadata: {}, + always: [], + ruleset: [], + }).pipe(Effect.forkScoped) - expect(yield* waitForPending(1).pipe(run)).toHaveLength(1) - yield* Effect.promise(() => reloadTestInstance({ directory: dir })) + expect(yield* waitForPending(1)).toHaveLength(1) + yield* store.reload({ directory: test.directory }) - const exit = yield* Fiber.await(fiber) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError) - }), + const exit = yield* Fiber.await(fiber) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError) + }), + { git: true }, ) -it.live("reply - does nothing for unknown requestID", () => - withDir({ git: true }, () => +it.instance( + "reply - does nothing for unknown requestID", + () => Effect.gen(function* () { yield* reply({ requestID: PermissionID.make("per_unknown"), reply: "once" }) expect(yield* list()).toHaveLength(0) }), - ), + { git: true }, ) -it.live("ask - checks all patterns and stops on first deny", () => - withDir({ git: true }, () => +it.instance( + "ask - checks all patterns and stops on first deny", + () => Effect.gen(function* () { const err = yield* fail( ask({ @@ -1066,11 +1085,12 @@ it.live("ask - checks all patterns and stops on first deny", () => ) expect(err).toBeInstanceOf(Permission.DeniedError) }), - ), + { git: true }, ) -it.live("ask - allows all patterns when all match allow rules", () => - withDir({ git: true }, () => +it.instance( + "ask - allows all patterns when all match allow rules", + () => Effect.gen(function* () { const result = yield* ask({ sessionID: SessionID.make("session_test"), @@ -1082,11 +1102,12 @@ it.live("ask - allows all patterns when all match allow rules", () => }) expect(result).toBeUndefined() }), - ), + { git: true }, ) -it.live("ask - should deny even when an earlier pattern is ask", () => - withDir({ git: true }, () => +it.instance( + "ask - should deny even when an earlier pattern is ask", + () => Effect.gen(function* () { const err = yield* fail( ask({ @@ -1105,30 +1126,33 @@ it.live("ask - should deny even when an earlier pattern is ask", () => expect(err).toBeInstanceOf(Permission.DeniedError) expect(yield* list()).toHaveLength(0) }), - ), + { git: true }, ) -it.live("ask - abort should clear pending request", () => - Effect.gen(function* () { - const dir = yield* tmpdirScoped({ git: true }) - const run = withProvided(dir) +it.instance( + "ask - abort should clear pending request", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const store = yield* InstanceStore.Service - const fiber = yield* ask({ - id: PermissionID.make("per_reload"), - sessionID: SessionID.make("session_reload"), - permission: "bash", - patterns: ["ls"], - metadata: {}, - always: [], - ruleset: [{ permission: "bash", pattern: "*", action: "ask" }], - }).pipe(run, Effect.forkScoped) + const fiber = yield* ask({ + id: PermissionID.make("per_reload"), + sessionID: SessionID.make("session_reload"), + permission: "bash", + patterns: ["ls"], + metadata: {}, + always: [], + ruleset: [{ permission: "bash", pattern: "*", action: "ask" }], + }).pipe(Effect.forkScoped) - const pending = yield* waitForPending(1).pipe(run) - expect(pending).toHaveLength(1) - yield* Effect.promise(() => reloadTestInstance({ directory: dir })) + const pending = yield* waitForPending(1) + expect(pending).toHaveLength(1) + yield* store.reload({ directory: test.directory }) - const exit = yield* Fiber.await(fiber) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError) - }), + const exit = yield* Fiber.await(fiber) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError) + }), + { git: true }, ) diff --git a/packages/opencode/test/plugin/auth-override.test.ts b/packages/opencode/test/plugin/auth-override.test.ts index c77c0ca1c0..adc66e48c5 100644 --- a/packages/opencode/test/plugin/auth-override.test.ts +++ b/packages/opencode/test/plugin/auth-override.test.ts @@ -1,15 +1,20 @@ import { describe, expect, test } from "bun:test" import path from "path" -import fs from "fs/promises" import { pathToFileURL } from "url" import { Effect, Layer } from "effect" -import { provideTestInstance, tmpdir } from "../fixture/fixture" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture" import { ProviderAuth } from "@/provider/auth" import { ProviderID } from "../../src/provider/schema" import { Plugin } from "@/plugin" +import { RuntimeFlags } from "@/effect/runtime-flags" import { Auth } from "@/auth" import { Bus } from "@/bus" import { TestConfig } from "../fixture/config" +import { testEffect } from "../lib/effect" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" + +const it = testEffect(Layer.mergeAll(CrossSpawnSpawner.defaultLayer, AppFileSystem.defaultLayer)) function layer(directory: string, plugins: string[]) { return ProviderAuth.layer.pipe( @@ -17,6 +22,7 @@ function layer(directory: string, plugins: string[]) { Layer.provide( Plugin.layer.pipe( Layer.provide(Bus.layer), + Layer.provide(RuntimeFlags.layer()), Layer.provide( TestConfig.layer({ get: () => @@ -37,13 +43,15 @@ function layer(directory: string, plugins: string[]) { } describe("plugin.auth-override", () => { - test("user plugin overrides built-in github-copilot auth", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - const pluginDir = path.join(dir, ".opencode", "plugin") - await fs.mkdir(pluginDir, { recursive: true }) + it.instance( + "user plugin overrides built-in github-copilot auth", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const fs = yield* AppFileSystem.Service + const pluginDir = path.join(tmp.directory, ".opencode", "plugin") - await Bun.write( + yield* fs.writeWithDirs( path.join(pluginDir, "custom-copilot-auth.ts"), [ "export default {", @@ -61,37 +69,26 @@ describe("plugin.auth-override", () => { "", ].join("\n"), ) - }, - }) - await using plain = await tmpdir() + const plain = yield* tmpdirScoped({ git: true }) + const plugin = pathToFileURL(path.join(pluginDir, "custom-copilot-auth.ts")).href + const methods = yield* ProviderAuth.Service.use((svc) => svc.methods()).pipe( + Effect.provide(layer(tmp.directory, [plugin])), + ) + const plainMethods = yield* ProviderAuth.Service.use((svc) => svc.methods()).pipe( + Effect.provide(layer(plain, [])), + provideInstance(plain), + ) - const plugin = pathToFileURL(path.join(tmp.path, ".opencode", "plugin", "custom-copilot-auth.ts")).href - const [methods, plainMethods] = await Promise.all([ - provideTestInstance({ - directory: tmp.path, - fn: async () => { - return Effect.runPromise( - ProviderAuth.Service.use((svc) => svc.methods()).pipe(Effect.provide(layer(tmp.path, [plugin]))), - ) - }, + const copilot = methods[ProviderID.make("github-copilot")] + expect(copilot).toBeDefined() + expect(copilot.length).toBe(1) + expect(copilot[0].label).toBe("Test Override Auth") + expect(plainMethods[ProviderID.make("github-copilot")][0].label).not.toBe("Test Override Auth") }), - provideTestInstance({ - directory: plain.path, - fn: async () => { - return Effect.runPromise( - ProviderAuth.Service.use((svc) => svc.methods()).pipe(Effect.provide(layer(plain.path, []))), - ) - }, - }), - ]) - - const copilot = methods[ProviderID.make("github-copilot")] - expect(copilot).toBeDefined() - expect(copilot.length).toBe(1) - expect(copilot[0].label).toBe("Test Override Auth") - expect(plainMethods[ProviderID.make("github-copilot")][0].label).not.toBe("Test Override Auth") - }, 30000) + { git: true }, + 30000, + ) }) const file = path.join(import.meta.dir, "../../src/plugin/index.ts") diff --git a/packages/opencode/test/plugin/loader-shared.test.ts b/packages/opencode/test/plugin/loader-shared.test.ts index 8c55950aff..6b1dd306dc 100644 --- a/packages/opencode/test/plugin/loader-shared.test.ts +++ b/packages/opencode/test/plugin/loader-shared.test.ts @@ -1,65 +1,74 @@ -import { afterAll, afterEach, describe, expect, spyOn, test } from "bun:test" +import { afterEach, describe, expect, spyOn } from "bun:test" import { Effect, Layer } from "effect" import fs from "fs/promises" import path from "path" import { pathToFileURL } from "url" -import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { disposeAllInstances, provideInstance, tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" import { Filesystem } from "@/util/filesystem" -const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS -process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = "1" - const { Plugin } = await import("../../src/plugin/index") const { PluginLoader } = await import("../../src/plugin/loader") const { readPackageThemes } = await import("../../src/plugin/shared") const { Bus } = await import("../../src/bus") const { Npm } = await import("@opencode-ai/core/npm") const { TestConfig } = await import("../fixture/config") - -afterAll(() => { - if (disableDefault === undefined) { - delete process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS - return - } - process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = disableDefault -}) +const { RuntimeFlags } = await import("../../src/effect/runtime-flags") afterEach(async () => { await disposeAllInstances() }) -async function load(dir: string) { - const source = path.join(dir, "opencode.json") - const config = (await Bun.file(source).json()) as { plugin?: Array]> } - const plugins = config.plugin ?? [] +const it = testEffect(CrossSpawnSpawner.defaultLayer) + +function withTmp( + init: (dir: string) => Promise, + body: (tmp: { path: string; extra: T }) => Effect.Effect, +) { return Effect.gen(function* () { - const plugin = yield* Plugin.Service - yield* plugin.list() - }).pipe( - Effect.provide( - Plugin.layer.pipe( - Layer.provide(Bus.layer), - Layer.provide( - TestConfig.layer({ - get: () => - Effect.succeed({ - plugin: plugins, - plugin_origins: plugins.map((plugin) => ({ spec: plugin, source, scope: "local" as const })), - }), - directories: () => Effect.succeed([dir]), - }), + const dir = yield* tmpdirScoped() + const extra = yield* Effect.promise(() => init(dir)) + return yield* body({ path: dir, extra }) + }) +} + +function load(dir: string, flags?: Parameters[0]) { + const source = path.join(dir, "opencode.json") + return Effect.gen(function* () { + const config = yield* Effect.promise( + () => Bun.file(source).json() as Promise<{ plugin?: Array]> }>, + ) + const plugins = config.plugin ?? [] + return yield* Effect.gen(function* () { + const plugin = yield* Plugin.Service + yield* plugin.list() + }).pipe( + Effect.provide( + Plugin.layer.pipe( + Layer.provide(Bus.layer), + Layer.provide(RuntimeFlags.layer({ disableDefaultPlugins: true, ...flags })), + Layer.provide( + TestConfig.layer({ + get: () => + Effect.succeed({ + plugin: plugins, + plugin_origins: plugins.map((plugin) => ({ spec: plugin, source, scope: "local" as const })), + }), + directories: () => Effect.succeed([dir]), + }), + ), ), ), - ), - provideInstance(dir), - Effect.runPromise, - ) + provideInstance(dir), + ) + }) } describe("plugin.loader.shared", () => { - test("loads a file:// plugin function export", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("loads a file:// plugin function export", () => + withTmp( + async (dir) => { const file = path.join(dir, "plugin.ts") const mark = path.join(dir, "called.txt") await Bun.write( @@ -80,15 +89,17 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + expect(yield* Effect.promise(() => fs.readFile(tmp.extra.mark, "utf8"))).toBe("called") + }), + ), + ) - await load(tmp.path) - expect(await fs.readFile(tmp.extra.mark, "utf8")).toBe("called") - }) - - test("deduplicates same function exported as default and named", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("deduplicates same function exported as default and named", () => + withTmp( + async (dir) => { const file = path.join(dir, "plugin.ts") const mark = path.join(dir, "count.txt") await Bun.write(mark, "") @@ -113,15 +124,17 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + expect(yield* Effect.promise(() => fs.readFile(tmp.extra.mark, "utf8"))).toBe("1") + }), + ), + ) - await load(tmp.path) - expect(await fs.readFile(tmp.extra.mark, "utf8")).toBe("1") - }) - - test("uses only default v1 server plugin when present", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("uses only default v1 server plugin when present", () => + withTmp( + async (dir) => { const file = path.join(dir, "plugin.ts") const mark = path.join(dir, "count.txt") await Bun.write( @@ -149,15 +162,17 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + expect(yield* Effect.promise(() => Bun.file(tmp.extra.mark).text())).toBe("default") + }), + ), + ) - await load(tmp.path) - expect(await Bun.file(tmp.extra.mark).text()).toBe("default") - }) - - test("rejects v1 file server plugin without id", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("rejects v1 file server plugin without id", () => + withTmp( + async (dir) => { const file = path.join(dir, "plugin.ts") const mark = path.join(dir, "called.txt") await Bun.write( @@ -180,20 +195,24 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + const called = yield* Effect.promise(() => + Bun.file(tmp.extra.mark) + .text() + .then(() => true) + .catch(() => false), + ) - await load(tmp.path) - const called = await Bun.file(tmp.extra.mark) - .text() - .then(() => true) - .catch(() => false) + expect(called).toBe(false) + }), + ), + ) - expect(called).toBe(false) - }) - - test("rejects v1 plugin that exports server and tui together", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("rejects v1 plugin that exports server and tui together", () => + withTmp( + async (dir) => { const file = path.join(dir, "plugin.ts") const mark = path.join(dir, "called.txt") await Bun.write( @@ -218,20 +237,24 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + const called = yield* Effect.promise(() => + Bun.file(tmp.extra.mark) + .text() + .then(() => true) + .catch(() => false), + ) - await load(tmp.path) - const called = await Bun.file(tmp.extra.mark) - .text() - .then(() => true) - .catch(() => false) + expect(called).toBe(false) + }), + ), + ) - expect(called).toBe(false) - }) - - test("resolves npm plugin specs with explicit and default versions", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("resolves npm plugin specs with explicit and default versions", () => + withTmp( + async (dir) => { const acme = path.join(dir, "node_modules", "acme-plugin") const scope = path.join(dir, "node_modules", "scope-plugin") await fs.mkdir(acme, { recursive: true }) @@ -254,26 +277,28 @@ describe("plugin.loader.shared", () => { return { acme, scope } }, - }) + (tmp) => + Effect.gen(function* () { + const add = spyOn(Npm, "add").mockImplementation(async (pkg) => { + if (pkg === "acme-plugin") return { directory: tmp.extra.acme, entrypoint: undefined } + return { directory: tmp.extra.scope, entrypoint: undefined } + }) - const add = spyOn(Npm, "add").mockImplementation(async (pkg) => { - if (pkg === "acme-plugin") return { directory: tmp.extra.acme, entrypoint: undefined } - return { directory: tmp.extra.scope, entrypoint: undefined } - }) + try { + yield* load(tmp.path) - try { - await load(tmp.path) + expect(add.mock.calls).toContainEqual(["acme-plugin@latest"]) + expect(add.mock.calls).toContainEqual(["scope-plugin@2.3.4"]) + } finally { + add.mockRestore() + } + }), + ), + ) - expect(add.mock.calls).toContainEqual(["acme-plugin@latest"]) - expect(add.mock.calls).toContainEqual(["scope-plugin@2.3.4"]) - } finally { - add.mockRestore() - } - }) - - test("loads npm server plugin from package ./server export", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("loads npm server plugin from package ./server export", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mods", "acme-plugin") const mark = path.join(dir, "server-called.txt") await fs.mkdir(mod, { recursive: true }) @@ -317,21 +342,23 @@ describe("plugin.loader.shared", () => { mark, } }, - }) + (tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) - const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) + try { + yield* load(tmp.path) + expect(yield* Effect.promise(() => Bun.file(tmp.extra.mark).text())).toBe("called") + } finally { + install.mockRestore() + } + }), + ), + ) - try { - await load(tmp.path) - expect(await Bun.file(tmp.extra.mark).text()).toBe("called") - } finally { - install.mockRestore() - } - }) - - test("loads npm server plugin from package server export without leading dot", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("loads npm server plugin from package server export without leading dot", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mods", "acme-plugin") const dist = path.join(mod, "dist") const mark = path.join(dir, "server-called.txt") @@ -374,21 +401,23 @@ describe("plugin.loader.shared", () => { mark, } }, - }) + (tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) - const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) + try { + yield* load(tmp.path) + expect(yield* Effect.promise(() => Bun.file(tmp.extra.mark).text())).toBe("called") + } finally { + install.mockRestore() + } + }), + ), + ) - try { - await load(tmp.path) - expect(await Bun.file(tmp.extra.mark).text()).toBe("called") - } finally { - install.mockRestore() - } - }) - - test("loads npm server plugin from package main without leading dot", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("loads npm server plugin from package main without leading dot", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mods", "acme-plugin") const dist = path.join(mod, "dist") const mark = path.join(dir, "main-called.txt") @@ -426,21 +455,23 @@ describe("plugin.loader.shared", () => { mark, } }, - }) + (tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) - const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) + try { + yield* load(tmp.path) + expect(yield* Effect.promise(() => Bun.file(tmp.extra.mark).text())).toBe("called") + } finally { + install.mockRestore() + } + }), + ), + ) - try { - await load(tmp.path) - expect(await Bun.file(tmp.extra.mark).text()).toBe("called") - } finally { - install.mockRestore() - } - }) - - test("does not use npm package exports dot for server entry", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("does not use npm package exports dot for server entry", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mods", "acme-plugin") const mark = path.join(dir, "dot-server.txt") await fs.mkdir(mod, { recursive: true }) @@ -471,26 +502,30 @@ describe("plugin.loader.shared", () => { return { mod, mark } }, - }) + (tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) - const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) + try { + yield* load(tmp.path) + const called = yield* Effect.promise(() => + Bun.file(tmp.extra.mark) + .text() + .then(() => true) + .catch(() => false), + ) - try { - await load(tmp.path) - const called = await Bun.file(tmp.extra.mark) - .text() - .then(() => true) - .catch(() => false) + expect(called).toBe(false) + } finally { + install.mockRestore() + } + }), + ), + ) - expect(called).toBe(false) - } finally { - install.mockRestore() - } - }) - - test("rejects npm server export that resolves outside plugin directory", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("rejects npm server export that resolves outside plugin directory", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mods", "acme-plugin") const outside = path.join(dir, "outside") const mark = path.join(dir, "outside-server.txt") @@ -534,25 +569,29 @@ describe("plugin.loader.shared", () => { mark, } }, - }) + (tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) - const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) + try { + yield* load(tmp.path) + const called = yield* Effect.promise(() => + Bun.file(tmp.extra.mark) + .text() + .then(() => true) + .catch(() => false), + ) + expect(called).toBe(false) + } finally { + install.mockRestore() + } + }), + ), + ) - try { - await load(tmp.path) - const called = await Bun.file(tmp.extra.mark) - .text() - .then(() => true) - .catch(() => false) - expect(called).toBe(false) - } finally { - install.mockRestore() - } - }) - - test("skips legacy codex and copilot auth plugin specs", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("skips legacy codex and copilot auth plugin specs", () => + withTmp( + async (dir) => { await Bun.write( path.join(dir, "opencode.json"), JSON.stringify( @@ -564,25 +603,27 @@ describe("plugin.loader.shared", () => { ), ) }, - }) + (_tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockResolvedValue({ directory: "", entrypoint: undefined }) - const install = spyOn(Npm, "add").mockResolvedValue({ directory: "", entrypoint: undefined }) + try { + yield* load(_tmp.path) - try { - await load(tmp.path) + const pkgs = install.mock.calls.map((call) => call[0]) + expect(pkgs).toContain("regular-plugin@1.0.0") + expect(pkgs).not.toContain("opencode-openai-codex-auth@1.0.0") + expect(pkgs).not.toContain("opencode-copilot-auth@1.0.0") + } finally { + install.mockRestore() + } + }), + ), + ) - const pkgs = install.mock.calls.map((call) => call[0]) - expect(pkgs).toContain("regular-plugin@1.0.0") - expect(pkgs).not.toContain("opencode-openai-codex-auth@1.0.0") - expect(pkgs).not.toContain("opencode-copilot-auth@1.0.0") - } finally { - install.mockRestore() - } - }) - - test("skips broken plugin when install fails", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("skips broken plugin when install fails", () => + withTmp( + async (dir) => { const ok = path.join(dir, "ok.ts") const mark = path.join(dir, "ok.txt") await Bun.write( @@ -604,22 +645,24 @@ describe("plugin.loader.shared", () => { ) return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockRejectedValue(new Error("boom")) - const install = spyOn(Npm, "add").mockRejectedValue(new Error("boom")) + try { + yield* load(tmp.path) + expect(install).toHaveBeenCalledWith("broken-plugin@9.9.9") + expect(yield* Effect.promise(() => Bun.file(tmp.extra.mark).text())).toBe("ok") + } finally { + install.mockRestore() + } + }), + ), + ) - try { - await load(tmp.path) - expect(install).toHaveBeenCalledWith("broken-plugin@9.9.9") - expect(await Bun.file(tmp.extra.mark).text()).toBe("ok") - } finally { - install.mockRestore() - } - }) - - test("continues loading plugins when plugin init throws", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("continues loading plugins when plugin init throws", () => + withTmp( + async (dir) => { const file = pathToFileURL(path.join(dir, "throws.ts")).href const ok = pathToFileURL(path.join(dir, "ok.ts")).href const mark = path.join(dir, "ok.txt") @@ -653,15 +696,17 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + expect(yield* Effect.promise(() => Bun.file(tmp.extra.mark).text())).toBe("ok") + }), + ), + ) - await load(tmp.path) - expect(await Bun.file(tmp.extra.mark).text()).toBe("ok") - }) - - test("continues loading plugins when plugin module has invalid export", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("continues loading plugins when plugin module has invalid export", () => + withTmp( + async (dir) => { const file = pathToFileURL(path.join(dir, "invalid.ts")).href const ok = pathToFileURL(path.join(dir, "ok.ts")).href const mark = path.join(dir, "ok.txt") @@ -687,15 +732,17 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + expect(yield* Effect.promise(() => Bun.file(tmp.extra.mark).text())).toBe("ok") + }), + ), + ) - await load(tmp.path) - expect(await Bun.file(tmp.extra.mark).text()).toBe("ok") - }) - - test("continues loading plugins when plugin import fails", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("continues loading plugins when plugin import fails", () => + withTmp( + async (dir) => { const missing = pathToFileURL(path.join(dir, "missing-plugin.ts")).href const ok = pathToFileURL(path.join(dir, "ok.ts")).href const mark = path.join(dir, "ok.txt") @@ -716,15 +763,17 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + expect(yield* Effect.promise(() => Bun.file(tmp.extra.mark).text())).toBe("ok") + }), + ), + ) - await load(tmp.path) - expect(await Bun.file(tmp.extra.mark).text()).toBe("ok") - }) - - test("loads object plugin via plugin.server", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("loads object plugin via plugin.server", () => + withTmp( + async (dir) => { const file = path.join(dir, "object-plugin.ts") const mark = path.join(dir, "object-called.txt") await Bun.write( @@ -749,15 +798,17 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + expect(yield* Effect.promise(() => fs.readFile(tmp.extra.mark, "utf8"))).toBe("called") + }), + ), + ) - await load(tmp.path) - expect(await fs.readFile(tmp.extra.mark, "utf8")).toBe("called") - }) - - test("passes tuple plugin options into server plugin", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("passes tuple plugin options into server plugin", () => + withTmp( + async (dir) => { const file = path.join(dir, "options-plugin.ts") const mark = path.join(dir, "options.json") await Bun.write( @@ -782,18 +833,22 @@ describe("plugin.loader.shared", () => { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + expect( + yield* Effect.promise(() => Filesystem.readJson<{ source: string; enabled: boolean }>(tmp.extra.mark)), + ).toEqual({ + source: "tuple", + enabled: true, + }) + }), + ), + ) - await load(tmp.path) - expect(await Filesystem.readJson<{ source: string; enabled: boolean }>(tmp.extra.mark)).toEqual({ - source: "tuple", - enabled: true, - }) - }) - - test("initializes server plugins in config order", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("initializes server plugins in config order", () => + withTmp( + async (dir) => { const a = path.join(dir, "a-plugin.ts") const b = path.join(dir, "b-plugin.ts") const marker = path.join(dir, "server-order.txt") @@ -833,16 +888,18 @@ export default { return { marker } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path) + const lines = (yield* Effect.promise(() => fs.readFile(tmp.extra.marker, "utf8"))).trim().split("\n") + expect(lines).toEqual(["a-start", "a-end", "b"]) + }), + ), + ) - await load(tmp.path) - const lines = (await fs.readFile(tmp.extra.marker, "utf8")).trim().split("\n") - expect(lines).toEqual(["a-start", "a-end", "b"]) - }) - - test("skips external plugins in pure mode", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("skips external plugins in pure mode", () => + withTmp( + async (dir) => { const file = path.join(dir, "plugin.ts") const mark = path.join(dir, "called.txt") await Bun.write( @@ -866,30 +923,23 @@ export default { return { mark } }, - }) + (tmp) => + Effect.gen(function* () { + yield* load(tmp.path, { pure: true }) + const called = yield* Effect.promise(() => + fs + .readFile(tmp.extra.mark, "utf8") + .then(() => true) + .catch(() => false), + ) + expect(called).toBe(false) + }), + ), + ) - const pure = process.env.OPENCODE_PURE - process.env.OPENCODE_PURE = "1" - - try { - await load(tmp.path) - const called = await fs - .readFile(tmp.extra.mark, "utf8") - .then(() => true) - .catch(() => false) - expect(called).toBe(false) - } finally { - if (pure === undefined) { - delete process.env.OPENCODE_PURE - } else { - process.env.OPENCODE_PURE = pure - } - } - }) - - test("reads oc-themes from package manifest", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("reads oc-themes from package manifest", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mod") await fs.mkdir(path.join(mod, "themes"), { recursive: true }) await Bun.write( @@ -907,25 +957,27 @@ export default { return { mod } }, - }) + (tmp) => + Effect.gen(function* () { + const file = path.join(tmp.extra.mod, "package.json") + const json = yield* Effect.promise(() => Filesystem.readJson>(file)) + const list = readPackageThemes("acme-plugin", { + dir: tmp.extra.mod, + pkg: file, + json, + }) - const file = path.join(tmp.extra.mod, "package.json") - const json = await Filesystem.readJson>(file) - const list = readPackageThemes("acme-plugin", { - dir: tmp.extra.mod, - pkg: file, - json, - }) + expect(list).toEqual([ + Filesystem.resolve(path.join(tmp.extra.mod, "themes", "one.json")), + Filesystem.resolve(path.join(tmp.extra.mod, "themes", "two.json")), + ]) + }), + ), + ) - expect(list).toEqual([ - Filesystem.resolve(path.join(tmp.extra.mod, "themes", "one.json")), - Filesystem.resolve(path.join(tmp.extra.mod, "themes", "two.json")), - ]) - }) - - test("handles no-entrypoint tui packages via missing callback", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("handles no-entrypoint tui packages via missing callback", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mods", "acme-plugin") await fs.mkdir(path.join(mod, "themes"), { recursive: true }) await Bun.write( @@ -943,54 +995,58 @@ export default { await Bun.write(path.join(mod, "themes", "night.json"), "{}\n") return { mod } }, - }) + (tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) + const missing: string[] = [] - const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) - const missing: string[] = [] + try { + const loaded = yield* Effect.promise(() => + PluginLoader.loadExternal({ + items: [ + { + spec: "acme-plugin@1.0.0", + scope: "local" as const, + source: tmp.path, + }, + ], + kind: "tui", + missing: async (item) => { + if (!item.pkg) return + const themes = readPackageThemes(item.spec, item.pkg) + if (!themes.length) return + return { + spec: item.spec, + target: item.target, + themes, + } + }, + report: { + missing(_candidate, _retry, message) { + missing.push(message) + }, + }, + }), + ) - try { - const loaded = await PluginLoader.loadExternal({ - items: [ - { - spec: "acme-plugin@1.0.0", - scope: "local" as const, - source: tmp.path, - }, - ], - kind: "tui", - missing: async (item) => { - if (!item.pkg) return - const themes = readPackageThemes(item.spec, item.pkg) - if (!themes.length) return - return { - spec: item.spec, - target: item.target, - themes, + expect(loaded).toEqual([ + { + spec: "acme-plugin@1.0.0", + target: tmp.extra.mod, + themes: [Filesystem.resolve(path.join(tmp.extra.mod, "themes", "night.json"))], + }, + ]) + expect(missing).toHaveLength(0) + } finally { + install.mockRestore() } - }, - report: { - missing(_candidate, _retry, message) { - missing.push(message) - }, - }, - }) + }), + ), + ) - expect(loaded).toEqual([ - { - spec: "acme-plugin@1.0.0", - target: tmp.extra.mod, - themes: [Filesystem.resolve(path.join(tmp.extra.mod, "themes", "night.json"))], - }, - ]) - expect(missing).toHaveLength(0) - } finally { - install.mockRestore() - } - }) - - test("passes package metadata for entrypoint tui plugins", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("passes package metadata for entrypoint tui plugins", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mods", "acme-plugin") await fs.mkdir(path.join(mod, "themes"), { recursive: true }) await Bun.write( @@ -1012,64 +1068,70 @@ export default { await Bun.write(path.join(mod, "themes", "night.json"), "{}\n") return { mod } }, - }) + (tmp) => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) - const install = spyOn(Npm, "add").mockResolvedValue({ directory: tmp.extra.mod, entrypoint: undefined }) + try { + const loaded = yield* Effect.promise(() => + PluginLoader.loadExternal({ + items: [ + { + spec: "acme-plugin@1.0.0", + scope: "local" as const, + source: tmp.path, + }, + ], + kind: "tui", + finish: async (item) => { + if (!item.pkg) return + return { + spec: item.spec, + themes: readPackageThemes(item.spec, item.pkg), + } + }, + }), + ) - try { - const loaded = await PluginLoader.loadExternal({ - items: [ - { - spec: "acme-plugin@1.0.0", - scope: "local" as const, - source: tmp.path, - }, - ], - kind: "tui", - finish: async (item) => { - if (!item.pkg) return - return { - spec: item.spec, - themes: readPackageThemes(item.spec, item.pkg), + expect(loaded).toEqual([ + { + spec: "acme-plugin@1.0.0", + themes: [Filesystem.resolve(path.join(tmp.extra.mod, "themes", "night.json"))], + }, + ]) + } finally { + install.mockRestore() } - }, - }) + }), + ), + ) - expect(loaded).toEqual([ - { - spec: "acme-plugin@1.0.0", - themes: [Filesystem.resolve(path.join(tmp.extra.mod, "themes", "night.json"))], - }, - ]) - } finally { - install.mockRestore() - } - }) - - test("rejects oc-themes path traversal", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("rejects oc-themes path traversal", () => + withTmp( + async (dir) => { const mod = path.join(dir, "mod") await fs.mkdir(mod, { recursive: true }) const file = path.join(mod, "package.json") await Bun.write(file, JSON.stringify({ name: "acme", "oc-themes": ["../escape.json"] }, null, 2)) return { mod, file } }, - }) + (tmp) => + Effect.gen(function* () { + const json = yield* Effect.promise(() => Filesystem.readJson>(tmp.extra.file)) + expect(() => + readPackageThemes("acme", { + dir: tmp.extra.mod, + pkg: tmp.extra.file, + json, + }), + ).toThrow("outside plugin directory") + }), + ), + ) - const json = await Filesystem.readJson>(tmp.extra.file) - expect(() => - readPackageThemes("acme", { - dir: tmp.extra.mod, - pkg: tmp.extra.file, - json, - }), - ).toThrow("outside plugin directory") - }) - - test("retries failed file plugins once after wait and keeps order", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("retries failed file plugins once after wait and keeps order", () => + withTmp( + async (dir) => { const a = path.join(dir, "a") const b = path.join(dir, "b") const aSpec = pathToFileURL(a).href @@ -1078,110 +1140,122 @@ export default { await fs.mkdir(b, { recursive: true }) return { a, b, aSpec, bSpec } }, - }) + (tmp) => + Effect.gen(function* () { + let wait = 0 + const calls: Array<[string, boolean]> = [] - let wait = 0 - const calls: Array<[string, boolean]> = [] + const loaded = yield* Effect.promise(() => + PluginLoader.loadExternal({ + items: [tmp.extra.aSpec, tmp.extra.bSpec].map((spec) => ({ + spec, + scope: "local" as const, + source: tmp.path, + })), + kind: "tui", + wait: async () => { + wait += 1 + await Bun.write(path.join(tmp.extra.a, "index.ts"), "export default {}\n") + await Bun.write(path.join(tmp.extra.b, "index.ts"), "export default {}\n") + }, + report: { + start(candidate, retry) { + calls.push([candidate.plan.spec, retry]) + }, + }, + }), + ) - const loaded = await PluginLoader.loadExternal({ - items: [tmp.extra.aSpec, tmp.extra.bSpec].map((spec) => ({ - spec, - scope: "local" as const, - source: tmp.path, - })), - kind: "tui", - wait: async () => { - wait += 1 - await Bun.write(path.join(tmp.extra.a, "index.ts"), "export default {}\n") - await Bun.write(path.join(tmp.extra.b, "index.ts"), "export default {}\n") - }, - report: { - start(candidate, retry) { - calls.push([candidate.plan.spec, retry]) - }, - }, - }) + expect(wait).toBe(1) + expect(calls).toEqual([ + [tmp.extra.aSpec, false], + [tmp.extra.bSpec, false], + [tmp.extra.aSpec, true], + [tmp.extra.bSpec, true], + ]) + expect(loaded.map((item) => item.spec)).toEqual([tmp.extra.aSpec, tmp.extra.bSpec]) + }), + ), + ) - expect(wait).toBe(1) - expect(calls).toEqual([ - [tmp.extra.aSpec, false], - [tmp.extra.bSpec, false], - [tmp.extra.aSpec, true], - [tmp.extra.bSpec, true], - ]) - expect(loaded.map((item) => item.spec)).toEqual([tmp.extra.aSpec, tmp.extra.bSpec]) - }) - - test("retries file plugins when finish returns undefined", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { + it.live("retries file plugins when finish returns undefined", () => + withTmp( + async (dir) => { const file = path.join(dir, "plugin.ts") const spec = pathToFileURL(file).href await Bun.write(file, "export default {}\n") return { spec } }, - }) + (tmp) => + Effect.gen(function* () { + let wait = 0 + let count = 0 - let wait = 0 - let count = 0 + const loaded = yield* Effect.promise(() => + PluginLoader.loadExternal({ + items: [ + { + spec: tmp.extra.spec, + scope: "local" as const, + source: tmp.path, + }, + ], + kind: "tui", + wait: async () => { + wait += 1 + }, + finish: async (load, _item, retry) => { + count += 1 + if (!retry) return + return { + retry, + spec: load.spec, + } + }, + }), + ) - const loaded = await PluginLoader.loadExternal({ - items: [ - { - spec: tmp.extra.spec, - scope: "local" as const, - source: tmp.path, - }, - ], - kind: "tui", - wait: async () => { - wait += 1 - }, - finish: async (load, _item, retry) => { - count += 1 - if (!retry) return - return { - retry, - spec: load.spec, - } - }, - }) + expect(wait).toBe(1) + expect(count).toBe(2) + expect(loaded).toEqual([{ retry: true, spec: tmp.extra.spec }]) + }), + ), + ) - expect(wait).toBe(1) - expect(count).toBe(2) - expect(loaded).toEqual([{ retry: true, spec: tmp.extra.spec }]) - }) + it.live("does not wait or retry npm plugin failures", () => + Effect.gen(function* () { + const install = spyOn(Npm, "add").mockRejectedValue(new Error("boom")) + let wait = 0 + const errors: Array<[string, boolean]> = [] - test("does not wait or retry npm plugin failures", async () => { - const install = spyOn(Npm, "add").mockRejectedValue(new Error("boom")) - let wait = 0 - const errors: Array<[string, boolean]> = [] + try { + const loaded = yield* Effect.promise(() => + PluginLoader.loadExternal({ + items: [ + { + spec: "acme-plugin@1.0.0", + scope: "local" as const, + source: "test", + }, + ], + kind: "tui", + wait: async () => { + wait += 1 + }, + report: { + error(_candidate, retry, stage) { + errors.push([stage, retry]) + }, + }, + }), + ) - try { - const loaded = await PluginLoader.loadExternal({ - items: [ - { - spec: "acme-plugin@1.0.0", - scope: "local" as const, - source: "test", - }, - ], - kind: "tui", - wait: async () => { - wait += 1 - }, - report: { - error(_candidate, retry, stage) { - errors.push([stage, retry]) - }, - }, - }) - - expect(loaded).toEqual([]) - expect(wait).toBe(0) - expect(errors).toEqual([["install", false]]) - } finally { - install.mockRestore() - } - }) + expect(loaded).toEqual([]) + expect(wait).toBe(0) + expect(errors).toEqual([["install", false]]) + } finally { + install.mockRestore() + } + }), + ) }) diff --git a/packages/opencode/test/plugin/trigger.test.ts b/packages/opencode/test/plugin/trigger.test.ts index 5e16af42be..94642fba62 100644 --- a/packages/opencode/test/plugin/trigger.test.ts +++ b/packages/opencode/test/plugin/trigger.test.ts @@ -1,26 +1,48 @@ -import { afterAll, describe, expect } from "bun:test" -import { Effect, Layer } from "effect" +import { describe, expect } from "bun:test" +import { Effect, Layer, Option } from "effect" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { EffectFlock } from "@opencode-ai/core/util/effect-flock" import path from "path" import { pathToFileURL } from "url" +import { Account } from "../../src/account/account" +import { Auth } from "../../src/auth" +import { Bus } from "../../src/bus" +import { Config } from "../../src/config/config" +import { Env } from "../../src/env" +import { RuntimeFlags } from "../../src/effect/runtime-flags" +import { Plugin } from "../../src/plugin/index" import { ModelID, ProviderID } from "../../src/provider/schema" import { provideTmpdirInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" +import { NpmTest } from "../fake/npm" -const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS -process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = "1" - -const { Plugin } = await import("../../src/plugin/index") -const it = testEffect(Layer.mergeAll(Plugin.defaultLayer, CrossSpawnSpawner.defaultLayer)) -const systemHook = "experimental.chat.system.transform" - -afterAll(() => { - if (disableDefault === undefined) { - delete process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS - return - } - process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = disableDefault +const emptyAccount = Layer.mock(Account.Service)({ + active: () => Effect.succeed(Option.none()), + activeOrg: () => Effect.succeed(Option.none()), }) +const emptyAuth = Layer.mock(Auth.Service)({ + all: () => Effect.succeed({}), +}) +const configLayer = Config.layer.pipe( + Layer.provide(EffectFlock.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(Env.defaultLayer), + Layer.provide(emptyAuth), + Layer.provide(emptyAccount), + Layer.provide(NpmTest.noop), +) +const it = testEffect( + Layer.mergeAll( + Plugin.layer.pipe( + Layer.provide(Bus.layer), + Layer.provide(configLayer), + Layer.provide(RuntimeFlags.layer({ disableDefaultPlugins: true })), + ), + CrossSpawnSpawner.defaultLayer, + ), +) +const systemHook = "experimental.chat.system.transform" function withProject(source: string, self: Effect.Effect) { return provideTmpdirInstance((dir) => diff --git a/packages/opencode/test/plugin/workspace-adapter.test.ts b/packages/opencode/test/plugin/workspace-adapter.test.ts index 9199a85a61..0cf603fa3b 100644 --- a/packages/opencode/test/plugin/workspace-adapter.test.ts +++ b/packages/opencode/test/plugin/workspace-adapter.test.ts @@ -1,25 +1,65 @@ import { afterAll, afterEach, describe, expect } from "bun:test" -import { Effect, Layer } from "effect" +import { Effect, Layer, Option } from "effect" +import { FetchHttpClient } from "effect/unstable/http" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { EffectFlock } from "@opencode-ai/core/util/effect-flock" +import { Flag } from "@opencode-ai/core/flag/flag" import path from "path" import { pathToFileURL } from "url" +import { Account } from "../../src/account/account" +import { Auth } from "../../src/auth" +import { Bus } from "../../src/bus" +import { Config } from "../../src/config/config" +import { Env } from "../../src/env" +import { RuntimeFlags } from "../../src/effect/runtime-flags" +import { Workspace } from "../../src/control-plane/workspace" +import { Plugin } from "../../src/plugin/index" +import { InstanceBootstrap } from "../../src/project/bootstrap-service" +import { Instance } from "../../src/project/instance" +import { InstanceStore } from "../../src/project/instance-store" +import { Project } from "../../src/project/project" +import { Vcs } from "../../src/project/vcs" +import { Session } from "../../src/session/session" +import { SessionPrompt } from "../../src/session/prompt" +import { SyncEvent } from "../../src/sync" import { disposeAllInstances, provideTmpdirInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" +import { NpmTest } from "../fake/npm" -const disableDefault = process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS -process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = "1" - -const { Flag } = await import("@opencode-ai/core/flag/flag") -const { Plugin } = await import("../../src/plugin/index") -const { Workspace } = await import("../../src/control-plane/workspace") -const { InstanceBootstrap } = await import("../../src/project/bootstrap") -const { Instance } = await import("../../src/project/instance") -const { InstanceStore } = await import("../../src/project/instance-store") -const workspaceLayer = Workspace.defaultLayer.pipe( - Layer.provide(InstanceStore.defaultLayer), - Layer.provide(InstanceBootstrap.defaultLayer), +const emptyAccount = Layer.mock(Account.Service)({ + active: () => Effect.succeed(Option.none()), + activeOrg: () => Effect.succeed(Option.none()), +}) +const emptyAuth = Layer.mock(Auth.Service)({ + all: () => Effect.succeed({}), +}) +const configLayer = Config.layer.pipe( + Layer.provide(EffectFlock.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(Env.defaultLayer), + Layer.provide(emptyAuth), + Layer.provide(emptyAccount), + Layer.provide(NpmTest.noop), ) -const it = testEffect(Layer.mergeAll(Plugin.defaultLayer, workspaceLayer, CrossSpawnSpawner.defaultLayer)) +const pluginLayer = Plugin.layer.pipe( + Layer.provide(Bus.layer), + Layer.provide(configLayer), + Layer.provide(RuntimeFlags.layer({ disableDefaultPlugins: true })), +) +const noopBootstrapLayer = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void })) +const workspaceLayer = Workspace.layer.pipe( + Layer.provide(Auth.defaultLayer), + Layer.provide(Session.defaultLayer), + Layer.provide(SyncEvent.defaultLayer), + Layer.provide(SessionPrompt.defaultLayer), + Layer.provide(Project.defaultLayer), + Layer.provide(Vcs.defaultLayer), + Layer.provide(FetchHttpClient.layer), + Layer.provide(InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrapLayer))), + Layer.provide(RuntimeFlags.layer({ experimentalWorkspaces: true })), +) +const it = testEffect(Layer.mergeAll(pluginLayer, workspaceLayer, CrossSpawnSpawner.defaultLayer)) const experimental = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES @@ -30,12 +70,6 @@ afterEach(async () => { }) afterAll(() => { - if (disableDefault === undefined) { - delete process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS - } else { - process.env.OPENCODE_DISABLE_DEFAULT_PLUGINS = disableDefault - } - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = experimental }) diff --git a/packages/opencode/test/preload.ts b/packages/opencode/test/preload.ts index b408f7ef11..24b804819e 100644 --- a/packages/opencode/test/preload.ts +++ b/packages/opencode/test/preload.ts @@ -35,6 +35,7 @@ process.env["XDG_CONFIG_HOME"] = path.join(dir, "config") process.env["XDG_STATE_HOME"] = path.join(dir, "state") process.env["OPENCODE_MODELS_PATH"] = path.join(import.meta.dir, "tool", "fixtures", "models-api.json") process.env["OPENCODE_EXPERIMENTAL_EVENT_SYSTEM"] = "true" +process.env["OPENCODE_EXPERIMENTAL_WORKSPACES"] = "true" // Set test home directory to isolate tests from user's actual home directory // This prevents tests from picking up real user configs/skills from ~/.claude/skills @@ -45,7 +46,6 @@ process.env["OPENCODE_TEST_HOME"] = testHome // Set test managed config directory to isolate tests from system managed settings const testManagedConfigDir = path.join(dir, "managed") process.env["OPENCODE_TEST_MANAGED_CONFIG_DIR"] = testManagedConfigDir -process.env["OPENCODE_DISABLE_DEFAULT_PLUGINS"] = "true" // Write the cache version file to prevent global/index.ts from clearing the cache const cacheDir = path.join(dir, "cache", "opencode") diff --git a/packages/opencode/test/project/instance-bootstrap.test.ts b/packages/opencode/test/project/instance-bootstrap.test.ts index 71521a765a..4be2a76113 100644 --- a/packages/opencode/test/project/instance-bootstrap.test.ts +++ b/packages/opencode/test/project/instance-bootstrap.test.ts @@ -1,11 +1,16 @@ -import { afterEach, expect, test } from "bun:test" +import { afterEach, expect } from "bun:test" import { existsSync } from "node:fs" import path from "node:path" import { pathToFileURL } from "node:url" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { Effect, Layer } from "effect" import { bootstrap as cliBootstrap } from "../../src/cli/bootstrap" -import { WithInstance } from "../../src/project/with-instance" -import { InstanceRuntime } from "../../src/project/instance-runtime" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" +import { InstanceLayer } from "../../src/project/instance-layer" +import { InstanceStore } from "../../src/project/instance-store" +import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" + +const it = testEffect(Layer.mergeAll(InstanceLayer.layer, CrossSpawnSpawner.defaultLayer)) // InstanceBootstrap must run before any code touches the instance — // originally tracked by PRs #25389 and #25449, now a permanent @@ -19,58 +24,64 @@ afterEach(async () => { await disposeAllInstances() }) -async function bootstrapFixture() { - return tmpdir({ - init: async (dir) => { - const marker = path.join(dir, "config-hook-fired") - const pluginFile = path.join(dir, "plugin.ts") - await Bun.write( - pluginFile, - [ - `const MARKER = ${JSON.stringify(marker)}`, - "export default async () => ({", - " config: async () => {", - ' await Bun.write(MARKER, "ran")', - " },", - "})", - "", - ].join("\n"), - ) - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - plugin: [pathToFileURL(pluginFile).href], - }), - ) - return marker - }, - }) -} - -test("WithInstance.provide runs InstanceBootstrap before fn", async () => { - await using tmp = await bootstrapFixture() - - await WithInstance.provide({ - directory: tmp.path, - fn: async () => "ok", - }) - - expect(existsSync(tmp.extra)).toBe(true) +const bootstrapFixture = Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + const marker = path.join(dir, "config-hook-fired") + const pluginFile = path.join(dir, "plugin.ts") + yield* Effect.promise(() => + Bun.write( + pluginFile, + [ + `const MARKER = ${JSON.stringify(marker)}`, + "export default async () => ({", + " config: async () => {", + ' await Bun.write(MARKER, "ran")', + " },", + "})", + "", + ].join("\n"), + ), + ) + yield* Effect.promise(() => + Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + plugin: [pathToFileURL(pluginFile).href], + }), + ), + ) + return { directory: dir, marker } }) -test("CLI bootstrap runs InstanceBootstrap before callback", async () => { - await using tmp = await bootstrapFixture() +it.live("InstanceStore.provide runs InstanceBootstrap before effect", () => + Effect.gen(function* () { + const tmp = yield* bootstrapFixture + const store = yield* InstanceStore.Service - await cliBootstrap(tmp.path, async () => "ok") + yield* store.provide({ directory: tmp.directory }, Effect.succeed("ok")) - expect(existsSync(tmp.extra)).toBe(true) -}) + expect(existsSync(tmp.marker)).toBe(true) + }), +) -test("InstanceRuntime.reloadInstance runs InstanceBootstrap", async () => { - await using tmp = await bootstrapFixture() +it.live("CLI bootstrap runs InstanceBootstrap before callback", () => + Effect.gen(function* () { + const tmp = yield* bootstrapFixture - await InstanceRuntime.reloadInstance({ directory: tmp.path }) + yield* Effect.promise(() => cliBootstrap(tmp.directory, async () => "ok")) - expect(existsSync(tmp.extra)).toBe(true) -}) + expect(existsSync(tmp.marker)).toBe(true) + }), +) + +it.live("InstanceStore.reload runs InstanceBootstrap", () => + Effect.gen(function* () { + const tmp = yield* bootstrapFixture + const store = yield* InstanceStore.Service + + yield* store.reload({ directory: tmp.directory }) + + expect(existsSync(tmp.marker)).toBe(true) + }), +) diff --git a/packages/opencode/test/project/instance.test.ts b/packages/opencode/test/project/instance.test.ts index 99b0f0666b..9c0f9150e1 100644 --- a/packages/opencode/test/project/instance.test.ts +++ b/packages/opencode/test/project/instance.test.ts @@ -1,13 +1,12 @@ -import { afterEach, describe, expect } from "bun:test" +import { describe, expect } from "bun:test" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" -import { Effect, Fiber, Layer } from "effect" +import { Deferred, Effect, Fiber, Layer } from "effect" import { InstanceRef } from "../../src/effect/instance-ref" import { registerDisposer } from "../../src/effect/instance-registry" import { InstanceBootstrap } from "../../src/project/bootstrap-service" import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { InstanceStore } from "../../src/project/instance-store" -import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture" +import { TestInstance, tmpdirScoped } from "../fixture/fixture" import { testEffect } from "../lib/effect" let bootstrapRun: Effect.Effect = Effect.void @@ -20,10 +19,22 @@ const it = testEffect( Layer.mergeAll(InstanceStore.defaultLayer, CrossSpawnSpawner.defaultLayer).pipe(Layer.provide(noopBootstrap)), ) -afterEach(async () => { - bootstrapRun = Effect.void - await disposeAllInstances() -}) +const setBootstrap = (run: Effect.Effect) => + Effect.acquireRelease( + Effect.sync(() => { + bootstrapRun = run + }), + () => + Effect.sync(() => { + bootstrapRun = Effect.void + }), + ) + +const registerDisposerScoped = (disposer: (directory: string) => Promise) => + Effect.acquireRelease( + Effect.sync(() => registerDisposer(disposer)), + (off) => Effect.sync(off), + ) describe("InstanceStore", () => { it.live("loads instance context without installing ALS for the caller", () => @@ -44,9 +55,11 @@ describe("InstanceStore", () => { const store = yield* InstanceStore.Service let initializedDirectory: string | undefined - bootstrapRun = Effect.gen(function* () { - initializedDirectory = (yield* InstanceRef)?.directory - }) + yield* setBootstrap( + Effect.gen(function* () { + initializedDirectory = (yield* InstanceRef)?.directory + }), + ) yield* store.load({ directory: dir }) expect(initializedDirectory).toBe(dir) @@ -60,9 +73,11 @@ describe("InstanceStore", () => { const store = yield* InstanceStore.Service let initialized = 0 - bootstrapRun = Effect.sync(() => { - initialized++ - }) + yield* setBootstrap( + Effect.sync(() => { + initialized++ + }), + ) const first = yield* store.load({ directory: dir }) const second = yield* store.load({ directory: dir }) @@ -75,26 +90,30 @@ describe("InstanceStore", () => { Effect.gen(function* () { const dir = yield* tmpdirScoped({ git: true }) const store = yield* InstanceStore.Service - const started = Promise.withResolvers() - const release = Promise.withResolvers() + const started = yield* Deferred.make() + const release = yield* Deferred.make() let initialized = 0 - bootstrapRun = Effect.promise(async () => { - initialized++ - started.resolve() - await release.promise - }) + yield* setBootstrap( + Effect.gen(function* () { + initialized++ + yield* Deferred.succeed(started, undefined) + yield* Deferred.await(release) + }), + ) const first = yield* store.load({ directory: dir }).pipe(Effect.forkScoped) - yield* Effect.promise(() => started.promise) + yield* Deferred.await(started) - bootstrapRun = Effect.sync(() => { - initialized++ - }) + yield* setBootstrap( + Effect.sync(() => { + initialized++ + }), + ) const second = yield* store.load({ directory: dir }).pipe(Effect.forkScoped) expect(initialized).toBe(1) - release.resolve() + yield* Deferred.succeed(release, undefined) const [firstCtx, secondCtx] = yield* Effect.all([Fiber.join(first), Fiber.join(second)]) expect(secondCtx).toBe(firstCtx) @@ -108,10 +127,12 @@ describe("InstanceStore", () => { const store = yield* InstanceStore.Service let attempts = 0 - bootstrapRun = Effect.sync(() => { - attempts++ - throw new Error("init failed") - }) + yield* setBootstrap( + Effect.sync(() => { + attempts++ + throw new Error("init failed") + }), + ) const failed = yield* store.load({ directory: dir }).pipe( Effect.as(false), Effect.catchCause(() => Effect.succeed(true)), @@ -119,9 +140,11 @@ describe("InstanceStore", () => { expect(failed).toBe(true) - bootstrapRun = Effect.sync(() => { - attempts++ - }) + yield* setBootstrap( + Effect.sync(() => { + attempts++ + }), + ) const ctx = yield* store.load({ directory: dir }) expect(ctx.directory).toBe(dir) @@ -147,24 +170,25 @@ describe("InstanceStore", () => { Effect.gen(function* () { const dir = yield* tmpdirScoped({ git: true }) const store = yield* InstanceStore.Service - const reloading = Promise.withResolvers() - const releaseReload = Promise.withResolvers() + const reloading = yield* Deferred.make() + const releaseReload = yield* Deferred.make() const disposed: Array = [] - const off = registerDisposer(async (directory) => { + yield* registerDisposerScoped(async (directory) => { disposed.push(directory) }) - yield* Effect.addFinalizer(() => Effect.sync(off)) const first = yield* store.load({ directory: dir }) - bootstrapRun = Effect.promise(async () => { - reloading.resolve() - await releaseReload.promise - }) + yield* setBootstrap( + Effect.gen(function* () { + yield* Deferred.succeed(reloading, undefined) + yield* Deferred.await(releaseReload) + }), + ) const reload = yield* store.reload({ directory: dir }).pipe(Effect.forkScoped) - yield* Effect.promise(() => reloading.promise) + yield* Deferred.await(reloading) const staleDispose = yield* store.dispose(first).pipe(Effect.forkScoped) - releaseReload.resolve() + yield* Deferred.succeed(releaseReload, undefined) const second = yield* Fiber.join(reload) yield* Fiber.join(staleDispose) @@ -178,23 +202,25 @@ describe("InstanceStore", () => { Effect.gen(function* () { const dir = yield* tmpdirScoped({ git: true }) const store = yield* InstanceStore.Service - const disposing = Promise.withResolvers() - const releaseDispose = Promise.withResolvers() + const disposing = yield* Deferred.make() + const releaseDispose = yield* Deferred.make<() => void>() const disposed: Array = [] - const off = registerDisposer(async (directory) => { + yield* registerDisposerScoped((directory) => { disposed.push(directory) - disposing.resolve() - await releaseDispose.promise + Deferred.doneUnsafe(disposing, Effect.void) + return new Promise((resolve) => { + Deferred.doneUnsafe(releaseDispose, Effect.succeed(resolve)) + }) }) - yield* Effect.addFinalizer(() => Effect.sync(off)) yield* store.load({ directory: dir }) const first = yield* store.disposeAll().pipe(Effect.forkScoped) - yield* Effect.promise(() => disposing.promise) + yield* Deferred.await(disposing) + const release = yield* Deferred.await(releaseDispose) const second = yield* store.disposeAll().pipe(Effect.forkScoped) expect(disposed).toEqual([dir]) - releaseDispose.resolve() + yield* Effect.sync(release) yield* Effect.all([Fiber.join(first), Fiber.join(second)]) expect(disposed).toEqual([dir]) }), @@ -206,10 +232,9 @@ describe("InstanceStore", () => { const dir2 = yield* tmpdirScoped({ git: true }) const store = yield* InstanceStore.Service const disposed: Array = [] - const off = registerDisposer(async (directory) => { + yield* registerDisposerScoped(async (directory) => { disposed.push(directory) }) - yield* Effect.addFinalizer(() => Effect.sync(off)) yield* store.load({ directory: dir1 }) yield* store.disposeAll() @@ -221,19 +246,19 @@ describe("InstanceStore", () => { }), ) - it.live("provides legacy Promise callers with instance ALS", () => - Effect.gen(function* () { - const dir = yield* tmpdirScoped({ git: true }) + it.instance( + "provides legacy Promise callers with instance ALS", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const ctx = yield* InstanceRef + if (!ctx) throw new Error("InstanceRef not provided") - const directory = yield* Effect.promise(() => - WithInstance.provide({ - directory: dir, - fn: () => Instance.directory, - }), - ) + const directory = yield* Effect.promise(() => Promise.resolve(Instance.restore(ctx, () => Instance.directory))) - expect(directory).toBe(dir) - expect(() => Instance.current).toThrow() - }), + expect(directory).toBe(test.directory) + expect(() => Instance.current).toThrow() + }), + { git: true }, ) }) diff --git a/packages/opencode/test/project/migrate-global.test.ts b/packages/opencode/test/project/migrate-global.test.ts index c476c108b4..6efd670c5c 100644 --- a/packages/opencode/test/project/migrate-global.test.ts +++ b/packages/opencode/test/project/migrate-global.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import { Project } from "@/project/project" import { Database } from "@/storage/db" import { eq } from "drizzle-orm" @@ -8,19 +8,14 @@ import { ProjectID } from "../../src/project/schema" import { SessionID } from "../../src/session/schema" import * as Log from "@opencode-ai/core/util/log" import { $ } from "bun" -import { tmpdir } from "../fixture/fixture" -import { Effect } from "effect" +import { tmpdirScoped } from "../fixture/fixture" +import { Effect, Layer } from "effect" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { testEffect } from "../lib/effect" -Log.init({ print: false }) +void Log.init({ print: false }) -function run(fn: (svc: Project.Interface) => Effect.Effect) { - return Effect.runPromise( - Effect.gen(function* () { - const svc = yield* Project.Service - return yield* fn(svc) - }).pipe(Effect.provide(Project.defaultLayer)), - ) -} +const it = testEffect(Layer.mergeAll(Project.defaultLayer, CrossSpawnSpawner.defaultLayer)) function legacySessionID() { // Global-session migration covers persisted IDs from before prefixed session IDs. @@ -63,91 +58,102 @@ function ensureGlobal() { } describe("migrateFromGlobal", () => { - test("migrates global sessions on first project creation", async () => { - // 1. Start with git init but no commits — creates "global" project row - await using tmp = await tmpdir() - await $`git init`.cwd(tmp.path).quiet() - await $`git config user.name "Test"`.cwd(tmp.path).quiet() - await $`git config user.email "test@opencode.test"`.cwd(tmp.path).quiet() - await $`git config commit.gpgsign false`.cwd(tmp.path).quiet() - const { project: pre } = await run((svc) => svc.fromDirectory(tmp.path)) - expect(pre.id).toBe(ProjectID.global) + it.live("migrates global sessions on first project creation", () => + Effect.gen(function* () { + // 1. Start with git init but no commits — creates "global" project row + const tmp = yield* tmpdirScoped() + yield* Effect.promise(() => $`git init`.cwd(tmp).quiet()) + yield* Effect.promise(() => $`git config user.name "Test"`.cwd(tmp).quiet()) + yield* Effect.promise(() => $`git config user.email "test@opencode.test"`.cwd(tmp).quiet()) + yield* Effect.promise(() => $`git config commit.gpgsign false`.cwd(tmp).quiet()) + const projects = yield* Project.Service + const { project: pre } = yield* projects.fromDirectory(tmp) + expect(pre.id).toBe(ProjectID.global) - // 2. Seed a session under "global" with matching directory - const id = legacySessionID() - seed({ id, dir: tmp.path, project: ProjectID.global }) + // 2. Seed a session under "global" with matching directory + const id = legacySessionID() + yield* Effect.sync(() => seed({ id, dir: tmp, project: ProjectID.global })) - // 3. Make a commit so the project gets a real ID - await $`git commit --allow-empty -m "root"`.cwd(tmp.path).quiet() + // 3. Make a commit so the project gets a real ID + yield* Effect.promise(() => $`git commit --allow-empty -m "root"`.cwd(tmp).quiet()) - const { project: real } = await run((svc) => svc.fromDirectory(tmp.path)) - expect(real.id).not.toBe(ProjectID.global) + const { project: real } = yield* projects.fromDirectory(tmp) + expect(real.id).not.toBe(ProjectID.global) - // 4. The session should have been migrated to the real project ID - const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) - expect(row).toBeDefined() - expect(row!.project_id).toBe(real.id) - }) + // 4. The session should have been migrated to the real project ID + const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) + expect(row).toBeDefined() + expect(row!.project_id).toBe(real.id) + }), + ) - test("migrates global sessions even when project row already exists", async () => { - // 1. Create a repo with a commit — real project ID created immediately - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) - expect(project.id).not.toBe(ProjectID.global) + it.live("migrates global sessions even when project row already exists", () => + Effect.gen(function* () { + // 1. Create a repo with a commit — real project ID created immediately + const tmp = yield* tmpdirScoped({ git: true }) + const projects = yield* Project.Service + const { project } = yield* projects.fromDirectory(tmp) + expect(project.id).not.toBe(ProjectID.global) - // 2. Ensure "global" project row exists (as it would from a prior no-git session) - ensureGlobal() + // 2. Ensure "global" project row exists (as it would from a prior no-git session) + yield* Effect.sync(() => ensureGlobal()) - // 3. Seed a session under "global" with matching directory. - // This simulates a session created before git init that wasn't - // present when the real project row was first created. - const id = legacySessionID() - seed({ id, dir: tmp.path, project: ProjectID.global }) + // 3. Seed a session under "global" with matching directory. + // This simulates a session created before git init that wasn't + // present when the real project row was first created. + const id = legacySessionID() + yield* Effect.sync(() => seed({ id, dir: tmp, project: ProjectID.global })) - // 4. Call fromDirectory again — project row already exists, - // so the current code skips migration entirely. This is the bug. - await run((svc) => svc.fromDirectory(tmp.path)) + // 4. Call fromDirectory again — project row already exists, + // so the current code skips migration entirely. This is the bug. + yield* projects.fromDirectory(tmp) - const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) - expect(row).toBeDefined() - expect(row!.project_id).toBe(project.id) - }) + const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) + expect(row).toBeDefined() + expect(row!.project_id).toBe(project.id) + }), + ) - test("does not claim sessions with empty directory", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) - expect(project.id).not.toBe(ProjectID.global) + it.live("does not claim sessions with empty directory", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const projects = yield* Project.Service + const { project } = yield* projects.fromDirectory(tmp) + expect(project.id).not.toBe(ProjectID.global) - ensureGlobal() + yield* Effect.sync(() => ensureGlobal()) - // Legacy sessions may lack a directory value. - // Without a matching origin directory, they should remain global. - const id = legacySessionID() - seed({ id, dir: "", project: ProjectID.global }) + // Legacy sessions may lack a directory value. + // Without a matching origin directory, they should remain global. + const id = legacySessionID() + yield* Effect.sync(() => seed({ id, dir: "", project: ProjectID.global })) - await run((svc) => svc.fromDirectory(tmp.path)) + yield* projects.fromDirectory(tmp) - const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) - expect(row).toBeDefined() - expect(row!.project_id).toBe(ProjectID.global) - }) + const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) + expect(row).toBeDefined() + expect(row!.project_id).toBe(ProjectID.global) + }), + ) - test("does not steal sessions from unrelated directories", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) - expect(project.id).not.toBe(ProjectID.global) + it.live("does not steal sessions from unrelated directories", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const projects = yield* Project.Service + const { project } = yield* projects.fromDirectory(tmp) + expect(project.id).not.toBe(ProjectID.global) - ensureGlobal() + yield* Effect.sync(() => ensureGlobal()) - // Seed a session under "global" but for a DIFFERENT directory - const id = legacySessionID() - seed({ id, dir: "/some/other/dir", project: ProjectID.global }) + // Seed a session under "global" but for a DIFFERENT directory + const id = legacySessionID() + yield* Effect.sync(() => seed({ id, dir: "/some/other/dir", project: ProjectID.global })) - await run((svc) => svc.fromDirectory(tmp.path)) - - const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) - expect(row).toBeDefined() - // Should remain under "global" — not stolen - expect(row!.project_id).toBe(ProjectID.global) - }) + yield* projects.fromDirectory(tmp) + const row = Database.use((db) => db.select().from(SessionTable).where(eq(SessionTable.id, id)).get()) + expect(row).toBeDefined() + // Should remain under "global" — not stolen + expect(row!.project_id).toBe(ProjectID.global) + }), + ) }) diff --git a/packages/opencode/test/project/project.test.ts b/packages/opencode/test/project/project.test.ts index 9906b31645..c9257d6575 100644 --- a/packages/opencode/test/project/project.test.ts +++ b/packages/opencode/test/project/project.test.ts @@ -4,26 +4,28 @@ import { Project } from "@/project/project" import * as Log from "@opencode-ai/core/util/log" import { $ } from "bun" import path from "path" -import { tmpdir } from "../fixture/fixture" +import { tmpdirScoped } from "../fixture/fixture" import { GlobalBus } from "../../src/bus/global" import { ProjectID } from "../../src/project/schema" -import { Effect, Layer, Stream } from "effect" +import { Cause, Effect, Exit, Layer, Stream } from "effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { NodePath } from "@effect/platform-node" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) const encoder = new TextEncoder() -function run(fn: (svc: Project.Interface) => Effect.Effect, layer = Project.defaultLayer) { - return Effect.runPromise( - Effect.gen(function* () { - const svc = yield* Project.Service - return yield* fn(svc) - }).pipe(Effect.provide(layer)), - ) +const layer = Layer.mergeAll(Project.defaultLayer, CrossSpawnSpawner.defaultLayer) +const it = testEffect(layer) + +function run(fn: (svc: Project.Interface) => Effect.Effect) { + return Effect.gen(function* () { + const svc = yield* Project.Service + return yield* fn(svc) + }) } /** @@ -70,400 +72,459 @@ function projectLayerWithFailure(failArg: string) { ) } +const failureIt = (failArg: string) => + testEffect(Layer.mergeAll(projectLayerWithFailure(failArg), CrossSpawnSpawner.defaultLayer)) + describe("Project.fromDirectory", () => { - test("should handle git repository with no commits", async () => { - await using tmp = await tmpdir() - await $`git init`.cwd(tmp.path).quiet() + it.live("should handle git repository with no commits", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* Effect.promise(() => $`git init`.cwd(tmp).quiet()) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - expect(project).toBeDefined() - expect(project.id).toBe(ProjectID.global) - expect(project.vcs).toBe("git") - expect(project.worktree).toBe(tmp.path) + expect(project).toBeDefined() + expect(project.id).toBe(ProjectID.global) + expect(project.vcs).toBe("git") + expect(project.worktree).toBe(tmp) - const opencodeFile = path.join(tmp.path, ".git", "opencode") - expect(await Bun.file(opencodeFile).exists()).toBe(false) - }) + const opencodeFile = path.join(tmp, ".git", "opencode") + expect(yield* Effect.promise(() => Bun.file(opencodeFile).exists())).toBe(false) + }), + ) - test("should handle git repository with commits", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("should handle git repository with commits", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - expect(project).toBeDefined() - expect(project.id).not.toBe(ProjectID.global) - expect(project.vcs).toBe("git") - expect(project.worktree).toBe(tmp.path) + expect(project).toBeDefined() + expect(project.id).not.toBe(ProjectID.global) + expect(project.vcs).toBe("git") + expect(project.worktree).toBe(tmp) - const opencodeFile = path.join(tmp.path, ".git", "opencode") - expect(await Bun.file(opencodeFile).exists()).toBe(true) - }) + const opencodeFile = path.join(tmp, ".git", "opencode") + expect(yield* Effect.promise(() => Bun.file(opencodeFile).exists())).toBe(true) + }), + ) - test("returns global for non-git directory", async () => { - await using tmp = await tmpdir() - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) - expect(project.id).toBe(ProjectID.global) - }) + it.live("returns global for non-git directory", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) + expect(project.id).toBe(ProjectID.global) + }), + ) - test("derives stable project ID from root commit", async () => { - await using tmp = await tmpdir({ git: true }) - const { project: a } = await run((svc) => svc.fromDirectory(tmp.path)) - const { project: b } = await run((svc) => svc.fromDirectory(tmp.path)) - expect(b.id).toBe(a.id) - }) + it.live("derives stable project ID from root commit", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project: a } = yield* run((svc) => svc.fromDirectory(tmp)) + const { project: b } = yield* run((svc) => svc.fromDirectory(tmp)) + expect(b.id).toBe(a.id) + }), + ) }) describe("Project.fromDirectory git failure paths", () => { - test("keeps vcs when rev-list exits non-zero (no commits)", async () => { - await using tmp = await tmpdir() - await $`git init`.cwd(tmp.path).quiet() + it.live("keeps vcs when rev-list exits non-zero (no commits)", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* Effect.promise(() => $`git init`.cwd(tmp).quiet()) - // rev-list fails because HEAD doesn't exist yet — this is the natural scenario - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) - expect(project.vcs).toBe("git") - expect(project.id).toBe(ProjectID.global) - expect(project.worktree).toBe(tmp.path) - }) + // rev-list fails because HEAD doesn't exist yet: this is the natural scenario. + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) + expect(project.vcs).toBe("git") + expect(project.id).toBe(ProjectID.global) + expect(project.worktree).toBe(tmp) + }), + ) - test("handles show-toplevel failure gracefully", async () => { - await using tmp = await tmpdir({ git: true }) - const layer = projectLayerWithFailure("--show-toplevel") + failureIt("--show-toplevel").live("handles show-toplevel failure gracefully", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const { project, sandbox } = await run((svc) => svc.fromDirectory(tmp.path), layer) - expect(project.worktree).toBe(tmp.path) - expect(sandbox).toBe(tmp.path) - }) + const { project, sandbox } = yield* run((svc) => svc.fromDirectory(tmp)) + expect(project.worktree).toBe(tmp) + expect(sandbox).toBe(tmp) + }), + ) - test("handles git-common-dir failure gracefully", async () => { - await using tmp = await tmpdir({ git: true }) - const layer = projectLayerWithFailure("--git-common-dir") + failureIt("--git-common-dir").live("handles git-common-dir failure gracefully", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const { project, sandbox } = await run((svc) => svc.fromDirectory(tmp.path), layer) - expect(project.worktree).toBe(tmp.path) - expect(sandbox).toBe(tmp.path) - }) + const { project, sandbox } = yield* run((svc) => svc.fromDirectory(tmp)) + expect(project.worktree).toBe(tmp) + expect(sandbox).toBe(tmp) + }), + ) }) describe("Project.fromDirectory with worktrees", () => { - test("should set worktree to root when called from root", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("should set worktree to root when called from root", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const { project, sandbox } = await run((svc) => svc.fromDirectory(tmp.path)) + const { project, sandbox } = yield* run((svc) => svc.fromDirectory(tmp)) - expect(project.worktree).toBe(tmp.path) - expect(sandbox).toBe(tmp.path) - expect(project.sandboxes).not.toContain(tmp.path) - }) + expect(project.worktree).toBe(tmp) + expect(sandbox).toBe(tmp) + expect(project.sandboxes).not.toContain(tmp) + }), + ) - test("should set worktree to root when called from a worktree", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("should set worktree to root when called from a worktree", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const worktreePath = path.join(tmp.path, "..", path.basename(tmp.path) + "-worktree") - try { - await $`git worktree add ${worktreePath} -b test-branch-${Date.now()}`.cwd(tmp.path).quiet() + const worktreePath = path.join(tmp, "..", path.basename(tmp) + "-worktree") + yield* Effect.addFinalizer(() => + Effect.promise(() => + $`git worktree remove ${worktreePath}` + .cwd(tmp) + .quiet() + .catch(() => {}), + ), + ) + yield* Effect.promise(() => $`git worktree add ${worktreePath} -b test-branch-${Date.now()}`.cwd(tmp).quiet()) - const { project, sandbox } = await run((svc) => svc.fromDirectory(worktreePath)) + const { project, sandbox } = yield* run((svc) => svc.fromDirectory(worktreePath)) - expect(project.worktree).toBe(tmp.path) + expect(project.worktree).toBe(tmp) expect(sandbox).toBe(worktreePath) expect(project.sandboxes).toContain(worktreePath) - expect(project.sandboxes).not.toContain(tmp.path) - } finally { - await $`git worktree remove ${worktreePath}` - .cwd(tmp.path) - .quiet() - .catch(() => {}) - } - }) + expect(project.sandboxes).not.toContain(tmp) + }), + ) - test("worktree should share project ID with main repo", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("worktree should share project ID with main repo", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const { project: main } = await run((svc) => svc.fromDirectory(tmp.path)) + const { project: main } = yield* run((svc) => svc.fromDirectory(tmp)) - const worktreePath = path.join(tmp.path, "..", path.basename(tmp.path) + "-wt-shared") - try { - await $`git worktree add ${worktreePath} -b shared-${Date.now()}`.cwd(tmp.path).quiet() + const worktreePath = path.join(tmp, "..", path.basename(tmp) + "-wt-shared") + yield* Effect.addFinalizer(() => + Effect.promise(() => + $`git worktree remove ${worktreePath}` + .cwd(tmp) + .quiet() + .catch(() => {}), + ), + ) + yield* Effect.promise(() => $`git worktree add ${worktreePath} -b shared-${Date.now()}`.cwd(tmp).quiet()) - const { project: wt } = await run((svc) => svc.fromDirectory(worktreePath)) + const { project: wt } = yield* run((svc) => svc.fromDirectory(worktreePath)) expect(wt.id).toBe(main.id) // Cache should live in the common .git dir, not the worktree's .git file - const cache = path.join(tmp.path, ".git", "opencode") - const exists = await Bun.file(cache).exists() + const cache = path.join(tmp, ".git", "opencode") + const exists = yield* Effect.promise(() => Bun.file(cache).exists()) expect(exists).toBe(true) - } finally { - await $`git worktree remove ${worktreePath}` - .cwd(tmp.path) - .quiet() - .catch(() => {}) - } - }) + }), + ) - test("separate clones of the same repo should share project ID", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("separate clones of the same repo should share project ID", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - // Create a bare remote, push, then clone into a second directory - const bare = tmp.path + "-bare" - const clone = tmp.path + "-clone" - try { - await $`git clone --bare ${tmp.path} ${bare}`.quiet() - await $`git clone ${bare} ${clone}`.quiet() + // Create a bare remote, push, then clone into a second directory + const bare = tmp + "-bare" + const clone = tmp + "-clone" + yield* Effect.addFinalizer(() => + Effect.promise(() => $`rm -rf ${bare} ${clone}`.quiet().nothrow()).pipe(Effect.ignore), + ) + yield* Effect.promise(() => $`git clone --bare ${tmp} ${bare}`.quiet()) + yield* Effect.promise(() => $`git clone ${bare} ${clone}`.quiet()) - const { project: a } = await run((svc) => svc.fromDirectory(tmp.path)) - const { project: b } = await run((svc) => svc.fromDirectory(clone)) + const { project: a } = yield* run((svc) => svc.fromDirectory(tmp)) + const { project: b } = yield* run((svc) => svc.fromDirectory(clone)) expect(b.id).toBe(a.id) - } finally { - await $`rm -rf ${bare} ${clone}`.quiet().nothrow() - } - }) + }), + ) - test("should accumulate multiple worktrees in sandboxes", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("should accumulate multiple worktrees in sandboxes", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const worktree1 = path.join(tmp.path, "..", path.basename(tmp.path) + "-wt1") - const worktree2 = path.join(tmp.path, "..", path.basename(tmp.path) + "-wt2") - try { - await $`git worktree add ${worktree1} -b branch-${Date.now()}`.cwd(tmp.path).quiet() - await $`git worktree add ${worktree2} -b branch-${Date.now() + 1}`.cwd(tmp.path).quiet() + const worktree1 = path.join(tmp, "..", path.basename(tmp) + "-wt1") + const worktree2 = path.join(tmp, "..", path.basename(tmp) + "-wt2") + yield* Effect.addFinalizer(() => + Effect.gen(function* () { + yield* Effect.promise(() => + $`git worktree remove ${worktree1}` + .cwd(tmp) + .quiet() + .catch(() => {}), + ) + yield* Effect.promise(() => + $`git worktree remove ${worktree2}` + .cwd(tmp) + .quiet() + .catch(() => {}), + ) + }), + ) + yield* Effect.promise(() => $`git worktree add ${worktree1} -b branch-${Date.now()}`.cwd(tmp).quiet()) + yield* Effect.promise(() => $`git worktree add ${worktree2} -b branch-${Date.now() + 1}`.cwd(tmp).quiet()) - await run((svc) => svc.fromDirectory(worktree1)) - const { project } = await run((svc) => svc.fromDirectory(worktree2)) + yield* run((svc) => svc.fromDirectory(worktree1)) + const { project } = yield* run((svc) => svc.fromDirectory(worktree2)) - expect(project.worktree).toBe(tmp.path) + expect(project.worktree).toBe(tmp) expect(project.sandboxes).toContain(worktree1) expect(project.sandboxes).toContain(worktree2) - expect(project.sandboxes).not.toContain(tmp.path) - } finally { - await $`git worktree remove ${worktree1}` - .cwd(tmp.path) - .quiet() - .catch(() => {}) - await $`git worktree remove ${worktree2}` - .cwd(tmp.path) - .quiet() - .catch(() => {}) - } - }) + expect(project.sandboxes).not.toContain(tmp) + }), + ) }) describe("Project.discover", () => { - test("should discover favicon.png in root", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should discover favicon.png in root", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const pngData = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]) - await Bun.write(path.join(tmp.path, "favicon.png"), pngData) + const pngData = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]) + yield* Effect.promise(() => Bun.write(path.join(tmp, "favicon.png"), pngData)) - await run((svc) => svc.discover(project)) + yield* run((svc) => svc.discover(project)) - const updated = Project.get(project.id) - expect(updated).toBeDefined() - expect(updated!.icon).toBeDefined() - expect(updated!.icon?.url).toStartWith("data:") - expect(updated!.icon?.url).toContain("base64") - expect(updated!.icon?.color).toBeUndefined() - }) + const updated = Project.get(project.id) + expect(updated).toBeDefined() + expect(updated!.icon).toBeDefined() + expect(updated!.icon?.url).toStartWith("data:") + expect(updated!.icon?.url).toContain("base64") + expect(updated!.icon?.color).toBeUndefined() + }), + ) - test("should not discover non-image files", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should not discover non-image files", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - await Bun.write(path.join(tmp.path, "favicon.txt"), "not an image") + yield* Effect.promise(() => Bun.write(path.join(tmp, "favicon.txt"), "not an image")) - await run((svc) => svc.discover(project)) + yield* run((svc) => svc.discover(project)) - const updated = Project.get(project.id) - expect(updated).toBeDefined() - expect(updated!.icon).toBeUndefined() - }) + const updated = Project.get(project.id) + expect(updated).toBeDefined() + expect(updated!.icon).toBeUndefined() + }), + ) - test("should not discover favicon when override is set", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should not discover favicon when override is set", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - await run((svc) => - svc.update({ - projectID: project.id, - icon: { override: "data:image/png;base64,override" }, - }), - ) + yield* run((svc) => + svc.update({ + projectID: project.id, + icon: { override: "data:image/png;base64,override" }, + }), + ) - const updatedProject = await run((svc) => svc.get(project.id)) - if (!updatedProject) throw new Error("Project not found") + const updatedProject = yield* run((svc) => svc.get(project.id)) + if (!updatedProject) throw new Error("Project not found") - const pngData = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]) - await Bun.write(path.join(tmp.path, "favicon.png"), pngData) + const pngData = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]) + yield* Effect.promise(() => Bun.write(path.join(tmp, "favicon.png"), pngData)) - await run((svc) => svc.discover(updatedProject)) + yield* run((svc) => svc.discover(updatedProject)) - const updated = Project.get(project.id) - expect(updated).toBeDefined() - expect(updated!.icon?.override).toBe("data:image/png;base64,override") - expect(updated!.icon?.url).toBeUndefined() - }) + const updated = Project.get(project.id) + expect(updated).toBeDefined() + expect(updated!.icon?.override).toBe("data:image/png;base64,override") + expect(updated!.icon?.url).toBeUndefined() + }), + ) }) describe("Project.update", () => { - test("should update name", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should update name", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const updated = await run((svc) => - svc.update({ - projectID: project.id, - name: "New Project Name", - }), - ) + const updated = yield* run((svc) => + svc.update({ + projectID: project.id, + name: "New Project Name", + }), + ) - expect(updated.name).toBe("New Project Name") + expect(updated.name).toBe("New Project Name") - const fromDb = Project.get(project.id) - expect(fromDb?.name).toBe("New Project Name") - }) + const fromDb = Project.get(project.id) + expect(fromDb?.name).toBe("New Project Name") + }), + ) - test("should update icon url", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should update icon url", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const updated = await run((svc) => - svc.update({ - projectID: project.id, - icon: { url: "https://example.com/icon.png" }, - }), - ) + const updated = yield* run((svc) => + svc.update({ + projectID: project.id, + icon: { url: "https://example.com/icon.png" }, + }), + ) - expect(updated.icon?.url).toBe("https://example.com/icon.png") + expect(updated.icon?.url).toBe("https://example.com/icon.png") - const fromDb = Project.get(project.id) - expect(fromDb?.icon?.url).toBe("https://example.com/icon.png") - }) + const fromDb = Project.get(project.id) + expect(fromDb?.icon?.url).toBe("https://example.com/icon.png") + }), + ) - test("should update icon color", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should update icon color", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const updated = await run((svc) => - svc.update({ - projectID: project.id, - icon: { color: "#ff0000" }, - }), - ) + const updated = yield* run((svc) => + svc.update({ + projectID: project.id, + icon: { color: "#ff0000" }, + }), + ) - expect(updated.icon?.color).toBe("#ff0000") + expect(updated.icon?.color).toBe("#ff0000") - const fromDb = Project.get(project.id) - expect(fromDb?.icon?.color).toBe("#ff0000") - }) + const fromDb = Project.get(project.id) + expect(fromDb?.icon?.color).toBe("#ff0000") + }), + ) - test("should update icon override", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should update icon override", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const updated = await run((svc) => - svc.update({ - projectID: project.id, - icon: { override: "data:image/png;base64,abc123" }, - }), - ) + const updated = yield* run((svc) => + svc.update({ + projectID: project.id, + icon: { override: "data:image/png;base64,abc123" }, + }), + ) - expect(updated.icon?.override).toBe("data:image/png;base64,abc123") + expect(updated.icon?.override).toBe("data:image/png;base64,abc123") - const fromDb = Project.get(project.id) - expect(fromDb?.icon?.override).toBe("data:image/png;base64,abc123") - }) + const fromDb = Project.get(project.id) + expect(fromDb?.icon?.override).toBe("data:image/png;base64,abc123") + }), + ) - test("should update commands", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should update commands", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const updated = await run((svc) => - svc.update({ - projectID: project.id, - commands: { start: "npm run dev" }, - }), - ) + const updated = yield* run((svc) => + svc.update({ + projectID: project.id, + commands: { start: "npm run dev" }, + }), + ) - expect(updated.commands?.start).toBe("npm run dev") + expect(updated.commands?.start).toBe("npm run dev") - const fromDb = Project.get(project.id) - expect(fromDb?.commands?.start).toBe("npm run dev") - }) + const fromDb = Project.get(project.id) + expect(fromDb?.commands?.start).toBe("npm run dev") + }), + ) - test("should throw error when project not found", async () => { - await expect( - run((svc) => + it.live("should throw error when project not found", () => + Effect.gen(function* () { + const exit = yield* run((svc) => svc.update({ projectID: ProjectID.make("nonexistent-project-id"), name: "Should Fail", }), - ), - ).rejects.toThrow("Project not found: nonexistent-project-id") - }) + ).pipe(Effect.exit) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const error = Cause.squash(exit.cause) + expect(error instanceof Error ? error.message : String(error)).toContain( + "Project not found: nonexistent-project-id", + ) + } + }), + ) - test("should emit GlobalBus event on update", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should emit GlobalBus event on update", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - let eventPayload: any = null - const on = (data: any) => { - eventPayload = data - } - GlobalBus.on("event", on) + let eventPayload: any = null + const on = (data: any) => { + eventPayload = data + } + GlobalBus.on("event", on) + yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", on))) - try { - await run((svc) => svc.update({ projectID: project.id, name: "Updated Name" })) + yield* run((svc) => svc.update({ projectID: project.id, name: "Updated Name" })) expect(eventPayload).not.toBeNull() expect(eventPayload.payload.type).toBe("project.updated") expect(eventPayload.payload.properties.name).toBe("Updated Name") - } finally { - GlobalBus.off("event", on) - } - }) + }), + ) - test("should update multiple fields at once", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("should update multiple fields at once", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const updated = await run((svc) => - svc.update({ - projectID: project.id, - name: "Multi Update", - icon: { url: "https://example.com/favicon.ico", override: "data:image/png;base64,abc123", color: "#00ff00" }, - commands: { start: "make start" }, - }), - ) + const updated = yield* run((svc) => + svc.update({ + projectID: project.id, + name: "Multi Update", + icon: { url: "https://example.com/favicon.ico", override: "data:image/png;base64,abc123", color: "#00ff00" }, + commands: { start: "make start" }, + }), + ) - expect(updated.name).toBe("Multi Update") - expect(updated.icon?.url).toBe("https://example.com/favicon.ico") - expect(updated.icon?.override).toBe("data:image/png;base64,abc123") - expect(updated.icon?.color).toBe("#00ff00") - expect(updated.commands?.start).toBe("make start") - }) + expect(updated.name).toBe("Multi Update") + expect(updated.icon?.url).toBe("https://example.com/favicon.ico") + expect(updated.icon?.override).toBe("data:image/png;base64,abc123") + expect(updated.icon?.color).toBe("#00ff00") + expect(updated.commands?.start).toBe("make start") + }), + ) }) describe("Project.list and Project.get", () => { - test("list returns all projects", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("list returns all projects", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const all = Project.list() - expect(all.length).toBeGreaterThan(0) - expect(all.find((p) => p.id === project.id)).toBeDefined() - }) + const all = Project.list() + expect(all.length).toBeGreaterThan(0) + expect(all.find((p) => p.id === project.id)).toBeDefined() + }), + ) - test("get returns project by id", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("get returns project by id", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - const found = Project.get(project.id) - expect(found).toBeDefined() - expect(found!.id).toBe(project.id) - }) + const found = Project.get(project.id) + expect(found).toBeDefined() + expect(found!.id).toBe(project.id) + }), + ) test("get returns undefined for unknown id", () => { const found = Project.get(ProjectID.make("nonexistent")) @@ -472,65 +533,74 @@ describe("Project.list and Project.get", () => { }) describe("Project.setInitialized", () => { - test("sets time_initialized on project", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) + it.live("sets time_initialized on project", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) - expect(project.time.initialized).toBeUndefined() + expect(project.time.initialized).toBeUndefined() - Project.setInitialized(project.id) + Project.setInitialized(project.id) - const updated = Project.get(project.id) - expect(updated?.time.initialized).toBeDefined() - }) + const updated = Project.get(project.id) + expect(updated?.time.initialized).toBeDefined() + }), + ) }) describe("Project.addSandbox and Project.removeSandbox", () => { - test("addSandbox adds directory and removeSandbox removes it", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) - const sandboxDir = path.join(tmp.path, "sandbox-test") + it.live("addSandbox adds directory and removeSandbox removes it", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) + const sandboxDir = path.join(tmp, "sandbox-test") - await run((svc) => svc.addSandbox(project.id, sandboxDir)) + yield* run((svc) => svc.addSandbox(project.id, sandboxDir)) - let found = Project.get(project.id) - expect(found?.sandboxes).toContain(sandboxDir) + let found = Project.get(project.id) + expect(found?.sandboxes).toContain(sandboxDir) - await run((svc) => svc.removeSandbox(project.id, sandboxDir)) + yield* run((svc) => svc.removeSandbox(project.id, sandboxDir)) - found = Project.get(project.id) - expect(found?.sandboxes).not.toContain(sandboxDir) - }) + found = Project.get(project.id) + expect(found?.sandboxes).not.toContain(sandboxDir) + }), + ) - test("addSandbox emits GlobalBus event", async () => { - await using tmp = await tmpdir({ git: true }) - const { project } = await run((svc) => svc.fromDirectory(tmp.path)) - const sandboxDir = path.join(tmp.path, "sandbox-event") + it.live("addSandbox emits GlobalBus event", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) + const { project } = yield* run((svc) => svc.fromDirectory(tmp)) + const sandboxDir = path.join(tmp, "sandbox-event") - const events: any[] = [] - const on = (evt: any) => events.push(evt) - GlobalBus.on("event", on) + const events: any[] = [] + const on = (evt: any) => events.push(evt) + GlobalBus.on("event", on) + yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", on))) - await run((svc) => svc.addSandbox(project.id, sandboxDir)) + yield* run((svc) => svc.addSandbox(project.id, sandboxDir)) - GlobalBus.off("event", on) - expect(events.some((e) => e.payload.type === Project.Event.Updated.type)).toBe(true) - }) + expect(events.some((e) => e.payload.type === Project.Event.Updated.type)).toBe(true) + }), + ) }) describe("Project.fromDirectory with bare repos", () => { - test("worktree from bare repo should cache in bare repo, not parent", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("worktree from bare repo should cache in bare repo, not parent", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const parentDir = path.dirname(tmp.path) - const barePath = path.join(parentDir, `bare-${Date.now()}.git`) - const worktreePath = path.join(parentDir, `worktree-${Date.now()}`) + const parentDir = path.dirname(tmp) + const barePath = path.join(parentDir, `bare-${Date.now()}.git`) + const worktreePath = path.join(parentDir, `worktree-${Date.now()}`) + yield* Effect.addFinalizer(() => + Effect.promise(() => $`rm -rf ${barePath} ${worktreePath}`.quiet().nothrow()).pipe(Effect.ignore), + ) - try { - await $`git clone --bare ${tmp.path} ${barePath}`.quiet() - await $`git worktree add ${worktreePath} HEAD`.cwd(barePath).quiet() + yield* Effect.promise(() => $`git clone --bare ${tmp} ${barePath}`.quiet()) + yield* Effect.promise(() => $`git worktree add ${worktreePath} HEAD`.cwd(barePath).quiet()) - const { project } = await run((svc) => svc.fromDirectory(worktreePath)) + const { project } = yield* run((svc) => svc.fromDirectory(worktreePath)) expect(project.id).not.toBe(ProjectID.global) expect(project.worktree).toBe(barePath) @@ -538,31 +608,34 @@ describe("Project.fromDirectory with bare repos", () => { const correctCache = path.join(barePath, "opencode") const wrongCache = path.join(parentDir, ".git", "opencode") - expect(await Bun.file(correctCache).exists()).toBe(true) - expect(await Bun.file(wrongCache).exists()).toBe(false) - } finally { - await $`rm -rf ${barePath} ${worktreePath}`.quiet().nothrow() - } - }) + expect(yield* Effect.promise(() => Bun.file(correctCache).exists())).toBe(true) + expect(yield* Effect.promise(() => Bun.file(wrongCache).exists())).toBe(false) + }), + ) - test("different bare repos under same parent should not share project ID", async () => { - await using tmp1 = await tmpdir({ git: true }) - await using tmp2 = await tmpdir({ git: true }) + it.live("different bare repos under same parent should not share project ID", () => + Effect.gen(function* () { + const tmp1 = yield* tmpdirScoped({ git: true }) + const tmp2 = yield* tmpdirScoped({ git: true }) - const parentDir = path.dirname(tmp1.path) - const bareA = path.join(parentDir, `bare-a-${Date.now()}.git`) - const bareB = path.join(parentDir, `bare-b-${Date.now()}.git`) - const worktreeA = path.join(parentDir, `wt-a-${Date.now()}`) - const worktreeB = path.join(parentDir, `wt-b-${Date.now()}`) + const parentDir = path.dirname(tmp1) + const bareA = path.join(parentDir, `bare-a-${Date.now()}.git`) + const bareB = path.join(parentDir, `bare-b-${Date.now()}.git`) + const worktreeA = path.join(parentDir, `wt-a-${Date.now()}`) + const worktreeB = path.join(parentDir, `wt-b-${Date.now()}`) + yield* Effect.addFinalizer(() => + Effect.promise(() => $`rm -rf ${bareA} ${bareB} ${worktreeA} ${worktreeB}`.quiet().nothrow()).pipe( + Effect.ignore, + ), + ) - try { - await $`git clone --bare ${tmp1.path} ${bareA}`.quiet() - await $`git clone --bare ${tmp2.path} ${bareB}`.quiet() - await $`git worktree add ${worktreeA} HEAD`.cwd(bareA).quiet() - await $`git worktree add ${worktreeB} HEAD`.cwd(bareB).quiet() + yield* Effect.promise(() => $`git clone --bare ${tmp1} ${bareA}`.quiet()) + yield* Effect.promise(() => $`git clone --bare ${tmp2} ${bareB}`.quiet()) + yield* Effect.promise(() => $`git worktree add ${worktreeA} HEAD`.cwd(bareA).quiet()) + yield* Effect.promise(() => $`git worktree add ${worktreeB} HEAD`.cwd(bareB).quiet()) - const { project: projA } = await run((svc) => svc.fromDirectory(worktreeA)) - const { project: projB } = await run((svc) => svc.fromDirectory(worktreeB)) + const { project: projA } = yield* run((svc) => svc.fromDirectory(worktreeA)) + const { project: projB } = yield* run((svc) => svc.fromDirectory(worktreeB)) expect(projA.id).not.toBe(projB.id) @@ -570,34 +643,33 @@ describe("Project.fromDirectory with bare repos", () => { const cacheB = path.join(bareB, "opencode") const wrongCache = path.join(parentDir, ".git", "opencode") - expect(await Bun.file(cacheA).exists()).toBe(true) - expect(await Bun.file(cacheB).exists()).toBe(true) - expect(await Bun.file(wrongCache).exists()).toBe(false) - } finally { - await $`rm -rf ${bareA} ${bareB} ${worktreeA} ${worktreeB}`.quiet().nothrow() - } - }) + expect(yield* Effect.promise(() => Bun.file(cacheA).exists())).toBe(true) + expect(yield* Effect.promise(() => Bun.file(cacheB).exists())).toBe(true) + expect(yield* Effect.promise(() => Bun.file(wrongCache).exists())).toBe(false) + }), + ) - test("bare repo without .git suffix is still detected via core.bare", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("bare repo without .git suffix is still detected via core.bare", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ git: true }) - const parentDir = path.dirname(tmp.path) - const barePath = path.join(parentDir, `bare-no-suffix-${Date.now()}`) - const worktreePath = path.join(parentDir, `worktree-${Date.now()}`) + const parentDir = path.dirname(tmp) + const barePath = path.join(parentDir, `bare-no-suffix-${Date.now()}`) + const worktreePath = path.join(parentDir, `worktree-${Date.now()}`) + yield* Effect.addFinalizer(() => + Effect.promise(() => $`rm -rf ${barePath} ${worktreePath}`.quiet().nothrow()).pipe(Effect.ignore), + ) - try { - await $`git clone --bare ${tmp.path} ${barePath}`.quiet() - await $`git worktree add ${worktreePath} HEAD`.cwd(barePath).quiet() + yield* Effect.promise(() => $`git clone --bare ${tmp} ${barePath}`.quiet()) + yield* Effect.promise(() => $`git worktree add ${worktreePath} HEAD`.cwd(barePath).quiet()) - const { project } = await run((svc) => svc.fromDirectory(worktreePath)) + const { project } = yield* run((svc) => svc.fromDirectory(worktreePath)) expect(project.id).not.toBe(ProjectID.global) expect(project.worktree).toBe(barePath) const correctCache = path.join(barePath, "opencode") - expect(await Bun.file(correctCache).exists()).toBe(true) - } finally { - await $`rm -rf ${barePath} ${worktreePath}`.quiet().nothrow() - } - }) + expect(yield* Effect.promise(() => Bun.file(correctCache).exists())).toBe(true) + }), + ) }) diff --git a/packages/opencode/test/project/worktree.test.ts b/packages/opencode/test/project/worktree.test.ts index b1b9d22b73..308e2f957b 100644 --- a/packages/opencode/test/project/worktree.test.ts +++ b/packages/opencode/test/project/worktree.test.ts @@ -1,302 +1,308 @@ -import { $ } from "bun" import { afterEach, describe, expect } from "bun:test" -import * as fs from "fs/promises" import path from "path" -import { Cause, Effect, Exit, Layer } from "effect" +import { AppFileSystem } from "@opencode-ai/core/filesystem" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect" +import { GlobalBus, type GlobalEvent } from "../../src/bus/global" +import { Git } from "../../src/git" import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { InstanceRuntime } from "../../src/project/instance-runtime" import { Worktree } from "../../src/worktree" -import { disposeAllInstances, provideInstance, provideTmpdirInstance } from "../fixture/fixture" +import { disposeAllInstances, provideInstance, TestInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" -const it = testEffect(Layer.mergeAll(Worktree.defaultLayer, CrossSpawnSpawner.defaultLayer)) -const wintest = process.platform !== "win32" ? it.live : it.live.skip +const it = testEffect( + Layer.mergeAll(Worktree.defaultLayer, AppFileSystem.defaultLayer, CrossSpawnSpawner.defaultLayer, Git.defaultLayer), +) +const wintest = process.platform !== "win32" ? it.instance : it.instance.skip function normalize(input: string) { return input.replace(/\\/g, "/").toLowerCase() } -async function waitReady() { - const { GlobalBus } = await import("../../src/bus/global") +const waitReady = Effect.fn("WorktreeTest.waitReady")(function* () { + const ready = yield* Deferred.make<{ name: string; branch?: string }>() + const on = (evt: GlobalEvent) => { + if (evt.payload.type !== Worktree.Event.Ready.type) return + Deferred.doneUnsafe(ready, Effect.succeed(evt.payload.properties)) + } - return await new Promise<{ name: string; branch?: string }>((resolve, reject) => { - const timer = setTimeout(() => { - GlobalBus.off("event", on) - reject(new Error("timed out waiting for worktree.ready")) - }, 10_000) + GlobalBus.on("event", on) + yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", on))) - function on(evt: { directory?: string; payload: { type: string; properties: { name: string; branch?: string } } }) { - if (evt.payload.type !== Worktree.Event.Ready.type) return - clearTimeout(timer) - GlobalBus.off("event", on) - resolve(evt.payload.properties) - } + return yield* Deferred.await(ready).pipe( + Effect.timeoutOrElse({ + duration: "10 seconds", + orElse: () => Effect.fail(new Error("timed out waiting for worktree.ready")), + }), + ) +}) - GlobalBus.on("event", on) +const removeCreatedWorktree = (directory: string) => + Effect.gen(function* () { + const svc = yield* Worktree.Service + const ctx = yield* Effect.sync(() => Instance.current).pipe(provideInstance(directory)) + yield* Effect.promise(() => InstanceRuntime.disposeInstance(ctx)) + const ok = yield* svc.remove({ directory }) + if (!ok) return yield* Effect.fail(new Error(`failed to remove worktree ${directory}`)) }) -} + +const withCreatedWorktree = ( + input: Parameters[0], + use: (created: { info: Worktree.Info; ready: { name: string; branch?: string } }) => Effect.Effect, +) => + Effect.acquireUseRelease( + Effect.gen(function* () { + const svc = yield* Worktree.Service + const ready = yield* waitReady().pipe(Effect.forkScoped) + const info = yield* svc.create(input) + const props = yield* Fiber.join(ready) + return { info, ready: props } + }), + use, + ({ info }) => removeCreatedWorktree(info.directory), + ) + +const git = Effect.fn("WorktreeTest.git")(function* (cwd: string, args: string[]) { + const service = yield* Git.Service + const result = yield* service.run(args, { cwd }) + if (result.exitCode !== 0) throw new Error(`git ${args.join(" ")} failed: ${result.stderr.toString("utf8")}`) + return result.text() +}) + +const gitResult = Effect.fn("WorktreeTest.gitResult")(function* (cwd: string, args: string[]) { + const service = yield* Git.Service + return yield* service.run(args, { cwd }) +}) describe("Worktree", () => { afterEach(() => disposeAllInstances()) describe("makeWorktreeInfo", () => { - it.live("returns info with name, branch, and directory", () => - provideTmpdirInstance( - () => - Effect.gen(function* () { - const svc = yield* Worktree.Service - const info = yield* svc.makeWorktreeInfo() - - expect(info.name).toBeDefined() - expect(typeof info.name).toBe("string") - expect(info.branch).toBe(`opencode/${info.name}`) - expect(info.directory).toContain(info.name) - }), - { git: true }, - ), - ) - - it.live("uses provided name as base", () => - provideTmpdirInstance( - () => - Effect.gen(function* () { - const svc = yield* Worktree.Service - const info = yield* svc.makeWorktreeInfo({ name: "my-feature" }) - - expect(info.name).toBe("my-feature") - expect(info.branch).toBe("opencode/my-feature") - }), - { git: true }, - ), - ) - - it.live("slugifies the provided name", () => - provideTmpdirInstance( - () => - Effect.gen(function* () { - const svc = yield* Worktree.Service - const info = yield* svc.makeWorktreeInfo({ name: "My Feature Branch!" }) - - expect(info.name).toBe("my-feature-branch") - }), - { git: true }, - ), - ) - - it.live("omits branch for detached info", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const svc = yield* Worktree.Service - yield* Effect.promise(() => $`git branch opencode/my-feature`.cwd(dir).quiet()) - - const info = yield* svc.makeWorktreeInfo({ name: "my-feature", detached: true }) - - expect(info.name).toBe("my-feature") - expect(info.branch).toBeUndefined() - }), - { git: true }, - ), - ) - - it.live("throws NotGitError for non-git directories", () => - provideTmpdirInstance(() => + it.instance( + "returns info with name, branch, and directory", + () => Effect.gen(function* () { const svc = yield* Worktree.Service - const exit = yield* Effect.exit(svc.makeWorktreeInfo()) + const info = yield* svc.makeWorktreeInfo() - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Worktree.NotGitError) + expect(info.name).toBeDefined() + expect(typeof info.name).toBe("string") + expect(info.branch).toBe(`opencode/${info.name}`) + expect(info.directory).toContain(info.name) }), - ), + { git: true }, ) - wintest("creates detached git worktree when info has no branch", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const svc = yield* Worktree.Service - const info = yield* svc.makeWorktreeInfo({ name: "detached-test", detached: true }) - const ready = waitReady() - yield* svc.createFromInfo(info) + it.instance( + "uses provided name as base", + () => + Effect.gen(function* () { + const svc = yield* Worktree.Service + const info = yield* svc.makeWorktreeInfo({ name: "my-feature" }) - const list = yield* Effect.promise(() => $`git worktree list --porcelain`.cwd(dir).quiet().text()) - const normalizedList = normalize(list) - const normalizedDir = normalize(info.directory) - expect(normalizedList).toContain(normalizedDir) + expect(info.name).toBe("my-feature") + expect(info.branch).toBe("opencode/my-feature") + }), + { git: true }, + ) - const branch = yield* Effect.promise(() => - $`git symbolic-ref -q --short HEAD`.cwd(info.directory).quiet().nothrow(), - ) - expect(branch.exitCode).not.toBe(0) + it.instance( + "slugifies the provided name", + () => + Effect.gen(function* () { + const svc = yield* Worktree.Service + const info = yield* svc.makeWorktreeInfo({ name: "My Feature Branch!" }) - const props = yield* Effect.promise(() => ready) - expect(props.name).toBe(info.name) - expect(props.branch).toBeUndefined() + expect(info.name).toBe("my-feature-branch") + }), + { git: true }, + ) - yield* svc.remove({ directory: info.directory }) - }), - { git: true }, - ), + it.instance( + "omits branch for detached info", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const svc = yield* Worktree.Service + yield* git(test.directory, ["branch", "opencode/my-feature"]) + + const info = yield* svc.makeWorktreeInfo({ name: "my-feature", detached: true }) + + expect(info.name).toBe("my-feature") + expect(info.branch).toBeUndefined() + }), + { git: true }, + ) + + it.instance("fails with NotGitError for non-git directories", () => + Effect.gen(function* () { + const svc = yield* Worktree.Service + const exit = yield* Effect.exit(svc.makeWorktreeInfo()) + + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const error = Cause.squash(exit.cause) + expect(error).toBeInstanceOf(Worktree.NotGitError) + if (error instanceof Worktree.NotGitError) expect(error._tag).toBe("WorktreeNotGitError") + } + }), + ) + + wintest( + "creates detached git worktree when info has no branch", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const svc = yield* Worktree.Service + const info = yield* svc.makeWorktreeInfo({ name: "detached-test", detached: true }) + const ready = yield* waitReady().pipe(Effect.forkScoped) + yield* svc.createFromInfo(info) + + const list = yield* git(test.directory, ["worktree", "list", "--porcelain"]) + const normalizedList = normalize(list) + const normalizedDir = normalize(info.directory) + expect(normalizedList).toContain(normalizedDir) + + const branch = yield* gitResult(info.directory, ["symbolic-ref", "-q", "--short", "HEAD"]) + expect(branch.exitCode).not.toBe(0) + + const props = yield* Fiber.join(ready) + expect(props.name).toBe(info.name) + expect(props.branch).toBeUndefined() + + yield* svc.remove({ directory: info.directory }) + }), + { git: true }, ) }) describe("create + remove lifecycle", () => { - it.live("create returns worktree info and remove cleans up", () => - provideTmpdirInstance( - () => + it.instance( + "create returns worktree info and remove cleans up", + () => + withCreatedWorktree(undefined, ({ info }) => Effect.gen(function* () { - const svc = yield* Worktree.Service - const info = yield* svc.create() - expect(info.name).toBeDefined() expect(info.branch ?? "").toStartWith("opencode/") expect(info.directory).toBeDefined() - - yield* Effect.promise(() => Bun.sleep(1000)) - - const ok = yield* svc.remove({ directory: info.directory }) - expect(ok).toBe(true) }), - { git: true }, - ), + ), + { git: true }, ) - it.live("create returns after setup and fires Event.Ready after bootstrap", () => - provideTmpdirInstance( - (dir) => + it.instance( + "create returns after setup and fires Event.Ready after bootstrap", + () => + withCreatedWorktree(undefined, ({ info, ready }) => Effect.gen(function* () { const svc = yield* Worktree.Service - const ready = waitReady() - const info = yield* svc.create() expect(info.name).toBeDefined() expect(info.branch ?? "").toStartWith("opencode/") - const text = yield* Effect.promise(() => $`git worktree list --porcelain`.cwd(dir).quiet().text()) - const next = yield* Effect.promise(() => fs.realpath(info.directory).catch(() => info.directory)) - expect(normalize(text)).toContain(normalize(next)) + expect(ready.name).toBe(info.name) + expect(ready.branch).toBe(info.branch) - const props = yield* Effect.promise(() => ready) - expect(props.name).toBe(info.name) - expect(props.branch).toBe(info.branch) - - yield* Effect.promise(() => - WithInstance.provide({ - directory: info.directory, - fn: () => InstanceRuntime.disposeInstance(Instance.current), - }), - ) - yield* Effect.promise(() => Bun.sleep(100)) - yield* svc.remove({ directory: info.directory }) + const list = yield* svc.list() + expect(list).toContainEqual(expect.objectContaining({ name: info.name, branch: info.branch })) }), - { git: true }, - ), + ), + { git: true }, ) - it.live("create with custom name", () => - provideTmpdirInstance( - () => + it.instance( + "create with custom name", + () => + withCreatedWorktree({ name: "test-workspace" }, ({ info }) => Effect.gen(function* () { - const svc = yield* Worktree.Service - const ready = waitReady() - const info = yield* svc.create({ name: "test-workspace" }) - expect(info.name).toBe("test-workspace") expect(info.branch).toBe("opencode/test-workspace") - - yield* Effect.promise(() => ready) - yield* Effect.promise(() => - WithInstance.provide({ - directory: info.directory, - fn: () => InstanceRuntime.disposeInstance(Instance.current), - }), - ) - yield* Effect.promise(() => Bun.sleep(100)) - yield* svc.remove({ directory: info.directory }) }), - { git: true }, - ), + ), + { git: true }, ) }) describe("createFromInfo", () => { - wintest("creates git worktree and boots asynchronously", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const svc = yield* Worktree.Service - const info = yield* svc.makeWorktreeInfo({ name: "from-info-test" }) - const ready = waitReady() - yield* svc.createFromInfo(info) + wintest( + "creates git worktree and boots asynchronously", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const svc = yield* Worktree.Service + const info = yield* svc.makeWorktreeInfo({ name: "from-info-test" }) + const ready = yield* waitReady().pipe(Effect.forkScoped) + yield* svc.createFromInfo(info) - const list = yield* Effect.promise(() => $`git worktree list --porcelain`.cwd(dir).quiet().text()) - const normalizedList = list.replace(/\\/g, "/") - const normalizedDir = info.directory.replace(/\\/g, "/") - expect(normalizedList).toContain(normalizedDir) + const list = yield* git(test.directory, ["worktree", "list", "--porcelain"]) + const normalizedList = list.replace(/\\/g, "/") + const normalizedDir = info.directory.replace(/\\/g, "/") + expect(normalizedList).toContain(normalizedDir) - yield* Effect.promise(() => ready) - yield* svc.remove({ directory: info.directory }) - }), - { git: true }, - ), + yield* Fiber.join(ready) + yield* removeCreatedWorktree(info.directory) + }), + { git: true }, ) }) describe("list", () => { - it.live("uses parent folder name when worktree basename matches the primary worktree", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const svc = yield* Worktree.Service - const parent = path.join(path.dirname(dir), `${path.basename(dir)}-parent`) - const target = path.join(parent, path.basename(dir)) - const branch = `same-basename-list-${Date.now()}` + it.instance( + "uses parent folder name when worktree basename matches the primary worktree", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const fs = yield* AppFileSystem.Service + const svc = yield* Worktree.Service + const parent = path.join(path.dirname(test.directory), `${path.basename(test.directory)}-parent`) + const target = path.join(parent, path.basename(test.directory)) + const branch = `same-basename-list-${Date.now()}` - yield* Effect.promise(() => fs.mkdir(parent, { recursive: true })) - yield* Effect.promise(() => $`git worktree add -b ${branch} ${target}`.cwd(dir).quiet()) + yield* fs.ensureDir(parent) + yield* git(test.directory, ["worktree", "add", "-b", branch, target]) - const list = yield* svc.list() - const directory = yield* Effect.promise(() => fs.realpath(target).catch(() => target)) + const list = yield* svc.list() + const directory = yield* fs.realPath(target).pipe(Effect.catch(() => Effect.succeed(target))) - expect(list.map((item) => ({ ...item, directory: normalize(item.directory) }))).toContainEqual({ - name: path.basename(parent), - branch, - directory: normalize(directory), - }) + expect(list.map((item) => ({ ...item, directory: normalize(item.directory) }))).toContainEqual({ + name: path.basename(parent), + branch, + directory: normalize(directory), + }) - yield* svc.remove({ directory: target }) - }), - { git: true }, - ), + yield* svc.remove({ directory: target }) + }), + { git: true }, ) }) describe("remove edge cases", () => { - it.live("remove non-existent directory succeeds silently", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const svc = yield* Worktree.Service - const ok = yield* svc.remove({ directory: path.join(dir, "does-not-exist") }) - expect(ok).toBe(true) - }), - { git: true }, - ), + it.instance( + "remove non-existent directory succeeds silently", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const svc = yield* Worktree.Service + const ok = yield* svc.remove({ directory: path.join(test.directory, "does-not-exist") }) + expect(ok).toBe(true) + }), + { git: true }, ) - it.live("throws NotGitError for non-git directories", () => - provideTmpdirInstance(() => - Effect.gen(function* () { - const svc = yield* Worktree.Service - const exit = yield* Effect.exit(svc.remove({ directory: "/tmp/fake" })) + it.instance("fails with NotGitError for non-git directories", () => + Effect.gen(function* () { + const test = yield* TestInstance + const svc = yield* Worktree.Service + const exit = yield* Effect.exit(svc.remove({ directory: path.join(test.directory, "fake") })) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Worktree.NotGitError) - }), - ), + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const error = Cause.squash(exit.cause) + expect(error).toBeInstanceOf(Worktree.NotGitError) + if (error instanceof Worktree.NotGitError) expect(error._tag).toBe("WorktreeNotGitError") + } + }), ) }) }) diff --git a/packages/opencode/test/provider/digitalocean.test.ts b/packages/opencode/test/provider/digitalocean.test.ts new file mode 100644 index 0000000000..665c792deb --- /dev/null +++ b/packages/opencode/test/provider/digitalocean.test.ts @@ -0,0 +1,122 @@ +import { expect } from "bun:test" +import { Provider } from "../../src/provider/provider" +import { ProviderID } from "../../src/provider/schema" +import { Effect } from "effect" +import { testEffect } from "../lib/effect" + +const DIGITALOCEAN = ProviderID.make("digitalocean") +const it = testEffect(Provider.defaultLayer) + +const withEnv = (values: Record, effect: Effect.Effect) => + Effect.acquireUseRelease( + Effect.sync(() => { + const previous = Object.fromEntries(Object.keys(values).map((key) => [key, process.env[key]] as const)) + Object.assign(process.env, values) + return previous + }), + () => effect, + (previous) => + Effect.sync(() => { + for (const [key, value] of Object.entries(previous)) { + if (value === undefined) delete process.env[key] + else process.env[key] = value + } + }), + ) + +const withAuth = (metadata: Record | undefined, effect: Effect.Effect) => + withEnv( + { + OPENCODE_AUTH_CONTENT: JSON.stringify({ + digitalocean: { + type: "api", + key: "sk_do_test", + ...(metadata ? { metadata } : {}), + }, + }), + }, + effect, + ) + +it.instance( + "digitalocean provider autoloads from DIGITALOCEAN_ACCESS_TOKEN", + () => + withEnv( + { DIGITALOCEAN_ACCESS_TOKEN: "test-token" }, + Effect.gen(function* () { + const provider = yield* Provider.Service + const providers = yield* provider.list() + expect(providers[DIGITALOCEAN]).toBeDefined() + expect(providers[DIGITALOCEAN].source).toBe("env") + const baseModel = Object.values(providers[DIGITALOCEAN].models)[0] + expect(baseModel.api.url).toBe("https://inference.do-ai.run/v1") + expect(baseModel.api.npm).toBe("@ai-sdk/openai-compatible") + const routerEntries = Object.keys(providers[DIGITALOCEAN].models).filter((id) => id.startsWith("router:")) + expect(routerEntries.length).toBe(0) + }), + ), + { config: {} }, +) + +it.instance( + "digitalocean provider.models surfaces cached routers from auth metadata", + () => + withAuth( + { + routers: JSON.stringify([ + { name: "my-router", uuid: "11f1499a-aaaa-bbbb-cccc-4e013e2ddde4" }, + { name: "other-router", uuid: "22f1499a-aaaa-bbbb-cccc-4e013e2ddde4" }, + ]), + routers_fetched_at: String(Date.now()), + oauth_access: "doo_v1_test", + oauth_expires: String(Date.now() + 60 * 60 * 1000), + }, + Effect.gen(function* () { + const provider = yield* Provider.Service + const providers = yield* provider.list() + const models = providers[DIGITALOCEAN].models + expect(models["router:my-router"]).toBeDefined() + expect(models["router:my-router"].api.id).toBe("router:my-router") + expect(models["router:my-router"].api.url).toBe("https://inference.do-ai.run/v1") + expect(models["router:my-router"].api.npm).toBe("@ai-sdk/openai-compatible") + expect(models["router:other-router"]).toBeDefined() + }), + ), + { config: {} }, +) + +it.instance( + "digitalocean provider.models skips refresh when oauth bearer is expired", + () => + withAuth( + { + routers: JSON.stringify([{ name: "stale-router", uuid: "stale" }]), + routers_fetched_at: "0", + oauth_access: "doo_v1_expired", + oauth_expires: "1", + }, + Effect.gen(function* () { + const provider = yield* Provider.Service + const providers = yield* provider.list() + const models = providers[DIGITALOCEAN].models + expect(models["router:stale-router"]).toBeDefined() + }), + ), + { config: {} }, +) + +it.instance( + "digitalocean provider.models passes through base models when no auth metadata", + () => + withEnv( + { DIGITALOCEAN_ACCESS_TOKEN: "test-token" }, + Effect.gen(function* () { + const provider = yield* Provider.Service + const providers = yield* provider.list() + const models = providers[DIGITALOCEAN].models + expect(Object.keys(models).length).toBeGreaterThan(0) + expect(Object.keys(models).filter((id) => id.startsWith("router:")).length).toBe(0) + }), + ), + { config: {} }, +) diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts index ea65c90c4f..2270418beb 100644 --- a/packages/opencode/test/provider/provider.test.ts +++ b/packages/opencode/test/provider/provider.test.ts @@ -582,64 +582,52 @@ it.instance( }, ) -test("model options are merged from existing model", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - provider: { - anthropic: { - models: { - "claude-sonnet-4-20250514": { - options: { - customOption: "custom-value", - }, - }, +it.instance( + "model options are merged from existing model", + Effect.gen(function* () { + const providers = yield* Provider.Service.use((provider) => provider.list()) + const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"] + expect(model.options.customOption).toBe("custom-value") + }), + { + config: { + provider: { + anthropic: { + options: { + apiKey: "test-api-key", + }, + models: { + "claude-sonnet-4-20250514": { + options: { + customOption: "custom-value", }, }, }, - }), - ) + }, + }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - set("ANTHROPIC_API_KEY", "test-api-key") - const providers = await list() - const model = providers[ProviderID.anthropic].models["claude-sonnet-4-20250514"] - expect(model.options.customOption).toBe("custom-value") - }, - }) -}) + }, +) -test("provider removed when all models filtered out", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - provider: { - anthropic: { - whitelist: ["nonexistent-model"], - }, +it.instance( + "provider removed when all models filtered out", + Effect.gen(function* () { + const providers = yield* Provider.Service.use((provider) => provider.list()) + expect(providers[ProviderID.anthropic]).toBeUndefined() + }), + { + config: { + provider: { + anthropic: { + options: { + apiKey: "test-api-key", }, - }), - ) + whitelist: ["nonexistent-model"], + }, + }, }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - set("ANTHROPIC_API_KEY", "test-api-key") - const providers = await list() - expect(providers[ProviderID.anthropic]).toBeUndefined() - }, - }) -}) + }, +) test("closest finds model by partial match", async () => { await using tmp = await tmpdir({ diff --git a/packages/opencode/test/pty/pty-output-isolation.test.ts b/packages/opencode/test/pty/pty-output-isolation.test.ts index 662042b64c..0fa710f02a 100644 --- a/packages/opencode/test/pty/pty-output-isolation.test.ts +++ b/packages/opencode/test/pty/pty-output-isolation.test.ts @@ -1,147 +1,162 @@ -import { describe, expect, test } from "bun:test" -import { AppRuntime } from "../../src/effect/app-runtime" -import { Effect } from "effect" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" +import { describe, expect } from "bun:test" +import { Bus } from "../../src/bus" +import { Config } from "../../src/config/config" +import { Plugin } from "../../src/plugin" import { Pty } from "../../src/pty" -import { tmpdir } from "../fixture/fixture" -import { setTimeout as sleep } from "node:timers/promises" +import { Duration, Effect, Layer, Queue } from "effect" +import { testEffect } from "../lib/effect" + +type Socket = Parameters[1] + +const it = testEffect( + Pty.layer.pipe( + Layer.provideMerge(Bus.layer), + Layer.provideMerge(Config.defaultLayer), + Layer.provideMerge(Plugin.defaultLayer), + ), +) +const ptyTest = process.platform === "win32" ? it.instance.skip : it.instance + +const createPty = Effect.fn("PtyOutputIsolationTest.createPty")(function* (input: Pty.CreateInput) { + const pty = yield* Pty.Service + return yield* Effect.acquireRelease(pty.create(input), (info) => pty.remove(info.id).pipe(Effect.ignore)) +}) + +const decodeOutput = (data: string | Uint8Array | ArrayBuffer) => + typeof data === "string" + ? data + : Buffer.from(data instanceof Uint8Array ? data : new Uint8Array(data)).toString("utf8") + +const makeSocket = Effect.fn("PtyOutputIsolationTest.makeSocket")(function* (data: unknown) { + const output = yield* Queue.unbounded() + const chunks: string[] = [] + const socket: Socket = { + readyState: 1, + data, + send: (data) => { + const text = decodeOutput(data) + chunks.push(text) + Queue.offerUnsafe(output, text) + }, + close: () => { + // no-op (simulate abrupt drop) + }, + } + + return { socket, output, chunks } +}) + +const waitForOutput = (output: Queue.Queue, text: string, duration: Duration.Input = "5 seconds") => + Effect.gen(function* () { + let received = "" + while (!received.includes(text)) { + received += yield* Queue.take(output) + } + return received + }).pipe( + Effect.timeoutOrElse({ + duration, + orElse: () => Effect.fail(new Error(`timeout waiting for output containing ${JSON.stringify(text)}`)), + }), + ) + +const waitForLeakedOutput = (output: Queue.Queue, text: string) => + Effect.gen(function* () { + let received = "" + while (!received.includes(text)) { + received += yield* Queue.take(output) + } + return received + }).pipe( + Effect.timeoutOrElse({ + duration: "100 millis", + orElse: () => Effect.succeed(undefined), + }), + ) describe("pty", () => { - test("does not leak output when websocket objects are reused", async () => { - await using dir = await tmpdir({ git: true }) + ptyTest( + "does not leak output when websocket objects are reused", + () => + Effect.gen(function* () { + const pty = yield* Pty.Service + const a = yield* createPty({ command: "cat", title: "a" }) + const b = yield* createPty({ command: "cat", title: "b" }) + const connectionA = yield* makeSocket({ events: { connection: "a" } }) + const connectionB = { events: { connection: "b" } } - await WithInstance.provide({ - directory: dir.path, - fn: () => - AppRuntime.runPromise( - Effect.gen(function* () { - const pty = yield* Pty.Service - const a = yield* pty.create({ command: "cat", title: "a" }) - const b = yield* pty.create({ command: "cat", title: "b" }) - try { - const outA: string[] = [] - const outB: string[] = [] + yield* pty.connect(a.id, connectionA.socket) - const ws = { - readyState: 1, - data: { events: { connection: "a" } }, - send: (data: unknown) => { - outA.push(typeof data === "string" ? data : Buffer.from(data as Uint8Array).toString("utf8")) - }, - close: () => { - // no-op (simulate abrupt drop) - }, - } + const outBQueue = yield* Queue.unbounded() + const outB: string[] = [] + connectionA.socket.data = connectionB + connectionA.socket.send = (data) => { + const text = decodeOutput(data) + outB.push(text) + Queue.offerUnsafe(outBQueue, text) + } + yield* pty.connect(b.id, connectionA.socket) - yield* pty.connect(a.id, ws as any) + connectionA.chunks.length = 0 + outB.length = 0 - ws.data = { events: { connection: "b" } } - ws.send = (data: unknown) => { - outB.push(typeof data === "string" ? data : Buffer.from(data as Uint8Array).toString("utf8")) - } - yield* pty.connect(b.id, ws as any) + yield* pty.write(a.id, "AAA\n") + const verifyA = yield* makeSocket({ events: { connection: "verify-a" } }) + yield* pty.connect(a.id, verifyA.socket) + yield* waitForOutput(verifyA.output, "AAA") - outA.length = 0 - outB.length = 0 + expect(outB.join("")).not.toContain("AAA") + expect(yield* waitForLeakedOutput(outBQueue, "AAA")).toBeUndefined() + }), + { git: true }, + ) - yield* pty.write(a.id, "AAA\n") - yield* Effect.promise(() => sleep(100)) + ptyTest( + "does not leak output when Bun recycles websocket objects before re-connect", + () => + Effect.gen(function* () { + const pty = yield* Pty.Service + const a = yield* createPty({ command: "cat", title: "a" }) + const outA = yield* makeSocket({ events: { connection: "a" } }) + const outB = yield* Queue.unbounded() - expect(outB.join("")).not.toContain("AAA") - } finally { - yield* pty.remove(a.id) - yield* pty.remove(b.id) - } - }), - ), - }) - }) + yield* pty.connect(a.id, outA.socket) + outA.chunks.length = 0 - test("does not leak output when Bun recycles websocket objects before re-connect", async () => { - await using dir = await tmpdir({ git: true }) + const connectionB = { events: { connection: "b" } } + outA.socket.data = connectionB + outA.socket.send = (data) => { + Queue.offerUnsafe(outB, decodeOutput(data)) + } - await WithInstance.provide({ - directory: dir.path, - fn: () => - AppRuntime.runPromise( - Effect.gen(function* () { - const pty = yield* Pty.Service - const a = yield* pty.create({ command: "cat", title: "a" }) - try { - const outA: string[] = [] - const outB: string[] = [] + yield* pty.write(a.id, "AAA\n") + const verifyA = yield* makeSocket({ events: { connection: "verify-a" } }) + yield* pty.connect(a.id, verifyA.socket) + yield* waitForOutput(verifyA.output, "AAA") - const ws = { - readyState: 1, - data: { events: { connection: "a" } }, - send: (data: unknown) => { - outA.push(typeof data === "string" ? data : Buffer.from(data as Uint8Array).toString("utf8")) - }, - close: () => { - // no-op (simulate abrupt drop) - }, - } + expect(yield* waitForLeakedOutput(outB, "AAA")).toBeUndefined() + }), + { git: true }, + ) - yield* pty.connect(a.id, ws as any) - outA.length = 0 + ptyTest( + "treats in-place socket data mutation as the same connection", + () => + Effect.gen(function* () { + const pty = yield* Pty.Service + const a = yield* createPty({ command: "cat", title: "a" }) + const ctx = { connId: 1 } + const out = yield* makeSocket(ctx) - ws.data = { events: { connection: "b" } } - ws.send = (data: unknown) => { - outB.push(typeof data === "string" ? data : Buffer.from(data as Uint8Array).toString("utf8")) - } + yield* pty.connect(a.id, out.socket) + out.chunks.length = 0 - yield* pty.write(a.id, "AAA\n") - yield* Effect.promise(() => sleep(100)) + ctx.connId = 2 - expect(outB.join("")).not.toContain("AAA") - } finally { - yield* pty.remove(a.id) - } - }), - ), - }) - }) + yield* pty.write(a.id, "AAA\n") - test("treats in-place socket data mutation as the same connection", async () => { - await using dir = await tmpdir({ git: true }) - - await WithInstance.provide({ - directory: dir.path, - fn: () => - AppRuntime.runPromise( - Effect.gen(function* () { - const pty = yield* Pty.Service - const a = yield* pty.create({ command: "cat", title: "a" }) - try { - const out: string[] = [] - - const ctx = { connId: 1 } - const ws = { - readyState: 1, - data: ctx, - send: (data: unknown) => { - out.push(typeof data === "string" ? data : Buffer.from(data as Uint8Array).toString("utf8")) - }, - close: () => { - // no-op - }, - } - - yield* pty.connect(a.id, ws as any) - out.length = 0 - - ctx.connId = 2 - - yield* pty.write(a.id, "AAA\n") - yield* Effect.promise(() => sleep(100)) - - expect(out.join("")).toContain("AAA") - } finally { - yield* pty.remove(a.id) - } - }), - ), - }) - }) + expect(yield* waitForOutput(out.output, "AAA")).toContain("AAA") + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/pty/pty-session.test.ts b/packages/opencode/test/pty/pty-session.test.ts index 8c5d804b73..12784baf31 100644 --- a/packages/opencode/test/pty/pty-session.test.ts +++ b/packages/opencode/test/pty/pty-session.test.ts @@ -1,103 +1,100 @@ -import { describe, expect, test } from "bun:test" -import { AppRuntime } from "../../src/effect/app-runtime" +import { describe, expect } from "bun:test" import { Bus } from "../../src/bus" -import { Effect } from "effect" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" +import { Config } from "../../src/config/config" +import { Plugin } from "../../src/plugin" import { Pty } from "../../src/pty" import type { PtyID } from "../../src/pty/schema" -import { tmpdir } from "../fixture/fixture" -import { setTimeout as sleep } from "node:timers/promises" +import { Effect, Layer, Queue } from "effect" +import { testEffect } from "../lib/effect" -const wait = async (fn: () => boolean, ms = 5000) => { - const end = Date.now() + ms - while (Date.now() < end) { - if (fn()) return - await sleep(25) - } - throw new Error("timeout waiting for pty events") -} +type PtyEvent = { type: "created" | "exited" | "deleted"; id: PtyID } -const pick = (log: Array<{ type: "created" | "exited" | "deleted"; id: PtyID }>, id: PtyID) => { - return log.filter((evt) => evt.id === id).map((evt) => evt.type) +const it = testEffect( + Pty.layer.pipe( + Layer.provideMerge(Bus.layer), + Layer.provideMerge(Config.defaultLayer), + Layer.provideMerge(Plugin.defaultLayer), + ), +) +const ptyTest = process.platform === "win32" ? it.instance.skip : it.instance + +const subscribePtyEvents = Effect.fn("PtySessionTest.subscribePtyEvents")(function* () { + const bus = yield* Bus.Service + const events = yield* Queue.unbounded() + + const subscribe = (effect: Effect.Effect<() => void, never, A>) => + Effect.acquireRelease(effect, (off) => Effect.sync(off)) + + yield* subscribe( + bus.subscribeCallback(Pty.Event.Created, (evt) => { + Queue.offerUnsafe(events, { type: "created", id: evt.properties.info.id }) + }), + ) + yield* subscribe( + bus.subscribeCallback(Pty.Event.Exited, (evt) => { + Queue.offerUnsafe(events, { type: "exited", id: evt.properties.id }) + }), + ) + yield* subscribe( + bus.subscribeCallback(Pty.Event.Deleted, (evt) => { + Queue.offerUnsafe(events, { type: "deleted", id: evt.properties.id }) + }), + ) + + return events +}) + +const createPty = Effect.fn("PtySessionTest.createPty")(function* (input: Pty.CreateInput) { + const pty = yield* Pty.Service + return yield* Effect.acquireRelease(pty.create(input), (info) => pty.remove(info.id).pipe(Effect.ignore)) +}) + +const waitForEvents = (events: Queue.Queue, id: PtyID, count: number) => { + return Effect.gen(function* () { + const picked: Array = [] + while (picked.length < count) { + const evt = yield* Queue.take(events) + if (evt.id === id) picked.push(evt.type) + } + return picked + }).pipe( + Effect.timeoutOrElse({ + duration: "5 seconds", + orElse: () => Effect.fail(new Error("timeout waiting for pty events")), + }), + ) } describe("pty", () => { - test("publishes created, exited, deleted in order for a short-lived process", async () => { - if (process.platform === "win32") return + ptyTest( + "publishes created, exited, deleted in order for a short-lived process", + () => + Effect.gen(function* () { + const events = yield* subscribePtyEvents() + const info = yield* createPty({ + command: "/usr/bin/env", + args: ["sh", "-c", "sleep 0.1"], + title: "sleep", + }) - await using dir = await tmpdir({ git: true }) + expect(yield* waitForEvents(events, info.id, 3)).toEqual(["created", "exited", "deleted"]) + }), + { git: true }, + ) - await WithInstance.provide({ - directory: dir.path, - fn: () => - AppRuntime.runPromise( - Effect.gen(function* () { - const pty = yield* Pty.Service - const log: Array<{ type: "created" | "exited" | "deleted"; id: PtyID }> = [] - const off = [ - Bus.subscribe(Pty.Event.Created, (evt) => log.push({ type: "created", id: evt.properties.info.id })), - Bus.subscribe(Pty.Event.Exited, (evt) => log.push({ type: "exited", id: evt.properties.id })), - Bus.subscribe(Pty.Event.Deleted, (evt) => log.push({ type: "deleted", id: evt.properties.id })), - ] + ptyTest( + "publishes created, exited, deleted in order for /bin/sh + remove", + () => + Effect.gen(function* () { + const pty = yield* Pty.Service + const events = yield* subscribePtyEvents() + const info = yield* createPty({ command: "/bin/sh", title: "sh" }) - let id: PtyID | undefined - try { - const info = yield* pty.create({ - command: "/usr/bin/env", - args: ["sh", "-c", "sleep 0.1"], - title: "sleep", - }) - id = info.id - - yield* Effect.promise(() => wait(() => pick(log, id!).includes("exited"))) - - yield* pty.remove(id) - yield* Effect.promise(() => wait(() => pick(log, id!).length >= 3)) - expect(pick(log, id!)).toEqual(["created", "exited", "deleted"]) - } finally { - off.forEach((x) => x()) - if (id) yield* pty.remove(id) - } - }), - ), - }) - }) - - test("publishes created, exited, deleted in order for /bin/sh + remove", async () => { - if (process.platform === "win32") return - - await using dir = await tmpdir({ git: true }) - - await WithInstance.provide({ - directory: dir.path, - fn: () => - AppRuntime.runPromise( - Effect.gen(function* () { - const pty = yield* Pty.Service - const log: Array<{ type: "created" | "exited" | "deleted"; id: PtyID }> = [] - const off = [ - Bus.subscribe(Pty.Event.Created, (evt) => log.push({ type: "created", id: evt.properties.info.id })), - Bus.subscribe(Pty.Event.Exited, (evt) => log.push({ type: "exited", id: evt.properties.id })), - Bus.subscribe(Pty.Event.Deleted, (evt) => log.push({ type: "deleted", id: evt.properties.id })), - ] - - let id: PtyID | undefined - try { - const info = yield* pty.create({ command: "/bin/sh", title: "sh" }) - id = info.id - - yield* Effect.promise(() => sleep(100)) - - yield* pty.remove(id) - yield* Effect.promise(() => wait(() => pick(log, id!).length >= 3)) - expect(pick(log, id!)).toEqual(["created", "exited", "deleted"]) - } finally { - off.forEach((x) => x()) - if (id) yield* pty.remove(id) - } - }), - ), - }) - }) + expect(yield* waitForEvents(events, info.id, 1)).toEqual(["created"]) + yield* pty.write(info.id, "exit\n") + expect(yield* waitForEvents(events, info.id, 2)).toEqual(["exited", "deleted"]) + yield* pty.remove(info.id) + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/pty/pty-shell.test.ts b/packages/opencode/test/pty/pty-shell.test.ts index 00e965d25e..e8132dec76 100644 --- a/packages/opencode/test/pty/pty-shell.test.ts +++ b/packages/opencode/test/pty/pty-shell.test.ts @@ -1,39 +1,35 @@ -import { describe, expect, test } from "bun:test" -import { AppRuntime } from "../../src/effect/app-runtime" +import { describe, expect } from "bun:test" import { Effect } from "effect" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { Pty } from "../../src/pty" import { Shell } from "../../src/shell/shell" -import { tmpdir } from "../fixture/fixture" +import { testEffect } from "../lib/effect" Shell.preferred.reset() +const it = testEffect(Pty.defaultLayer) + +const createPty = (input: Pty.CreateInput) => + Effect.acquireRelease( + Effect.gen(function* () { + const pty = yield* Pty.Service + const info = yield* pty.create(input) + return { pty, info } + }), + ({ pty, info }) => pty.remove(info.id).pipe(Effect.ignore), + ).pipe(Effect.map(({ info }) => info)) + describe("pty shell args", () => { if (process.platform !== "win32") return const ps = Bun.which("pwsh") || Bun.which("powershell") if (ps) { - test( + it.instance( "does not add login args to pwsh", - async () => { - await using dir = await tmpdir() - await WithInstance.provide({ - directory: dir.path, - fn: () => - AppRuntime.runPromise( - Effect.gen(function* () { - const pty = yield* Pty.Service - const info = yield* pty.create({ command: ps, title: "pwsh" }) - try { - expect(info.args).toEqual([]) - } finally { - yield* pty.remove(info.id) - } - }), - ), - }) - }, + () => + Effect.gen(function* () { + const info = yield* createPty({ command: ps, title: "pwsh" }) + expect(info.args).toEqual([]) + }), { timeout: 30000 }, ) } @@ -44,62 +40,36 @@ describe("pty shell args", () => { return Shell.gitbash() })() if (bash) { - test( + it.instance( "adds login args to bash", - async () => { - await using dir = await tmpdir() - await WithInstance.provide({ - directory: dir.path, - fn: () => - AppRuntime.runPromise( - Effect.gen(function* () { - const pty = yield* Pty.Service - const info = yield* pty.create({ command: bash, title: "bash" }) - try { - expect(info.args).toEqual(["-l"]) - } finally { - yield* pty.remove(info.id) - } - }), - ), - }) - }, + () => + Effect.gen(function* () { + const info = yield* createPty({ command: bash, title: "bash" }) + expect(info.args).toEqual(["-l"]) + }), { timeout: 30000 }, ) } }) describe("pty configured shell", () => { - test( - "uses configured shell for default PTY command", - async () => { - const configured = process.platform === "win32" ? Bun.which("pwsh") || Bun.which("powershell") : Bun.which("bash") - if (!configured) return + const configured = process.platform === "win32" ? Bun.which("pwsh") || Bun.which("powershell") : Bun.which("bash") - await using dir = await tmpdir({ - config: { shell: Shell.name(configured) }, - }) - await WithInstance.provide({ - directory: dir.path, - fn: () => - AppRuntime.runPromise( - Effect.gen(function* () { - const pty = yield* Pty.Service - const info = yield* pty.create({ title: "configured" }) - try { - if (process.platform === "win32") { - expect(info.command.toLowerCase()).toBe(configured.toLowerCase()) - } else { - expect(info.command).toBe(configured) - } - expect(info.args).toEqual(process.platform === "win32" ? [] : ["-l"]) - } finally { - yield* pty.remove(info.id) - } - }), - ), - }) - }, + it.instance( + "uses configured shell for default PTY command", + () => + Effect.gen(function* () { + if (!configured) return + + const info = yield* createPty({ title: "configured" }) + if (process.platform === "win32") { + expect(info.command.toLowerCase()).toBe(configured.toLowerCase()) + } else { + expect(info.command).toBe(configured) + } + expect(info.args).toEqual(process.platform === "win32" ? [] : ["-l"]) + }), + configured ? { config: { shell: Shell.name(configured) } } : undefined, { timeout: 30000 }, ) }) diff --git a/packages/opencode/test/question/question.test.ts b/packages/opencode/test/question/question.test.ts index 4e2c8ef9bb..3e970b63fa 100644 --- a/packages/opencode/test/question/question.test.ts +++ b/packages/opencode/test/question/question.test.ts @@ -2,7 +2,6 @@ import { afterEach, expect } from "bun:test" import { Cause, Effect, Exit, Fiber, Layer } from "effect" import { Question } from "../../src/question" import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { InstanceRuntime } from "../../src/project/instance-runtime" import { QuestionID } from "../../src/question/schema" import { disposeAllInstances, provideInstance, reloadTestInstance, tmpdirScoped } from "../fixture/fixture" @@ -398,9 +397,8 @@ it.live("pending question rejects on instance dispose", () => }).pipe(provideInstance(dir), Effect.forkScoped) expect(yield* waitForPending(1).pipe(provideInstance(dir))).toHaveLength(1) - yield* Effect.promise(() => - WithInstance.provide({ directory: dir, fn: () => InstanceRuntime.disposeInstance(Instance.current) }), - ) + const ctx = yield* Effect.sync(() => Instance.current).pipe(provideInstance(dir)) + yield* Effect.promise(() => InstanceRuntime.disposeInstance(ctx)) const exit = yield* Fiber.await(fiber) expect(Exit.isFailure(exit)).toBe(true) diff --git a/packages/opencode/test/reference/reference.test.ts b/packages/opencode/test/reference/reference.test.ts index 4717c61d25..f4a73dbf9f 100644 --- a/packages/opencode/test/reference/reference.test.ts +++ b/packages/opencode/test/reference/reference.test.ts @@ -3,8 +3,9 @@ import path from "path" import { Effect, Layer } from "effect" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" -import { Flag } from "@opencode-ai/core/flag/flag" import { Global } from "@opencode-ai/core/global" +import { Config } from "../../src/config/config" +import { RuntimeFlags } from "../../src/effect/runtime-flags" import { Git } from "../../src/git" import { Reference } from "../../src/reference/reference" import { disposeAllInstances, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture" @@ -14,24 +15,26 @@ afterEach(async () => { await disposeAllInstances() }) -const it = testEffect( - Layer.mergeAll(AppFileSystem.defaultLayer, CrossSpawnSpawner.defaultLayer, Git.defaultLayer, Reference.defaultLayer), -) - -const experimentalScout = (self: Effect.Effect) => - Effect.acquireUseRelease( - Effect.sync(() => { - const previous = Flag.OPENCODE_EXPERIMENTAL_SCOUT - Flag.OPENCODE_EXPERIMENTAL_SCOUT = true - return previous - }), - () => self, - (previous) => - Effect.sync(() => { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = previous - }), +const referenceLayer = (flags: Partial = {}) => + Reference.layer.pipe( + Layer.provide(Config.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(Git.defaultLayer), + Layer.provide(RuntimeFlags.layer(flags)), ) +const it = testEffect( + Layer.mergeAll(AppFileSystem.defaultLayer, CrossSpawnSpawner.defaultLayer, Git.defaultLayer, referenceLayer()), +) +const scout = testEffect( + Layer.mergeAll( + AppFileSystem.defaultLayer, + CrossSpawnSpawner.defaultLayer, + Git.defaultLayer, + referenceLayer({ experimentalScout: true }), + ), +) + const githubBase = (url: string, self: Effect.Effect) => Effect.acquireUseRelease( Effect.sync(() => { @@ -127,118 +130,114 @@ describe("reference", () => { }), ) - it.live("materializes configured git references during init", () => - experimentalScout( - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-test", "repo") - yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) - yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) + scout.live("materializes configured git references during init", () => + provideTmpdirInstance( + (_dir) => + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-test", "repo") + yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) + yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) - const source = yield* tmpdirScoped({ git: true }) - const remoteRoot = yield* tmpdirScoped() - const remoteDir = path.join(remoteRoot, "opencode-reference-test") - const remoteRepo = path.join(remoteDir, "repo.git") + const source = yield* tmpdirScoped({ git: true }) + const remoteRoot = yield* tmpdirScoped() + const remoteDir = path.join(remoteRoot, "opencode-reference-test") + const remoteRepo = path.join(remoteDir, "repo.git") - yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "configured\n")) - yield* git(source, ["add", "."]) - yield* git(source, ["commit", "-m", "add readme"]) - yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) - yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) + yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "configured\n")) + yield* git(source, ["add", "."]) + yield* git(source, ["commit", "-m", "add readme"]) + yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) + yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) - const reference = yield* Reference.Service - yield* githubBase( - `file://${remoteRoot}/`, - Effect.gen(function* () { - yield* reference.init() - yield* waitForContent(fs, path.join(cache, "README.md"), "configured\n") - }), - ) + const reference = yield* Reference.Service + yield* githubBase( + `file://${remoteRoot}/`, + Effect.gen(function* () { + yield* reference.init() + yield* waitForContent(fs, path.join(cache, "README.md"), "configured\n") + }), + ) - expect(yield* fs.existsSafe(path.join(cache, ".git"))).toBe(true) - expect(yield* fs.readFileString(path.join(cache, "README.md"))).toBe("configured\n") + expect(yield* fs.existsSafe(path.join(cache, ".git"))).toBe(true) + expect(yield* fs.readFileString(path.join(cache, "README.md"))).toBe("configured\n") - const resolved = yield* reference.get("docs") - expect(resolved?.kind).toBe("git") - if (resolved?.kind === "git") expect(resolved.path).toBe(cache) - }), - { - config: { - reference: { - docs: "opencode-reference-test/repo", - }, + const resolved = yield* reference.get("docs") + expect(resolved?.kind).toBe("git") + if (resolved?.kind === "git") expect(resolved.path).toBe(cache) + }), + { + config: { + reference: { + docs: "opencode-reference-test/repo", }, }, - ), + }, ), ) - it.live("refreshes configured git references on new instance init", () => - experimentalScout( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-refresh", "repo") - yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) - yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) + scout.live("refreshes configured git references on new instance init", () => + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-refresh", "repo") + yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) + yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) - const source = yield* tmpdirScoped({ git: true }) - const remoteRoot = yield* tmpdirScoped() - const remoteDir = path.join(remoteRoot, "opencode-reference-refresh") - const remoteRepo = path.join(remoteDir, "repo.git") + const source = yield* tmpdirScoped({ git: true }) + const remoteRoot = yield* tmpdirScoped() + const remoteDir = path.join(remoteRoot, "opencode-reference-refresh") + const remoteRepo = path.join(remoteDir, "repo.git") - yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v1\n")) - yield* git(source, ["add", "."]) - yield* git(source, ["commit", "-m", "add readme"]) - yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) - yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) + yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v1\n")) + yield* git(source, ["add", "."]) + yield* git(source, ["commit", "-m", "add readme"]) + yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) + yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) - yield* githubBase( - `file://${remoteRoot}/`, - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const reference = yield* Reference.Service - yield* reference.init() - yield* waitForContent(fs, path.join(cache, "README.md"), "v1\n") - }), - { - config: { - reference: { - docs: "opencode-reference-refresh/repo", - }, + yield* githubBase( + `file://${remoteRoot}/`, + provideTmpdirInstance( + (_dir) => + Effect.gen(function* () { + const reference = yield* Reference.Service + yield* reference.init() + yield* waitForContent(fs, path.join(cache, "README.md"), "v1\n") + }), + { + config: { + reference: { + docs: "opencode-reference-refresh/repo", }, }, - ), - ) + }, + ), + ) - const branch = yield* git(source, ["branch", "--show-current"]) - yield* git(source, ["remote", "add", "origin", remoteRepo]) - yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v2\n")) - yield* git(source, ["add", "."]) - yield* git(source, ["commit", "-m", "update readme"]) - yield* git(source, ["push", "origin", `${branch}:${branch}`]) + const branch = yield* git(source, ["branch", "--show-current"]) + yield* git(source, ["remote", "add", "origin", remoteRepo]) + yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v2\n")) + yield* git(source, ["add", "."]) + yield* git(source, ["commit", "-m", "update readme"]) + yield* git(source, ["push", "origin", `${branch}:${branch}`]) - yield* githubBase( - `file://${remoteRoot}/`, - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const reference = yield* Reference.Service - yield* reference.init() - yield* waitForContent(fs, path.join(cache, "README.md"), "v2\n") - }), - { - config: { - reference: { - docs: "opencode-reference-refresh/repo", - }, + yield* githubBase( + `file://${remoteRoot}/`, + provideTmpdirInstance( + (_dir) => + Effect.gen(function* () { + const reference = yield* Reference.Service + yield* reference.init() + yield* waitForContent(fs, path.join(cache, "README.md"), "v2\n") + }), + { + config: { + reference: { + docs: "opencode-reference-refresh/repo", }, }, - ), - ) - }), - ), + }, + ), + ) + }), ) }) diff --git a/packages/opencode/test/server/global-bus.ts b/packages/opencode/test/server/global-bus.ts index c8d0f92191..24e5cf77b5 100644 --- a/packages/opencode/test/server/global-bus.ts +++ b/packages/opencode/test/server/global-bus.ts @@ -29,6 +29,3 @@ export function waitGlobalBusEvent(input: { ), ) } - -export const waitGlobalBusEventPromise = (input: Parameters[0]) => - Effect.runPromise(waitGlobalBusEvent(input)) diff --git a/packages/opencode/test/server/global-session-list.test.ts b/packages/opencode/test/server/global-session-list.test.ts index 04348e5c0d..0fdba1f663 100644 --- a/packages/opencode/test/server/global-session-list.test.ts +++ b/packages/opencode/test/server/global-session-list.test.ts @@ -1,104 +1,104 @@ -import { describe, expect, test } from "bun:test" -import { Effect } from "effect" -import { WithInstance } from "../../src/project/with-instance" +import { describe, expect } from "bun:test" +import { Deferred, Effect, Layer } from "effect" import { Project } from "@/project/project" import { Session as SessionNs } from "@/session/session" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import * as Log from "@opencode-ai/core/util/log" -import { tmpdir } from "../fixture/fixture" +import { provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) -function run(fx: Effect.Effect) { - return Effect.runPromise(fx.pipe(Effect.provide(SessionNs.defaultLayer))) -} +const it = testEffect(Layer.mergeAll(SessionNs.defaultLayer, Project.defaultLayer, CrossSpawnSpawner.defaultLayer)) -const svc = { - ...SessionNs, - create(input?: SessionNs.CreateInput) { - return run(SessionNs.Service.use((svc) => svc.create(input))) - }, - setArchived(input: typeof SessionNs.SetArchivedInput.Type) { - return run(SessionNs.Service.use((svc) => svc.setArchived(input))) - }, -} +const withSession = (input?: Parameters[0]) => + Effect.acquireRelease( + SessionNs.Service.use((session) => session.create(input)), + (created) => SessionNs.Service.use((session) => session.remove(created.id).pipe(Effect.ignore)), + ) describe("session.listGlobal", () => { - test("lists sessions across projects with project metadata", async () => { - await using first = await tmpdir({ git: true }) - await using second = await tmpdir({ git: true }) + it.instance( + "lists sessions across projects with project metadata", + () => + Effect.gen(function* () { + const first = yield* TestInstance + const second = yield* tmpdirScoped({ git: true }) - const firstSession = await WithInstance.provide({ - directory: first.path, - fn: async () => svc.create({ title: "first-session" }), - }) - const secondSession = await WithInstance.provide({ - directory: second.path, - fn: async () => svc.create({ title: "second-session" }), - }) + const firstSession = yield* withSession({ title: "first-session" }) + const secondSession = yield* withSession({ title: "second-session" }).pipe(provideInstance(second)) - const sessions = [...svc.listGlobal({ limit: 200 })] - const ids = sessions.map((session) => session.id) + const sessions = yield* Effect.sync(() => [...SessionNs.listGlobal({ limit: 200 })]) + const ids = sessions.map((session) => session.id) - expect(ids).toContain(firstSession.id) - expect(ids).toContain(secondSession.id) + expect(ids).toContain(firstSession.id) + expect(ids).toContain(secondSession.id) - const firstProject = Project.get(firstSession.projectID) - const secondProject = Project.get(secondSession.projectID) + const firstProject = yield* Project.Service.use((project) => project.get(firstSession.projectID)) + const secondProject = yield* Project.Service.use((project) => project.get(secondSession.projectID)) - const firstItem = sessions.find((session) => session.id === firstSession.id) - const secondItem = sessions.find((session) => session.id === secondSession.id) + const firstItem = sessions.find((session) => session.id === firstSession.id) + const secondItem = sessions.find((session) => session.id === secondSession.id) - expect(firstItem?.project?.id).toBe(firstProject?.id) - expect(firstItem?.project?.worktree).toBe(firstProject?.worktree) - expect(secondItem?.project?.id).toBe(secondProject?.id) - expect(secondItem?.project?.worktree).toBe(secondProject?.worktree) - }) + expect(firstItem?.project?.id).toBe(firstProject?.id) + expect(firstItem?.project?.worktree).toBe(firstProject?.worktree) + expect(secondItem?.project?.id).toBe(secondProject?.id) + expect(secondItem?.project?.worktree).toBe(secondProject?.worktree) + expect(first.directory).not.toBe(second) + }), + { git: true }, + ) - test("excludes archived sessions by default", async () => { - await using tmp = await tmpdir({ git: true }) + it.instance( + "excludes archived sessions by default", + () => + Effect.gen(function* () { + const archived = yield* withSession({ title: "archived-session" }) - const archived = await WithInstance.provide({ - directory: tmp.path, - fn: async () => svc.create({ title: "archived-session" }), - }) + yield* SessionNs.Service.use((session) => session.setArchived({ sessionID: archived.id, time: Date.now() })) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => svc.setArchived({ sessionID: archived.id, time: Date.now() }), - }) + const sessions = yield* Effect.sync(() => [...SessionNs.listGlobal({ limit: 200 })]) + const ids = sessions.map((session) => session.id) - const sessions = [...svc.listGlobal({ limit: 200 })] - const ids = sessions.map((session) => session.id) + expect(ids).not.toContain(archived.id) - expect(ids).not.toContain(archived.id) + const allSessions = yield* Effect.sync(() => [...SessionNs.listGlobal({ limit: 200, archived: true })]) + const allIds = allSessions.map((session) => session.id) - const allSessions = [...svc.listGlobal({ limit: 200, archived: true })] - const allIds = allSessions.map((session) => session.id) + expect(allIds).toContain(archived.id) + }), + { git: true }, + ) - expect(allIds).toContain(archived.id) - }) + it.instance( + "supports cursor pagination", + () => + Effect.gen(function* () { + const test = yield* TestInstance - test("supports cursor pagination", async () => { - await using tmp = await tmpdir({ git: true }) + const first = yield* withSession({ title: "page-one" }) + const ready = yield* Deferred.make() + yield* Deferred.succeed(ready, undefined).pipe(Effect.delay("5 millis"), Effect.forkScoped) + yield* Deferred.await(ready).pipe( + Effect.timeoutOrElse({ + duration: "1 second", + orElse: () => Effect.fail(new Error("timed out waiting between session creates")), + }), + ) + const second = yield* withSession({ title: "page-two" }) - const first = await WithInstance.provide({ - directory: tmp.path, - fn: async () => svc.create({ title: "page-one" }), - }) - await new Promise((resolve) => setTimeout(resolve, 5)) - const second = await WithInstance.provide({ - directory: tmp.path, - fn: async () => svc.create({ title: "page-two" }), - }) + const page = yield* Effect.sync(() => [...SessionNs.listGlobal({ directory: test.directory, limit: 1 })]) + expect(page.length).toBe(1) + expect(page[0].id).toBe(second.id) - const page = [...svc.listGlobal({ directory: tmp.path, limit: 1 })] - expect(page.length).toBe(1) - expect(page[0].id).toBe(second.id) + const next = yield* Effect.sync(() => [ + ...SessionNs.listGlobal({ directory: test.directory, limit: 10, cursor: page[0].time.updated }), + ]) + const ids = next.map((session) => session.id) - const next = [...svc.listGlobal({ directory: tmp.path, limit: 10, cursor: page[0].time.updated })] - const ids = next.map((session) => session.id) - - expect(ids).toContain(first.id) - expect(ids).not.toContain(second.id) - }) + expect(ids).toContain(first.id) + expect(ids).not.toContain(second.id) + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/server/httpapi-config.test.ts b/packages/opencode/test/server/httpapi-config.test.ts index 26c0fe03e6..7619a0c881 100644 --- a/packages/opencode/test/server/httpapi-config.test.ts +++ b/packages/opencode/test/server/httpapi-config.test.ts @@ -1,10 +1,12 @@ -import { afterEach, describe, expect, test } from "bun:test" +import { afterEach, describe, expect } from "bun:test" import path from "path" import { Server } from "../../src/server/server" import * as Log from "@opencode-ai/core/util/log" +import { Effect, Fiber } from "effect" import { resetDatabase } from "../fixture/db" import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { waitGlobalBusEventPromise } from "./global-bus" +import { it } from "../lib/effect" +import { waitGlobalBusEvent } from "./global-bus" void Log.init({ print: false }) @@ -12,47 +14,90 @@ function app() { return Server.Default().app } -async function waitDisposed(directory: string) { - await waitGlobalBusEventPromise({ +function waitDisposed(directory: string) { + return waitGlobalBusEvent({ message: "timed out waiting for instance disposal", predicate: (event) => event.payload.type === "server.instance.disposed" && event.directory === directory, }) } +const tmpdirEffect = (options: Parameters[0]) => + Effect.acquireRelease( + Effect.promise(() => tmpdir(options)), + (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), + ) + afterEach(async () => { await disposeAllInstances() await resetDatabase() }) describe("config HttpApi", () => { - test("serves config update through the default server app", async () => { - await using tmp = await tmpdir({ config: { formatter: false, lsp: false } }) - const disposed = waitDisposed(tmp.path) + it.live( + "serves config update through the default server app", + Effect.gen(function* () { + const tmp = yield* tmpdirEffect({ config: { formatter: false, lsp: false } }) + const disposed = yield* waitDisposed(tmp.path).pipe(Effect.forkScoped) - const response = await app().request("/config", { - method: "PATCH", - headers: { - "content-type": "application/json", - "x-opencode-directory": tmp.path, - }, - body: JSON.stringify({ username: "patched-user", formatter: false, lsp: false }), - }) + const response = yield* Effect.promise(() => + Promise.resolve( + app().request("/config", { + method: "PATCH", + headers: { + "content-type": "application/json", + "x-opencode-directory": tmp.path, + }, + body: JSON.stringify({ username: "patched-user", formatter: false, lsp: false }), + }), + ), + ) - expect(response.status).toBe(200) - expect(await response.json()).toMatchObject({ username: "patched-user", formatter: false, lsp: false }) - await disposed - expect(await Bun.file(path.join(tmp.path, "config.json")).json()).toMatchObject({ - username: "patched-user", - formatter: false, - lsp: false, - }) - }) - - test("serves config with active provider model status", async () => { - await using tmp = await tmpdir({ - config: { + expect(response.status).toBe(200) + expect(yield* Effect.promise(() => response.json())).toMatchObject({ + username: "patched-user", formatter: false, lsp: false, + }) + yield* Fiber.join(disposed) + expect(yield* Effect.promise(() => Bun.file(path.join(tmp.path, "config.json")).json())).toMatchObject({ + username: "patched-user", + formatter: false, + lsp: false, + }) + }), + ) + + it.live( + "serves config with active provider model status", + Effect.gen(function* () { + const tmp = yield* tmpdirEffect({ + config: { + formatter: false, + lsp: false, + provider: { + omniroute: { + models: { + "gpt-4o": { + status: "active", + }, + }, + }, + }, + }, + }) + + const response = yield* Effect.promise(() => + Promise.resolve( + app().request("/config", { + headers: { + "x-opencode-directory": tmp.path, + }, + }), + ), + ) + + expect(response.status).toBe(200) + expect(yield* Effect.promise(() => response.json())).toMatchObject({ provider: { omniroute: { models: { @@ -62,26 +107,7 @@ describe("config HttpApi", () => { }, }, }, - }, - }) - - const response = await app().request("/config", { - headers: { - "x-opencode-directory": tmp.path, - }, - }) - - expect(response.status).toBe(200) - expect(await response.json()).toMatchObject({ - provider: { - omniroute: { - models: { - "gpt-4o": { - status: "active", - }, - }, - }, - }, - }) - }) + }) + }), + ) }) diff --git a/packages/opencode/test/server/httpapi-error-middleware.test.ts b/packages/opencode/test/server/httpapi-error-middleware.test.ts new file mode 100644 index 0000000000..f53a9e887b --- /dev/null +++ b/packages/opencode/test/server/httpapi-error-middleware.test.ts @@ -0,0 +1,50 @@ +import { NodeHttpServer, NodeServices } from "@effect/platform-node" +import { describe, expect } from "bun:test" +import { Effect, Layer } from "effect" +import { HttpClient, HttpClientRequest, HttpRouter } from "effect/unstable/http" +import { errorLayer } from "../../src/server/routes/instance/httpapi/middleware/error" +import { NotFoundError } from "../../src/storage/storage" +import { testEffect } from "../lib/effect" + +const it = testEffect(Layer.mergeAll(NodeHttpServer.layerTest, NodeServices.layer)) + +describe("HttpApi error middleware", () => { + it.live("returns a safe body for unknown 500 defects", () => + Effect.gen(function* () { + yield* HttpRouter.add("GET", "/boom", Effect.die(new Error("secret stack marker"))).pipe( + Layer.provide(errorLayer), + HttpRouter.serve, + Layer.build, + ) + + const response = yield* HttpClientRequest.get("/boom").pipe(HttpClient.execute) + const body = yield* response.json + + expect(response.status).toBe(500) + expect(body).toEqual({ + name: "UnknownError", + data: { message: "Unexpected server error. Check server logs for details." }, + }) + expect(JSON.stringify(body)).not.toContain("secret stack marker") + }), + ) + + it.live("does not map storage not-found defects to 404", () => + Effect.gen(function* () { + yield* HttpRouter.add( + "GET", + "/missing", + Effect.die(new NotFoundError({ message: "Resource not found: secret" })), + ).pipe(Layer.provide(errorLayer), HttpRouter.serve, Layer.build) + + const response = yield* HttpClientRequest.get("/missing").pipe(HttpClient.execute) + const body = yield* response.json + + expect(response.status).toBe(500) + expect(body).toEqual({ + name: "UnknownError", + data: { message: "Unexpected server error. Check server logs for details." }, + }) + }), + ) +}) diff --git a/packages/opencode/test/server/httpapi-exercise/index.ts b/packages/opencode/test/server/httpapi-exercise/index.ts index 0d6bec2dfe..293e2a3449 100644 --- a/packages/opencode/test/server/httpapi-exercise/index.ts +++ b/packages/opencode/test/server/httpapi-exercise/index.ts @@ -593,6 +593,12 @@ const scenarios: Scenario[] = [ check(auth.test === undefined, "auth remove should delete provider from isolated auth file") }), ), + http.protected.get("/api/model", "v2.model.list").json(200, array), + http.protected.get("/api/provider", "v2.provider.list").json(200, array), + http.protected + .get("/api/provider/{providerID}", "v2.provider.get") + .at((ctx) => ({ path: route("/api/provider/{providerID}", { providerID: "missing" }), headers: ctx.headers() })) + .json(404, object, "status"), http.protected .get("/api/session", "v2.session.list") .at((ctx) => ({ path: "/api/session?roots=true", headers: ctx.headers() })) diff --git a/packages/opencode/test/server/httpapi-exercise/runner.ts b/packages/opencode/test/server/httpapi-exercise/runner.ts index bc246dbeda..b14647680c 100644 --- a/packages/opencode/test/server/httpapi-exercise/runner.ts +++ b/packages/opencode/test/server/httpapi-exercise/runner.ts @@ -168,9 +168,10 @@ function withContext( ) return { info, part } }), - messages: (sessionID) => run(modules.Session.Service.use((svc) => svc.messages({ sessionID }))), + messages: (sessionID) => + run(modules.Session.Service.use((svc) => svc.messages({ sessionID }).pipe(Effect.orDie))), todos: (sessionID, todos) => run(modules.Todo.Service.use((svc) => svc.update({ sessionID, todos }))), - worktree: (input) => run(modules.Worktree.Service.use((svc) => svc.create(input))), + worktree: (input) => run(modules.Worktree.Service.use((svc) => svc.create(input).pipe(Effect.orDie))), worktreeRemove: (directory) => run(modules.Worktree.Service.use((svc) => svc.remove({ directory })).pipe(Effect.ignore)), llmText: (value) => Effect.suspend(() => llm().text(value)), diff --git a/packages/opencode/test/server/httpapi-experimental.test.ts b/packages/opencode/test/server/httpapi-experimental.test.ts index 383442e00e..2613ee3850 100644 --- a/packages/opencode/test/server/httpapi-experimental.test.ts +++ b/packages/opencode/test/server/httpapi-experimental.test.ts @@ -1,47 +1,183 @@ -import { afterEach, describe, expect, test } from "bun:test" -import { Effect } from "effect" -import { WithInstance } from "../../src/project/with-instance" +import { afterEach, describe, expect } from "bun:test" +import { Deferred, Effect, Fiber, Layer } from "effect" +import { eq } from "drizzle-orm" +import { GlobalBus, type GlobalEvent } from "@/bus/global" import { Server } from "../../src/server/server" import { ExperimentalPaths } from "../../src/server/routes/instance/httpapi/groups/experimental" import { Session } from "@/session/session" +import { SessionTable } from "@/session/session.sql" import { Database } from "@/storage/db" import * as Log from "@opencode-ai/core/util/log" import { Worktree } from "../../src/worktree" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { waitGlobalBusEventPromise } from "./global-bus" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) -const testWorktreeMutations = process.platform === "win32" ? test.skip : test +const it = testEffect(Layer.mergeAll(Session.defaultLayer)) +const testWorktreeMutations = process.platform === "win32" ? it.instance.skip : it.instance function app() { return Server.Default().app } -function runSession(fx: Effect.Effect) { - return Effect.runPromise(fx.pipe(Effect.provide(Session.defaultLayer))) +function request(path: string, directory: string, init: RequestInit = {}) { + return Effect.promise(() => { + const headers = new Headers(init.headers) + headers.set("x-opencode-directory", directory) + return Promise.resolve(app().request(path, { ...init, headers })) + }) } function createSession(input?: Session.CreateInput) { - return runSession(Session.Service.use((svc) => svc.create(input))) + return Session.Service.use((svc) => svc.create(input)) } -async function waitReady(directory: string) { - await waitGlobalBusEventPromise({ - message: "timed out waiting for worktree.ready", - predicate: (event) => event.payload.type === Worktree.Event.Ready.type && event.directory === directory, +function json(response: Response) { + return Effect.promise(() => response.json() as Promise) +} + +function waitReady(input: { directory?: string; name?: string }) { + return Effect.gen(function* () { + const ready = yield* Deferred.make() + const on = (event: GlobalEvent) => { + if (event.payload.type !== Worktree.Event.Ready.type) return + if (input.directory && event.directory !== input.directory) return + if (input.name && event.payload.properties.name !== input.name) return + Deferred.doneUnsafe(ready, Effect.void) + } + + GlobalBus.on("event", on) + yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", on))) + + return yield* Deferred.await(ready).pipe( + Effect.timeoutOrElse({ + duration: "10 seconds", + orElse: () => Effect.fail(new Error("timed out waiting for worktree.ready")), + }), + ) }) } +function insertAccount() { + return Effect.acquireRelease( + Effect.sync(() => { + Database.Client() + .$client.prepare( + "INSERT INTO account (id, email, url, access_token, refresh_token, time_created, time_updated) VALUES (?, ?, ?, ?, ?, ?, ?)", + ) + .run( + "account-test", + "test@example.com", + "https://console.example.com", + "access", + "refresh", + Date.now(), + Date.now(), + ) + return "account-test" + }), + (id) => + Effect.sync(() => { + Database.Client().$client.prepare("DELETE FROM account WHERE id = ?").run(id) + }), + ) +} + +function setSessionUpdated(session: Session.Info, updated: number) { + return Effect.sync(() => { + Database.use((db) => + db.update(SessionTable).set({ time_updated: updated }).where(eq(SessionTable.id, session.id)).run(), + ) + }) +} + +function withCreatedWorktree(directory: string, use: (info: Worktree.Info) => Effect.Effect) { + const name = "api-test" + const headers = { "content-type": "application/json" } + return Effect.acquireUseRelease( + Effect.gen(function* () { + const ready = yield* waitReady({ name }).pipe(Effect.forkScoped) + const created = yield* request(ExperimentalPaths.worktree, directory, { + method: "POST", + headers, + body: JSON.stringify({ name }), + }) + + expect(created.status).toBe(200) + const info = yield* json(created) + expect(info).toMatchObject({ name, branch: "opencode/api-test" }) + yield* Fiber.join(ready) + return info + }), + use, + (info) => + Effect.gen(function* () { + const removed = yield* request(ExperimentalPaths.worktree, directory, { + method: "DELETE", + headers, + body: JSON.stringify({ directory: info.directory }), + }) + if (removed.status !== 200) return yield* Effect.fail(new Error(`failed to remove worktree: ${removed.status}`)) + const ok = yield* json(removed) + if (!ok) return yield* Effect.fail(new Error(`failed to remove worktree ${info.directory}`)) + }), + ) +} + afterEach(async () => { await disposeAllInstances() await resetDatabase() }) describe("experimental HttpApi", () => { - test("serves read-only experimental endpoints through the default server app", async () => { - await using tmp = await tmpdir({ + it.instance( + "serves read-only experimental endpoints through the default server app", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const directory = tmp.directory + const [consoleState, consoleOrgs, toolList, toolIDs, worktrees, resources] = yield* Effect.all( + [ + request(ExperimentalPaths.console, directory), + request(ExperimentalPaths.consoleOrgs, directory), + request(`${ExperimentalPaths.tool}?provider=opencode&model=gpt-5`, directory), + request(ExperimentalPaths.toolIDs, directory), + request(ExperimentalPaths.worktree, directory), + request(ExperimentalPaths.resource, directory), + ], + { concurrency: "unbounded" }, + ) + + expect(consoleState.status).toBe(200) + expect(yield* json(consoleState)).toEqual({ + consoleManagedProviders: [], + switchableOrgCount: 0, + }) + + expect(consoleOrgs.status).toBe(200) + expect(yield* json(consoleOrgs)).toEqual({ orgs: [] }) + + expect(toolList.status).toBe(200) + expect(yield* json(toolList)).toContainEqual( + expect.objectContaining({ + id: "bash", + description: expect.any(String), + parameters: expect.any(Object), + }), + ) + + expect(toolIDs.status).toBe(200) + expect(yield* json(toolIDs)).toContain("bash") + + expect(worktrees.status).toBe(200) + expect(yield* json(worktrees)).toEqual([]) + + expect(resources.status).toBe(200) + expect(yield* json(resources)).toEqual({}) + }), + { config: { formatter: false, lsp: false, @@ -53,150 +189,105 @@ describe("experimental HttpApi", () => { }, }, }, - }) + }, + ) - const headers = { "x-opencode-directory": tmp.path } - const [consoleState, consoleOrgs, toolList, toolIDs, worktrees, resources] = await Promise.all([ - app().request(ExperimentalPaths.console, { headers }), - app().request(ExperimentalPaths.consoleOrgs, { headers }), - app().request(`${ExperimentalPaths.tool}?provider=opencode&model=gpt-5`, { headers }), - app().request(ExperimentalPaths.toolIDs, { headers }), - app().request(ExperimentalPaths.worktree, { headers }), - app().request(ExperimentalPaths.resource, { headers }), - ]) - - expect(consoleState.status).toBe(200) - expect(await consoleState.json()).toEqual({ - consoleManagedProviders: [], - switchableOrgCount: 0, - }) - - expect(consoleOrgs.status).toBe(200) - expect(await consoleOrgs.json()).toEqual({ orgs: [] }) - - expect(toolList.status).toBe(200) - expect(await toolList.json()).toContainEqual( - expect.objectContaining({ - id: "bash", - description: expect.any(String), - parameters: expect.any(Object), - }), - ) - - expect(toolIDs.status).toBe(200) - expect(await toolIDs.json()).toContain("bash") - - expect(worktrees.status).toBe(200) - expect(await worktrees.json()).toEqual([]) - - expect(resources.status).toBe(200) - expect(await resources.json()).toEqual({}) - }) - - test("serves Console org switch through the default server app", async () => { - await using tmp = await tmpdir({ config: { formatter: false, lsp: false } }) - Database.Client() - .$client.prepare( - "INSERT INTO account (id, email, url, access_token, refresh_token, time_created, time_updated) VALUES (?, ?, ?, ?, ?, ?, ?)", - ) - .run( - "account-test", - "test@example.com", - "https://console.example.com", - "access", - "refresh", - Date.now(), - Date.now(), - ) - - const switched = await app().request(ExperimentalPaths.consoleSwitch, { - method: "POST", - headers: { "x-opencode-directory": tmp.path, "content-type": "application/json" }, - body: JSON.stringify({ accountID: "account-test", orgID: "org-test" }), - }) - - expect(switched.status).toBe(200) - expect(await switched.json()).toBe(true) - }) - - test("serves global session list through the default server app", async () => { - await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } }) - - const first = await WithInstance.provide({ - directory: tmp.path, - fn: async () => createSession({ title: "page-one" }), - }) - await new Promise((resolve) => setTimeout(resolve, 5)) - const second = await WithInstance.provide({ - directory: tmp.path, - fn: async () => createSession({ title: "page-two" }), - }) - - const headers = { "x-opencode-directory": tmp.path } - const page = await app().request( - `${ExperimentalPaths.session}?${new URLSearchParams({ directory: tmp.path, limit: "1" })}`, - { headers }, - ) - expect(page.status).toBe(200) - expect(page.headers.get("x-next-cursor")).toBeTruthy() - - const body = (await page.json()) as Session.GlobalInfo[] - expect(body.map((session) => session.id)).toEqual([second.id]) - expect(body[0].project?.id).toBe(second.projectID) - - const next = await app().request( - `${ExperimentalPaths.session}?${new URLSearchParams({ - directory: tmp.path, - limit: "10", - cursor: body[0].time.updated.toString(), - })}`, - { headers }, - ) - expect(next.status).toBe(200) - expect(((await next.json()) as Session.GlobalInfo[]).map((session) => session.id)).toContain(first.id) - }) - - testWorktreeMutations("serves worktree mutations through the default server app", async () => { - await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } }) - - const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" } - const created = await app().request(ExperimentalPaths.worktree, { - method: "POST", - headers, - body: JSON.stringify({ name: "api-test" }), - }) - - expect(created.status).toBe(200) - const info = (await created.json()) as Worktree.Info - expect(info).toMatchObject({ name: "api-test", branch: "opencode/api-test" }) - await waitReady(info.directory) - - const listed = await app().request(ExperimentalPaths.worktree, { headers }) - expect(listed.status).toBe(200) - expect(await listed.json()).toContain(info.directory) - - if (process.platform !== "win32") { - const reset = await app().request(ExperimentalPaths.worktreeReset, { + it.instance("returns declared worktree errors", () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const response = yield* request(ExperimentalPaths.worktree, tmp.directory, { method: "POST", - headers, - body: JSON.stringify({ directory: info.directory }), + headers: { "content-type": "application/json" }, + body: JSON.stringify({}), }) - expect(reset.status).toBe(200) - expect(await reset.json()).toBe(true) - } + expect(response.status).toBe(400) + expect(yield* json(response)).toEqual({ + name: "WorktreeNotGitError", + data: { message: "Worktrees are only supported for git projects" }, + }) + }), + ) - const removed = await app().request(ExperimentalPaths.worktree, { - method: "DELETE", - headers, - body: JSON.stringify({ directory: info.directory }), - }) + it.instance( + "serves Console org switch through the default server app", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const accountID = yield* insertAccount() + const switched = yield* request(ExperimentalPaths.consoleSwitch, tmp.directory, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ accountID, orgID: "org-test" }), + }) - expect(removed.status).toBe(200) - expect(await removed.json()).toBe(true) + expect(switched.status).toBe(200) + expect(yield* json(switched)).toBe(true) + }), + { config: { formatter: false, lsp: false } }, + ) - const afterRemove = await app().request(ExperimentalPaths.worktree, { headers }) - expect(afterRemove.status).toBe(200) - expect(await afterRemove.json()).toEqual([]) - }) + it.instance( + "serves global session list through the default server app", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const first = yield* createSession({ title: "page-one" }) + const second = yield* createSession({ title: "page-two" }) + yield* setSessionUpdated(first, 1) + yield* setSessionUpdated(second, 2) + + const page = yield* request( + `${ExperimentalPaths.session}?${new URLSearchParams({ directory: tmp.directory, limit: "1" })}`, + tmp.directory, + ) + expect(page.status).toBe(200) + expect(page.headers.get("x-next-cursor")).toBeTruthy() + + const body = yield* json(page) + expect(body.map((session) => session.id)).toEqual([second.id]) + expect(body[0].project?.id).toBe(second.projectID) + + const next = yield* request( + `${ExperimentalPaths.session}?${new URLSearchParams({ + directory: tmp.directory, + limit: "10", + cursor: body[0].time.updated.toString(), + })}`, + tmp.directory, + ) + expect(next.status).toBe(200) + expect((yield* json(next)).map((session) => session.id)).toContain(first.id) + }), + { git: true, config: { formatter: false, lsp: false } }, + ) + + testWorktreeMutations( + "serves worktree mutations through the default server app", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + yield* withCreatedWorktree(tmp.directory, (info) => + Effect.gen(function* () { + const listed = yield* request(ExperimentalPaths.worktree, tmp.directory) + expect(listed.status).toBe(200) + expect(yield* json(listed)).toContain(info.directory) + + const reset = yield* request(ExperimentalPaths.worktreeReset, tmp.directory, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ directory: info.directory }), + }) + + expect(reset.status).toBe(200) + expect(yield* json(reset)).toBe(true) + }), + ) + + const afterRemove = yield* request(ExperimentalPaths.worktree, tmp.directory) + expect(afterRemove.status).toBe(200) + expect(yield* json(afterRemove)).toEqual([]) + }), + { git: true, config: { formatter: false, lsp: false } }, + ) }) diff --git a/packages/opencode/test/server/httpapi-mcp.test.ts b/packages/opencode/test/server/httpapi-mcp.test.ts index b6c7aebcd2..21cb0cfd24 100644 --- a/packages/opencode/test/server/httpapi-mcp.test.ts +++ b/packages/opencode/test/server/httpapi-mcp.test.ts @@ -1,69 +1,57 @@ -import { afterEach, describe, expect, test } from "bun:test" -import { Context, Effect, FileSystem, Layer, Path } from "effect" -import { NodeFileSystem, NodePath } from "@effect/platform-node" +import { describe, expect } from "bun:test" +import { Context, Effect, Layer } from "effect" import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" import { McpPaths } from "../../src/server/routes/instance/httpapi/groups/mcp" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" -import { InstanceRuntime } from "../../src/project/instance-runtime" import { Server } from "../../src/server/server" import * as Log from "@opencode-ai/core/util/log" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture" +import { TestInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" void Log.init({ print: false }) const context = Context.empty() as Context.Context -const it = testEffect(Layer.mergeAll(NodeFileSystem.layer, NodePath.layer)) +const testStateLayer = Layer.effectDiscard( + Effect.gen(function* () { + yield* Effect.promise(() => resetDatabase()) + yield* Effect.addFinalizer(() => Effect.promise(() => resetDatabase()).pipe(Effect.ignore)) + }), +) +const it = testEffect(testStateLayer) function app() { return Server.Default().app } type TestApp = ReturnType +type TestHandler = ReturnType -function request(route: string, directory: string, init?: RequestInit) { +const handlerScoped = Effect.acquireRelease( + Effect.sync(() => ExperimentalHttpApiServer.webHandler()), + (handler) => Effect.promise(() => handler.dispose()).pipe(Effect.ignore), +) + +const request = Effect.fnUntraced(function* ( + handler: TestHandler, + route: string, + directory: string, + init?: RequestInit, +) { const headers = new Headers(init?.headers) headers.set("x-opencode-directory", directory) - return ExperimentalHttpApiServer.webHandler().handler( - new Request(`http://localhost${route}`, { - ...init, - headers, - }), - context, + return yield* Effect.promise(() => + Promise.resolve( + handler.handler( + new Request(`http://localhost${route}`, { + ...init, + headers, + }), + context, + ), + ), ) -} +}) -function withMcpProject(self: (dir: string) => Effect.Effect) { - return Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - const dir = yield* fs.makeTempDirectoryScoped({ prefix: "opencode-test-" }) - - yield* fs.writeFileString( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - formatter: false, - lsp: false, - mcp: { - demo: { - type: "local", - command: ["echo", "demo"], - enabled: false, - }, - }, - }), - ) - yield* Effect.addFinalizer(() => - Effect.promise(() => - WithInstance.provide({ directory: dir, fn: () => InstanceRuntime.disposeInstance(Instance.current) }), - ).pipe(Effect.ignore), - ) - - return yield* self(dir).pipe(provideInstance(dir)) - }) -} +const json = (response: Response) => Effect.promise(() => response.json() as Promise) const readResponse = Effect.fnUntraced(function* (input: { app: TestApp; path: string; headers: HeadersInit }) { const response = yield* Effect.promise(() => @@ -75,95 +63,108 @@ const readResponse = Effect.fnUntraced(function* (input: { app: TestApp; path: s } }) -afterEach(async () => { - await disposeAllInstances() - await resetDatabase() -}) - describe("mcp HttpApi", () => { - test("serves status endpoint", async () => { - await using tmp = await tmpdir({ - config: { - mcp: { - demo: { - type: "local", - command: ["echo", "demo"], - enabled: false, - }, - }, - }, - }) - - const response = await request(McpPaths.status, tmp.path) - expect(response.status).toBe(200) - expect(await response.json()).toEqual({ demo: { status: "disabled" } }) - }) - - test("serves add, connect, and disconnect endpoints", async () => { - await using tmp = await tmpdir({ - config: { - mcp: { - demo: { - type: "local", - command: ["echo", "demo"], - enabled: false, - }, - }, - }, - }) - - const added = await request(McpPaths.status, tmp.path, { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ - name: "added", - config: { - type: "local", - command: ["echo", "added"], - enabled: false, - }, - }), - }) - expect(added.status).toBe(200) - expect(await added.json()).toMatchObject({ added: { status: "disabled" } }) - - const connected = await request("/mcp/demo/connect", tmp.path, { method: "POST" }) - expect(connected.status).toBe(200) - expect(await connected.json()).toBe(true) - - const disconnected = await request("/mcp/demo/disconnect", tmp.path, { method: "POST" }) - expect(disconnected.status).toBe(200) - expect(await disconnected.json()).toBe(true) - }) - - test("serves deterministic OAuth endpoints", async () => { - await using tmp = await tmpdir({ - config: { - mcp: { - demo: { - type: "local", - command: ["echo", "demo"], - enabled: false, - }, - }, - }, - }) - - const start = await request("/mcp/demo/auth", tmp.path, { method: "POST" }) - expect(start.status).toBe(400) - - const authenticate = await request("/mcp/demo/auth/authenticate", tmp.path, { method: "POST" }) - expect(authenticate.status).toBe(400) - - const removed = await request("/mcp/demo/auth", tmp.path, { method: "DELETE" }) - expect(removed.status).toBe(200) - expect(await removed.json()).toEqual({ success: true }) - }) - - it.live( - "returns unsupported OAuth error responses", - withMcpProject((dir) => + it.instance( + "serves status endpoint", + () => Effect.gen(function* () { + const tmp = yield* TestInstance + const handler = yield* handlerScoped + const response = yield* request(handler, McpPaths.status, tmp.directory) + + expect(response.status).toBe(200) + expect(yield* json(response)).toEqual({ demo: { status: "disabled" } }) + }), + { + config: { + mcp: { + demo: { + type: "local", + command: ["echo", "demo"], + enabled: false, + }, + }, + }, + }, + ) + + it.instance( + "serves add, connect, and disconnect endpoints", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const handler = yield* handlerScoped + const added = yield* request(handler, McpPaths.status, tmp.directory, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + name: "added", + config: { + type: "local", + command: ["echo", "added"], + enabled: false, + }, + }), + }) + expect(added.status).toBe(200) + expect(yield* json(added)).toMatchObject({ added: { status: "disabled" } }) + + const connected = yield* request(handler, "/mcp/demo/connect", tmp.directory, { method: "POST" }) + expect(connected.status).toBe(200) + expect(yield* json(connected)).toBe(true) + + const disconnected = yield* request(handler, "/mcp/demo/disconnect", tmp.directory, { method: "POST" }) + expect(disconnected.status).toBe(200) + expect(yield* json(disconnected)).toBe(true) + }), + { + config: { + mcp: { + demo: { + type: "local", + command: ["echo", "demo"], + enabled: false, + }, + }, + }, + }, + ) + + it.instance( + "serves deterministic OAuth endpoints", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const handler = yield* handlerScoped + const start = yield* request(handler, "/mcp/demo/auth", tmp.directory, { method: "POST" }) + expect(start.status).toBe(400) + + const authenticate = yield* request(handler, "/mcp/demo/auth/authenticate", tmp.directory, { method: "POST" }) + expect(authenticate.status).toBe(400) + + const removed = yield* request(handler, "/mcp/demo/auth", tmp.directory, { method: "DELETE" }) + expect(removed.status).toBe(200) + expect(yield* json(removed)).toEqual({ success: true }) + }), + { + config: { + mcp: { + demo: { + type: "local", + command: ["echo", "demo"], + enabled: false, + }, + }, + }, + }, + ) + + it.instance( + "returns unsupported OAuth error responses", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const dir = tmp.directory const headers = { "x-opencode-directory": dir } yield* Effect.forEach(["/mcp/demo/auth", "/mcp/demo/auth/authenticate"], (path) => @@ -177,6 +178,18 @@ describe("mcp HttpApi", () => { }), ) }), - ), + { + config: { + formatter: false, + lsp: false, + mcp: { + demo: { + type: "local", + command: ["echo", "demo"], + enabled: false, + }, + }, + }, + }, ) }) diff --git a/packages/opencode/test/server/httpapi-provider.test.ts b/packages/opencode/test/server/httpapi-provider.test.ts index 68db6663d2..490b947fd9 100644 --- a/packages/opencode/test/server/httpapi-provider.test.ts +++ b/packages/opencode/test/server/httpapi-provider.test.ts @@ -1,18 +1,24 @@ -import { afterEach, describe, expect } from "bun:test" -import { Effect, FileSystem, Layer, Path } from "effect" -import { NodeFileSystem, NodePath } from "@effect/platform-node" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" -import { InstanceRuntime } from "../../src/project/instance-runtime" +import { describe, expect } from "bun:test" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { Effect, Layer } from "effect" +import path from "path" import { Server } from "../../src/server/server" import * as Log from "@opencode-ai/core/util/log" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, provideInstance } from "../fixture/fixture" +import { TestInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" void Log.init({ print: false }) -const it = testEffect(Layer.mergeAll(NodeFileSystem.layer, NodePath.layer)) +const testStateLayer = Layer.effectDiscard( + Effect.acquireRelease( + Effect.promise(() => resetDatabase()), + () => Effect.promise(() => resetDatabase()), + ), +) + +const it = testEffect(Layer.mergeAll(testStateLayer, AppFileSystem.defaultLayer)) +const projectOptions = { config: { formatter: false, lsp: false } } const providerID = "test-oauth-parity" const oauthURL = "https://example.com/oauth" const oauthInstructions = "Finish OAuth" @@ -74,12 +80,33 @@ function requestAuthorize(input: { providerID: string method: number headers: HeadersInit + inputs?: Record }) { return Effect.promise(async () => { const response = await input.app.request(`/provider/${input.providerID}/oauth/authorize`, { method: "POST", headers: input.headers, - body: JSON.stringify({ method: input.method }), + body: JSON.stringify({ method: input.method, ...(input.inputs ? { inputs: input.inputs } : {}) }), + }) + return { + status: response.status, + body: await response.text(), + } + }) +} + +function requestCallback(input: { + app: ReturnType + providerID: string + method: number + headers: HeadersInit + code?: string +}) { + return Effect.promise(async () => { + const response = await input.app.request(`/provider/${input.providerID}/oauth/callback`, { + method: "POST", + headers: input.headers, + body: JSON.stringify({ method: input.method, ...(input.code ? { code: input.code } : {}) }), }) return { status: response.status, @@ -90,11 +117,9 @@ function requestAuthorize(input: { function writeProviderAuthPlugin(dir: string) { return Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path + const fs = yield* AppFileSystem.Service - yield* fs.makeDirectory(path.join(dir, ".opencode", "plugin"), { recursive: true }) - yield* fs.writeFileString( + yield* fs.writeWithDirs( path.join(dir, ".opencode", "plugin", "provider-oauth-parity.ts"), [ "export default {", @@ -124,13 +149,52 @@ function writeProviderAuthPlugin(dir: string) { }) } +function writeProviderAuthValidationPlugin(dir: string) { + return Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + + yield* fs.writeWithDirs( + path.join(dir, ".opencode", "plugin", "provider-oauth-validation.ts"), + [ + "export default {", + ' id: "test.provider-oauth-validation",', + " server: async () => ({", + " auth: {", + ' provider: "test-oauth-validation",', + " methods: [", + " {", + ' type: "oauth",', + ' label: "OAuth",', + " prompts: [", + " {", + ' type: "text",', + ' key: "token",', + ' message: "Token",', + " validate: (value) => value === 'ok' ? undefined : 'Token must be ok',", + " },", + " ],", + " authorize: async () => ({", + ` url: "${oauthURL}",`, + ' method: "code",', + ` instructions: "${oauthInstructions}",`, + " callback: async () => ({ type: 'success', key: 'token' }),", + " }),", + " },", + " ],", + " },", + " }),", + "}", + "", + ].join("\n"), + ) + }) +} + function writeFunctionOptionsPlugin(dir: string) { return Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path + const fs = yield* AppFileSystem.Service - yield* fs.makeDirectory(path.join(dir, ".opencode", "plugin"), { recursive: true }) - yield* fs.writeFileString( + yield* fs.writeWithDirs( path.join(dir, ".opencode", "plugin", "provider-function-options.ts"), [ "export default {", @@ -159,11 +223,9 @@ function writeFunctionOptionsPlugin(dir: string) { function writeProviderModelsMutationPlugin(dir: string) { return Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path + const fs = yield* AppFileSystem.Service - yield* fs.makeDirectory(path.join(dir, ".opencode", "plugin"), { recursive: true }) - yield* fs.writeFileString( + yield* fs.writeWithDirs( path.join(dir, ".opencode", "plugin", "provider-models-mutation.ts"), [ "export default {", @@ -191,91 +253,114 @@ function writeProviderModelsMutationPlugin(dir: string) { }) } -function withProviderProject(self: (dir: string) => Effect.Effect) { - return Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - const dir = yield* fs.makeTempDirectoryScoped({ prefix: "opencode-test-" }) - - yield* fs.writeFileString( - path.join(dir, "opencode.json"), - JSON.stringify({ $schema: "https://opencode.ai/config.json", formatter: false, lsp: false }), - ) - yield* writeProviderAuthPlugin(dir) - yield* Effect.addFinalizer(() => - Effect.promise(() => - WithInstance.provide({ directory: dir, fn: () => InstanceRuntime.disposeInstance(Instance.current) }), - ).pipe(Effect.ignore), - ) - - return yield* self(dir).pipe(provideInstance(dir)) - }) +function setEnvScoped(key: string, value: string) { + return Effect.acquireRelease( + Effect.sync(() => { + const previous = process.env[key] + process.env[key] = value + return previous + }), + (previous) => + Effect.sync(() => { + if (previous === undefined) delete process.env[key] + else process.env[key] = previous + }), + ) } -afterEach(async () => { - await disposeAllInstances() - await resetDatabase() -}) - describe("provider HttpApi", () => { - it.live( + it.instance( "serves OAuth authorize response shapes", - withProviderProject((dir) => - Effect.gen(function* () { - const headers = { "x-opencode-directory": dir, "content-type": "application/json" } - const server = app() + Effect.gen(function* () { + const instance = yield* TestInstance + yield* writeProviderAuthPlugin(instance.directory) + const headers = { "x-opencode-directory": instance.directory, "content-type": "application/json" } + const server = app() - const api = yield* requestAuthorize({ - app: server, - providerID, - method: 0, - headers, - }) - // method 0 (api-key style) — authorize() resolves with no further - // redirect; #26474 changed the wire format to JSON `null` so clients - // can `.json()` parse uniformly instead of getting an empty body - // that throws. - expect(api).toEqual({ status: 200, body: "null" }) + const api = yield* requestAuthorize({ + app: server, + providerID, + method: 0, + headers, + }) + // method 0 (api-key style) — authorize() resolves with no further + // redirect; #26474 changed the wire format to JSON `null` so clients + // can `.json()` parse uniformly instead of getting an empty body + // that throws. + expect(api).toEqual({ status: 200, body: "null" }) - const oauth = yield* requestAuthorize({ - app: server, - providerID, - method: 1, - headers, - }) - expect(JSON.parse(oauth.body)).toEqual({ - url: oauthURL, - method: "code", - instructions: oauthInstructions, - }) - }), - ), + const oauth = yield* requestAuthorize({ + app: server, + providerID, + method: 1, + headers, + }) + expect(JSON.parse(oauth.body)).toEqual({ + url: oauthURL, + method: "code", + instructions: oauthInstructions, + }) + }), + projectOptions, + 30000, ) - it.live("serves provider lists when auth loaders add runtime fetch options", () => + it.instance( + "returns declared provider auth validation errors", Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - const dir = yield* fs.makeTempDirectoryScoped({ prefix: "opencode-test-" }) - const previous = process.env.OPENCODE_AUTH_CONTENT - - yield* fs.writeFileString( - path.join(dir, "opencode.json"), - JSON.stringify({ $schema: "https://opencode.ai/config.json", formatter: false, lsp: false }), - ) - yield* writeFunctionOptionsPlugin(dir) - yield* Effect.sync(() => { - process.env.OPENCODE_AUTH_CONTENT = JSON.stringify({ - google: { type: "oauth", refresh: "dummy", access: "dummy", expires: 9999999999999 }, - }) + const instance = yield* TestInstance + yield* writeProviderAuthValidationPlugin(instance.directory) + const response = yield* requestAuthorize({ + app: app(), + providerID: "test-oauth-validation", + method: 0, + inputs: { token: "nope" }, + headers: { "x-opencode-directory": instance.directory, "content-type": "application/json" }, }) - yield* Effect.addFinalizer(() => - Effect.sync(() => { - if (previous === undefined) delete process.env.OPENCODE_AUTH_CONTENT - if (previous !== undefined) process.env.OPENCODE_AUTH_CONTENT = previous + + expect(response.status).toBe(400) + expect(JSON.parse(response.body)).toEqual({ + name: "ProviderAuthValidationFailed", + data: { field: "token", message: "Token must be ok" }, + }) + }), + projectOptions, + 30000, + ) + + it.instance( + "returns declared provider auth callback errors", + Effect.gen(function* () { + const instance = yield* TestInstance + const response = yield* requestCallback({ + app: app(), + providerID, + method: 0, + headers: { "x-opencode-directory": instance.directory, "content-type": "application/json" }, + }) + + expect(response.status).toBe(400) + expect(JSON.parse(response.body)).toEqual({ + name: "ProviderAuthOauthMissing", + data: { providerID }, + }) + }), + projectOptions, + 30000, + ) + + it.instance( + "serves provider lists when auth loaders add runtime fetch options", + Effect.gen(function* () { + const instance = yield* TestInstance + yield* writeFunctionOptionsPlugin(instance.directory) + yield* setEnvScoped( + "OPENCODE_AUTH_CONTENT", + JSON.stringify({ + google: { type: "oauth", refresh: "dummy", access: "dummy", expires: 9999999999999 }, }), ) - const headers = { "x-opencode-directory": dir } + const headers = { "x-opencode-directory": instance.directory } const providerResponse = yield* Effect.promise(() => Promise.resolve(app().request("/provider", { headers }))) const configResponse = yield* Effect.promise(() => Promise.resolve(app().request("/config/providers", { headers })), @@ -291,21 +376,16 @@ describe("provider HttpApi", () => { expect(hasNonZeroModelCost(providerBody, "all", "google")).toBe(true) expect(hasNonZeroModelCost(configBody, "providers", "google")).toBe(true) }), + projectOptions, ) - it.live("keeps provider.models hook input mutations out of provider state", () => + it.instance( + "keeps provider.models hook input mutations out of provider state", Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem - const path = yield* Path.Path - const dir = yield* fs.makeTempDirectoryScoped({ prefix: "opencode-test-" }) + const instance = yield* TestInstance + yield* writeProviderModelsMutationPlugin(instance.directory) - yield* fs.writeFileString( - path.join(dir, "opencode.json"), - JSON.stringify({ $schema: "https://opencode.ai/config.json", formatter: false, lsp: false }), - ) - yield* writeProviderModelsMutationPlugin(dir) - - const headers = { "x-opencode-directory": dir } + const headers = { "x-opencode-directory": instance.directory } const providerResponse = yield* Effect.promise(() => Promise.resolve(app().request("/provider", { headers }))) const configResponse = yield* Effect.promise(() => Promise.resolve(app().request("/config/providers", { headers })), @@ -320,5 +400,6 @@ describe("provider HttpApi", () => { expect(hasProviderMutationMarker(configBody, "providers", "google")).toBe(false) expect(hasNonZeroModelCost(providerBody, "all", "google")).toBe(true) }), + projectOptions, ) }) diff --git a/packages/opencode/test/server/httpapi-pty-websocket.test.ts b/packages/opencode/test/server/httpapi-pty-websocket.test.ts index 81ee952d96..19d97ef09c 100644 --- a/packages/opencode/test/server/httpapi-pty-websocket.test.ts +++ b/packages/opencode/test/server/httpapi-pty-websocket.test.ts @@ -1,16 +1,19 @@ -import { describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import { Effect } from "effect" import { handlePtyInput } from "../../src/pty/input" +import { it } from "../lib/effect" describe("pty HttpApi websocket input", () => { - test("does not forward invalid binary frames to the PTY handler", async () => { - const messages: Array = [] - const handler = { onMessage: (message: string | ArrayBuffer) => messages.push(message) } + it.effect("does not forward invalid binary frames to the PTY handler", () => + Effect.gen(function* () { + const messages: Array = [] + const handler = { onMessage: (message: string | ArrayBuffer) => messages.push(message) } - await Effect.runPromise(handlePtyInput(handler, "ready")) - await Effect.runPromise(handlePtyInput(handler, new Uint8Array([0xff, 0xfe, 0xfd]))) - await Effect.runPromise(handlePtyInput(handler, new TextEncoder().encode("hello"))) + yield* handlePtyInput(handler, "ready") + yield* handlePtyInput(handler, new Uint8Array([0xff, 0xfe, 0xfd])) + yield* handlePtyInput(handler, new TextEncoder().encode("hello")) - expect(messages).toEqual(["ready", "hello"]) - }) + expect(messages).toEqual(["ready", "hello"]) + }), + ) }) diff --git a/packages/opencode/test/server/httpapi-schema-error-body.test.ts b/packages/opencode/test/server/httpapi-schema-error-body.test.ts index fe6a1caad0..48ed7b6bfb 100644 --- a/packages/opencode/test/server/httpapi-schema-error-body.test.ts +++ b/packages/opencode/test/server/httpapi-schema-error-body.test.ts @@ -3,7 +3,6 @@ import { Effect } from "effect" import { eq } from "drizzle-orm" import * as Database from "@/storage/db" import { ModelID, ProviderID } from "../../src/provider/schema" -import { WithInstance } from "../../src/project/with-instance" import { Server } from "../../src/server/server" import { Session } from "@/session/session" import { SessionPaths } from "../../src/server/routes/instance/httpapi/groups/session" @@ -11,80 +10,68 @@ import { SyncPaths } from "../../src/server/routes/instance/httpapi/groups/sync" import { MessageID, PartID } from "../../src/session/schema" import { PartTable } from "@/session/session.sql" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { it } from "../lib/effect" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" + +const it = testEffect(Session.defaultLayer) afterEach(async () => { await disposeAllInstances() await resetDatabase() }) -const withTmp = ( - options: Parameters[0], - fn: (tmp: Awaited>) => Effect.Effect, -) => - Effect.acquireRelease( - Effect.promise(() => tmpdir(options)), - (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), - ).pipe(Effect.flatMap(fn)) - -async function seedCorruptStepFinishPart(directory: string) { - return WithInstance.provide({ - directory, - fn: () => - Effect.runPromise( - Effect.gen(function* () { - const session = yield* Session.Service - const info = yield* session.create({}) - const message = yield* session.updateMessage({ - id: MessageID.ascending(), - role: "user", - sessionID: info.id, - agent: "build", - model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") }, - time: { created: Date.now() }, - }) - const partID = PartID.ascending() - yield* session.updatePart({ - id: partID, - sessionID: info.id, - messageID: message.id, +const seedCorruptStepFinishPart = Effect.gen(function* () { + const session = yield* Session.Service + const info = yield* session.create({}) + const message = yield* session.updateMessage({ + id: MessageID.ascending(), + role: "user", + sessionID: info.id, + agent: "build", + model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") }, + time: { created: Date.now() }, + }) + const partID = PartID.ascending() + yield* session.updatePart({ + id: partID, + sessionID: info.id, + messageID: message.id, + type: "step-finish", + reason: "stop", + cost: 0, + tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, + }) + // Schema.Finite still rejects NaN at encode: exact mirror of the corrupt row + // that broke the user's session in the OMO/Windows bug. + yield* Effect.sync(() => + Database.use((db) => + db + .update(PartTable) + .set({ + data: { type: "step-finish", reason: "stop", cost: 0, - tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, - }) - // Schema.Finite still rejects NaN at encode — exact mirror of the - // corrupt row that broke the user's session in the OMO/Windows bug. - Database.use((db) => - db - .update(PartTable) - .set({ - data: { - type: "step-finish", - reason: "stop", - cost: 0, - tokens: { input: 0, output: NaN, reasoning: 0, cache: { read: 0, write: 0 } }, - } as never, // drizzle's .set() can't narrow the discriminated union - }) - .where(eq(PartTable.id, partID)) - .run(), - ) - return info.id - }).pipe(Effect.provide(Session.defaultLayer)), - ), - }) -} + tokens: { input: 0, output: NaN, reasoning: 0, cache: { read: 0, write: 0 } }, + } as never, // drizzle's .set() can't narrow the discriminated union + }) + .where(eq(PartTable.id, partID)) + .run(), + ), + ) + return info.id +}) describe("schema-rejection wire shape", () => { - it.live( + it.instance( "Payload schema rejection returns NamedError-shaped JSON, not empty", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { + const test = yield* TestInstance const res = yield* Effect.promise(async () => Server.Default().app.request(SyncPaths.history, { method: "POST", - headers: { "x-opencode-directory": tmp.path, "content-type": "application/json" }, + headers: { "x-opencode-directory": test.directory, "content-type": "application/json" }, body: JSON.stringify({ aggregate: -1 }), }), ) @@ -99,36 +86,38 @@ describe("schema-rejection wire shape", () => { expect(parsed.data.message).toEqual(expect.any(String)) expect(parsed.data.message.length).toBeGreaterThan(0) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "Query schema rejection returns NamedError-shaped JSON", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { + const test = yield* TestInstance // /find/file?limit=999999 violates the limit constraint check. - const url = `/find/file?query=foo&limit=999999&directory=${encodeURIComponent(tmp.path)}` + const url = `/find/file?query=foo&limit=999999&directory=${encodeURIComponent(test.directory)}` const res = yield* Effect.promise(async () => Server.Default().app.request(url)) const body = yield* Effect.promise(async () => res.text()) expect(res.status).toBe(400) const parsed = JSON.parse(body) expect(parsed).toMatchObject({ name: "BadRequest", data: { kind: "Query" } }) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "rejected request body never echoes back unbounded — message is capped", // Defense against DoS-amplification + secret-echo: Effect's Issue formatter // dumps the rejected `actual` verbatim. A multi-MB invalid array would // become a multi-MB 400 response and log line. Cap kicks in around 1KB. - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { + const test = yield* TestInstance const huge = "X".repeat(50_000) const res = yield* Effect.promise(async () => Server.Default().app.request(SyncPaths.history, { method: "POST", - headers: { "x-opencode-directory": tmp.path, "content-type": "application/json" }, + headers: { "x-opencode-directory": test.directory, "content-type": "application/json" }, body: JSON.stringify({ aggregate: huge }), }), ) @@ -139,15 +128,16 @@ describe("schema-rejection wire shape", () => { const parsed = JSON.parse(body) expect(parsed.data.message).not.toContain(huge) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "response-encode failure: corrupted stored row returns NamedError-shaped JSON with field path", - withTmp({ config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { - const sessionID = yield* Effect.promise(() => seedCorruptStepFinishPart(tmp.path)) - const url = `${SessionPaths.messages.replace(":sessionID", sessionID)}?limit=80&directory=${encodeURIComponent(tmp.path)}` + const test = yield* TestInstance + const sessionID = yield* seedCorruptStepFinishPart + const url = `${SessionPaths.messages.replace(":sessionID", sessionID)}?limit=80&directory=${encodeURIComponent(test.directory)}` const res = yield* Effect.promise(async () => Server.Default().app.request(url)) const body = yield* Effect.promise(async () => res.text()) expect(res.status).toBe(400) @@ -157,6 +147,6 @@ describe("schema-rejection wire shape", () => { // Field path in data.message — what made this PR worth shipping. expect(parsed.data.message).toMatch(/output/) }), - ), + { config: { formatter: false, lsp: false } }, ) }) diff --git a/packages/opencode/test/server/httpapi-sdk.test.ts b/packages/opencode/test/server/httpapi-sdk.test.ts index 0201f98c25..a76877a0bf 100644 --- a/packages/opencode/test/server/httpapi-sdk.test.ts +++ b/packages/opencode/test/server/httpapi-sdk.test.ts @@ -2,11 +2,14 @@ import { afterEach, describe, expect } from "bun:test" import { ConfigProvider, Effect, Layer } from "effect" import type * as Scope from "effect/Scope" import { HttpRouter } from "effect/unstable/http" +import { ChildProcessSpawner } from "effect/unstable/process" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { Flag } from "@opencode-ai/core/flag/flag" import { createOpencodeClient } from "@opencode-ai/sdk/v2" import { validateSession } from "../../src/cli/cmd/tui/validate-session" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" +import { InstanceBootstrap } from "../../src/project/bootstrap-service" +import { InstanceStore } from "../../src/project/instance-store" import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" import { Server } from "../../src/server/server" import { MessageID, PartID, SessionID } from "../../src/session/schema" @@ -18,8 +21,17 @@ import { errorMessage } from "../../src/util/error" import { TestLLMServer } from "../lib/llm-server" import path from "path" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { it } from "../lib/effect" +import { disposeAllInstances, TestInstance, tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" + +const noopBootstrap = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void })) +const it = testEffect( + Layer.mergeAll( + AppFileSystem.defaultLayer, + CrossSpawnSpawner.defaultLayer, + InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrap)), + ), +) const original = { OPENCODE_SERVER_PASSWORD: Flag.OPENCODE_SERVER_PASSWORD, @@ -32,6 +44,8 @@ type SdkResult = { response: Response; data?: unknown; error?: unknown } type Captured = { status: number; data?: unknown; error?: unknown } type ProjectFixture = { sdk: Sdk; directory: string } type LlmProjectFixture = ProjectFixture & { llm: TestLLMServer["Service"] } +type TestServices = AppFileSystem.Service | ChildProcessSpawner.ChildProcessSpawner | InstanceStore.Service +type TestScope = Scope.Scope | TestServices function app(serverPath: ServerPath, input?: { password?: string; username?: string }) { Flag.OPENCODE_SERVER_PASSWORD = input?.password @@ -149,12 +163,27 @@ function expectStatus(request: () => Promise<{ response: Response }>, status: nu ) } -function firstEvent(open: () => Promise<{ stream: AsyncIterator }>) { - return Effect.acquireRelease(call(open), (events) => - call(async () => void (await events.stream.return?.(undefined))).pipe(Effect.ignore), +function firstEvent(open: (signal: AbortSignal) => Promise<{ stream: AsyncIterator }>) { + return Effect.acquireRelease( + Effect.sync(() => new AbortController()), + (controller) => Effect.sync(() => controller.abort()), ).pipe( - Effect.flatMap((events) => call(() => events.stream.next())), - Effect.map((result) => result.value), + Effect.flatMap((controller) => + Effect.acquireRelease( + call(() => open(controller.signal)), + (events) => call(async () => void (await events.stream.return?.(undefined))).pipe(Effect.ignore), + ).pipe( + Effect.flatMap((events) => + call(() => events.stream.next()).pipe( + Effect.timeoutOrElse({ + duration: "1 second", + orElse: () => Effect.fail(new Error("timed out waiting for SDK event")), + }), + ), + ), + Effect.map((result) => result.value), + ), + ), ) } @@ -188,11 +217,32 @@ function resetState() { }) } -function httpapi(name: string, effect: Effect.Effect) { +function httpapi(name: string, effect: Effect.Effect) { it.live(name, effect) } -function serverPathParity(name: string, scenario: (serverPath: ServerPath) => Effect.Effect) { +function httpapiInstance( + name: string, + options: { + serverPath: ServerPath + git?: boolean + config?: Partial + setup?: (dir: string) => Effect.Effect + }, + run: (input: ProjectFixture) => Effect.Effect, +) { + it.instance( + name, + Effect.gen(function* () { + const instance = yield* TestInstance + yield* options.setup?.(instance.directory) ?? Effect.void + return yield* run({ sdk: client(options.serverPath, instance.directory), directory: instance.directory }) + }), + { git: options.git ?? true, config: { formatter: false, lsp: false, ...options.config } }, + ) +} + +function serverPathParity(name: string, scenario: (serverPath: ServerPath) => Effect.Effect) { it.live( name, Effect.gen(function* () { @@ -204,35 +254,43 @@ function serverPathParity(name: string, scenario: (serverPath: ServerPath) ) } -function withProject( +function withProject( serverPath: ServerPath, - options: { git?: boolean; config?: Partial; setup?: (dir: string) => Effect.Effect }, - run: (input: ProjectFixture) => Effect.Effect, + options: { + git?: boolean + config?: Partial + setup?: (dir: string) => Effect.Effect + }, + run: (input: ProjectFixture) => Effect.Effect, ) { - return Effect.acquireRelease( - call(() => tmpdir({ git: options.git ?? true, config: { formatter: false, lsp: false, ...options.config } })), - (tmp) => call(() => tmp[Symbol.asyncDispose]()).pipe(Effect.ignore), - ).pipe( - Effect.tap((tmp) => options.setup?.(tmp.path) ?? Effect.void), - Effect.flatMap((tmp) => run({ sdk: client(serverPath, tmp.path), directory: tmp.path })), - ) + return Effect.gen(function* () { + const directory = yield* tmpdirScoped({ + git: options.git ?? true, + config: { formatter: false, lsp: false, ...options.config }, + }) + yield* options.setup?.(directory) ?? Effect.void + return yield* run({ sdk: client(serverPath, directory), directory }) + }) } -function withStandardProject(serverPath: ServerPath, run: (input: ProjectFixture) => Effect.Effect) { +function withStandardProject( + serverPath: ServerPath, + run: (input: ProjectFixture) => Effect.Effect, +) { return withProject(serverPath, { setup: writeStandardFiles }, run) } -function withFakeLlm(serverPath: ServerPath, run: (input: LlmProjectFixture) => Effect.Effect) { +function withFakeLlm(serverPath: ServerPath, run: (input: LlmProjectFixture) => Effect.Effect) { return Effect.gen(function* () { const llm = yield* TestLLMServer return yield* withProject(serverPath, { config: providerConfig(llm.url) }, (input) => run({ ...input, llm })) }).pipe(Effect.provide(TestLLMServer.layer)) } -function withFakeLlmProject( +function withFakeLlmProject( serverPath: ServerPath, - options: { setup?: (dir: string) => Effect.Effect }, - run: (input: LlmProjectFixture) => Effect.Effect, + options: { setup?: (dir: string) => Effect.Effect }, + run: (input: LlmProjectFixture) => Effect.Effect, ) { return Effect.gen(function* () { const llm = yield* TestLLMServer @@ -248,15 +306,17 @@ function withFakeLlmProject( } function writeStandardFiles(dir: string) { - return Effect.all([ - call(() => Bun.write(path.join(dir, "hello.txt"), "hello")), - call(() => Bun.write(path.join(dir, "needle.ts"), "export const needle = 'sdk-parity'\n")), - ]).pipe(Effect.asVoid) + return AppFileSystem.Service.use((fs) => + Effect.all([ + fs.writeWithDirs(path.join(dir, "hello.txt"), "hello"), + fs.writeWithDirs(path.join(dir, "needle.ts"), "export const needle = 'sdk-parity'\n"), + ]).pipe(Effect.asVoid), + ) } function writeProjectSkill(dir: string) { - return call(() => - Bun.write( + return AppFileSystem.Service.use((fs) => + fs.writeWithDirs( path.join(dir, ".opencode", "skills", "project-rest-skill", "SKILL.md"), `--- name: project-rest-skill @@ -266,40 +326,36 @@ description: A project skill visible to REST API prompts. # Project REST Skill `, ), - ).pipe(Effect.asVoid) + ) } function seedMessage(directory: string, sessionID: string) { const id = SessionID.make(sessionID) - return call( - async () => - await WithInstance.provide({ - directory, - fn: () => - Effect.runPromise( - SessionNs.Service.use((svc) => - Effect.gen(function* () { - const message = yield* svc.updateMessage({ - id: MessageID.ascending(), - sessionID: id, - role: "user", - time: { created: Date.now() }, - agent: "test", - model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") }, - tools: {}, - } satisfies MessageV2.User) - const part = yield* svc.updatePart({ - id: PartID.ascending(), - sessionID: id, - messageID: message.id, - type: "text", - text: "seeded message", - }) - return { message, part } - }), - ).pipe(Effect.provide(SessionNs.defaultLayer)), - ), - }), + return InstanceStore.Service.use((store) => + store.provide( + { directory }, + SessionNs.Service.use((svc) => + Effect.gen(function* () { + const message = yield* svc.updateMessage({ + id: MessageID.ascending(), + sessionID: id, + role: "user", + time: { created: Date.now() }, + agent: "test", + model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") }, + tools: {}, + } satisfies MessageV2.User) + const part = yield* svc.updatePart({ + id: PartID.ascending(), + sessionID: id, + messageID: message.id, + type: "text", + text: "seeded message", + }) + return { message, part } + }), + ).pipe(Effect.provide(SessionNs.defaultLayer)), + ), ) } @@ -320,7 +376,7 @@ describe("HttpApi SDK", () => { expect(health.response.status).toBe(200) expect(health.data).toMatchObject({ healthy: true }) - expect(yield* firstEvent(() => sdk.global.event({ signal: AbortSignal.timeout(1_000) }))).toMatchObject({ + expect(yield* firstEvent((signal) => sdk.global.event({ signal }))).toMatchObject({ payload: { type: "server.connected" }, }) expect(log.response.status).toBe(200) @@ -329,9 +385,10 @@ describe("HttpApi SDK", () => { }), ) - httpapi( + httpapiInstance( "uses the generated SDK for safe instance routes", - withProject("raw", { git: false, setup: writeStandardFiles }, ({ sdk }) => + { serverPath: "raw", git: false, setup: writeStandardFiles }, + ({ sdk }) => Effect.gen(function* () { const file = yield* call(() => sdk.file.read({ path: "hello.txt" })) const session = yield* call(() => sdk.session.create({ title: "sdk" })) @@ -351,7 +408,6 @@ describe("HttpApi SDK", () => { expectStatus(() => sdk.find.files({ query: "hello", limit: 10 }), 200), ]) }), - ), ) serverPathParity("matches generated SDK global and control behavior", (serverPath) => @@ -370,14 +426,14 @@ describe("HttpApi SDK", () => { ) serverPathParity("matches generated SDK global event stream", (serverPath) => - firstEvent(() => client(serverPath).global.event({ signal: AbortSignal.timeout(1_000) })).pipe( + firstEvent((signal) => client(serverPath).global.event({ signal })).pipe( Effect.map((event) => ({ type: record(record(event).payload).type })), ), ) serverPathParity("matches generated SDK instance event stream", (serverPath) => withStandardProject(serverPath, ({ sdk }) => - firstEvent(() => sdk.event.subscribe(undefined, { signal: AbortSignal.timeout(1_000) })).pipe( + firstEvent((signal) => sdk.event.subscribe(undefined, { signal })).pipe( Effect.map((event) => ({ type: record(record(event).payload).type })), ), ), @@ -431,9 +487,10 @@ describe("HttpApi SDK", () => { ), ) - httpapi( + httpapiInstance( "uses generated SDK basic auth behavior", - withStandardProject("raw", ({ directory }) => + { serverPath: "raw", setup: writeStandardFiles }, + ({ directory }) => Effect.gen(function* () { const missing = yield* capture(() => client("raw", directory, { password: "secret" }).file.read({ path: "hello.txt" }), @@ -456,7 +513,6 @@ describe("HttpApi SDK", () => { content: record(good.data).content, } }), - ), ) serverPathParity("matches generated SDK instance read routes", (serverPath) => @@ -687,7 +743,7 @@ describe("HttpApi SDK", () => { ) httpapi( - "includes project skills in REST API async prompt context", + "includes project skills in REST API prompt context", withFakeLlmProject("default", { setup: writeProjectSkill }, ({ sdk, llm }) => Effect.gen(function* () { yield* llm.text("skill context ok", { usage: { input: 11, output: 7 } }) @@ -699,18 +755,17 @@ describe("HttpApi SDK", () => { ) const sessionID = String(record(session.data).id) const prompt = yield* capture(() => - sdk.session.promptAsync({ + sdk.session.prompt({ sessionID, agent: "build", model: { providerID: "test", modelID: "test-model" }, parts: [{ type: "text", text: "hello skill context" }], }), ) - yield* llm.wait(1) const inputs = yield* llm.inputs expect(session.status).toBe(200) - expect(prompt.status).toBe(204) + expect(prompt.status).toBe(200) expect(JSON.stringify(inputs[0])).toContain("project-rest-skill") }), ), diff --git a/packages/opencode/test/server/httpapi-session.test.ts b/packages/opencode/test/server/httpapi-session.test.ts index 210863e0c9..3e5527761e 100644 --- a/packages/opencode/test/server/httpapi-session.test.ts +++ b/packages/opencode/test/server/httpapi-session.test.ts @@ -8,8 +8,8 @@ import type { WorkspaceAdapter } from "../../src/control-plane/types" import { Workspace } from "../../src/control-plane/workspace" import { PermissionID } from "../../src/permission/schema" import { ModelID, ProviderID } from "../../src/provider/schema" -import { WithInstance } from "../../src/project/with-instance" import { InstanceBootstrap } from "../../src/project/bootstrap" +import { InstanceBootstrap as InstanceBootstrapService } from "../../src/project/bootstrap-service" import { InstanceStore } from "../../src/project/instance-store" import { Project } from "../../src/project/project" import { Server } from "../../src/server/server" @@ -20,13 +20,14 @@ import { MessageV2 } from "../../src/session/message-v2" import { Database } from "@/storage/db" import { SessionMessageTable, SessionTable } from "@/session/session.sql" import { SessionMessage } from "../../src/v2/session-message" -import { Modelv2 } from "../../src/v2/model" +import { ModelV2 } from "@opencode-ai/core/model" +import { ProviderV2 } from "@opencode-ai/core/provider" import * as DateTime from "effect/DateTime" import * as Log from "@opencode-ai/core/util/log" import { eq } from "drizzle-orm" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { it } from "../lib/effect" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) @@ -35,58 +36,45 @@ const workspaceLayer = Workspace.defaultLayer.pipe( Layer.provide(InstanceStore.defaultLayer), Layer.provide(InstanceBootstrap.defaultLayer), ) +const instanceStoreLayer = InstanceStore.defaultLayer.pipe( + Layer.provide( + Layer.succeed(InstanceBootstrapService.Service, InstanceBootstrapService.Service.of({ run: Effect.void })), + ), +) +const it = testEffect(Layer.mergeAll(instanceStoreLayer, Project.defaultLayer, Session.defaultLayer, workspaceLayer)) function app() { return Server.Default().app } -function runSession(fx: Effect.Effect) { - return Effect.runPromise(fx.pipe(Effect.provide(Session.defaultLayer))) -} - function pathFor(path: string, params: Record) { return Object.entries(params).reduce((result, [key, value]) => result.replace(`:${key}`, value), path) } -function createSession(directory: string, input?: Session.CreateInput) { - return Effect.promise( - async () => - await WithInstance.provide({ - directory, - fn: () => runSession(Session.Service.use((svc) => svc.create(input))), - }), - ) +function createSession(input?: Session.CreateInput) { + return Session.Service.use((svc) => svc.create(input)) } -function createTextMessage(directory: string, sessionID: SessionIDType, text: string) { - return Effect.promise( - async () => - await WithInstance.provide({ - directory, - fn: () => - runSession( - Effect.gen(function* () { - const svc = yield* Session.Service - const info = yield* svc.updateMessage({ - id: MessageID.ascending(), - role: "user", - sessionID, - agent: "build", - model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") }, - time: { created: Date.now() }, - }) - const part = yield* svc.updatePart({ - id: PartID.ascending(), - sessionID, - messageID: info.id, - type: "text", - text, - }) - return { info, part } - }), - ), - }), - ) +function createTextMessage(sessionID: SessionIDType, text: string) { + return Effect.gen(function* () { + const svc = yield* Session.Service + const info = yield* svc.updateMessage({ + id: MessageID.ascending(), + role: "user", + sessionID, + agent: "build", + model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") }, + time: { created: Date.now() }, + }) + const part = yield* svc.updatePart({ + id: PartID.ascending(), + sessionID, + messageID: info.id, + type: "text", + text, + }) + return { info, part } + }) } const localAdapter = (directory: string): WorkspaceAdapter => ({ @@ -101,18 +89,88 @@ const localAdapter = (directory: string): WorkspaceAdapter => ({ }) const createLocalWorkspace = (input: { projectID: Project.Info["id"]; type: string; directory: string }) => - Effect.gen(function* () { - registerAdapter(input.projectID, input.type, localAdapter(input.directory)) - return yield* Workspace.Service.use((svc) => - svc.create({ - type: input.type, - branch: null, - extra: null, - projectID: input.projectID, - }), - ).pipe(Effect.provide(workspaceLayer)) + Effect.acquireRelease( + Effect.gen(function* () { + registerAdapter(input.projectID, input.type, localAdapter(input.directory)) + return yield* Workspace.Service.use((svc) => + svc.create({ + type: input.type, + branch: null, + extra: null, + projectID: input.projectID, + }), + ) + }), + (info) => Workspace.Service.use((svc) => svc.remove(info.id)).pipe(Effect.ignore), + ) + +const insertLegacyAssistantMessage = (sessionID: SessionIDType) => + Effect.sync(() => { + const message = new SessionMessage.Assistant({ + id: SessionMessage.ID.create(), + type: "assistant", + agent: "build", + model: { + id: ModelV2.ID.make("model"), + providerID: ProviderV2.ID.make("provider"), + variant: ModelV2.VariantID.make("default"), + }, + time: { created: DateTime.makeUnsafe(1) }, + content: [], + }) + Database.use((db) => + db + .insert(SessionMessageTable) + .values([ + { + id: message.id, + session_id: sessionID, + type: message.type, + time_created: 1, + data: { + time: { created: 1 }, + agent: message.agent, + model: message.model, + content: message.content, + } as NonNullable<(typeof SessionMessageTable.$inferInsert)["data"]>, + }, + ]) + .run(), + ) }) +const setLegacySummaryDiff = (sessionID: SessionIDType) => + Effect.sync(() => + Database.use((db) => + db + .update(SessionTable) + .set({ + summary_additions: 1, + summary_deletions: 0, + summary_files: 1, + summary_diffs: [{ additions: 1, deletions: 0 }], + }) + .where(eq(SessionTable.id, sessionID)) + .run(), + ), + ) + +const getWorkspaceID = (sessionID: SessionIDType) => + Effect.sync(() => + Database.use((db) => + db + .select({ workspaceID: SessionTable.workspace_id }) + .from(SessionTable) + .where(eq(SessionTable.id, sessionID)) + .get(), + ), + ) + +const clearSessionPath = (sessionID: SessionIDType) => + Effect.sync(() => + Database.use((db) => db.update(SessionTable).set({ path: null }).where(eq(SessionTable.id, sessionID)).run()), + ) + function request(path: string, init?: RequestInit) { return Effect.promise(async () => app().request(path, init)) } @@ -132,16 +190,6 @@ function requestJson(path: string, init?: RequestInit) { return request(path, init).pipe(Effect.flatMap(json)) } -function withTmp( - options: Parameters[0], - fn: (tmp: Awaited>) => Effect.Effect, -) { - return Effect.acquireRelease( - Effect.promise(() => tmpdir(options)), - (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), - ).pipe(Effect.flatMap(fn)) -} - afterEach(async () => { Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces await disposeAllInstances() @@ -149,11 +197,12 @@ afterEach(async () => { }) describe("session HttpApi", () => { - it.live( + it.instance( "returns declared not found errors for read routes", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { - const headers = { "x-opencode-directory": tmp.path } + const test = yield* TestInstance + const headers = { "x-opencode-directory": test.directory } const missingSession = SessionID.descending() const missingSessionBody = { name: "NotFoundError", @@ -164,6 +213,14 @@ describe("session HttpApi", () => { expect(get.status).toBe(404) expect(yield* responseJson(get)).toEqual(missingSessionBody) + const children = yield* request(pathFor(SessionPaths.children, { sessionID: missingSession }), { headers }) + expect(children.status).toBe(404) + expect(yield* responseJson(children)).toEqual(missingSessionBody) + + const todo = yield* request(pathFor(SessionPaths.todo, { sessionID: missingSession }), { headers }) + expect(todo.status).toBe(404) + expect(yield* responseJson(todo)).toEqual(missingSessionBody) + const messages = yield* request(pathFor(SessionPaths.messages, { sessionID: missingSession }), { headers }) expect(messages.status).toBe(404) expect(yield* responseJson(messages)).toEqual(missingSessionBody) @@ -175,7 +232,22 @@ describe("session HttpApi", () => { expect(remove.status).toBe(404) expect(yield* responseJson(remove)).toEqual(missingSessionBody) - const session = yield* createSession(tmp.path, { title: "missing message" }) + const prompt = yield* request(pathFor(SessionPaths.prompt, { sessionID: missingSession }), { + headers: { ...headers, "content-type": "application/json" }, + method: "POST", + body: JSON.stringify({ agent: "build", noReply: true, parts: [{ type: "text", text: "hello" }] }), + }) + expect(prompt.status).toBe(404) + expect(yield* responseJson(prompt)).toEqual(missingSessionBody) + + const abort = yield* request(pathFor(SessionPaths.abort, { sessionID: missingSession }), { + headers, + method: "POST", + }) + expect(abort.status).toBe(200) + expect(yield* responseJson(abort)).toBe(true) + + const session = yield* createSession({ title: "missing message" }) const missingMessage = MessageID.ascending() const message = yield* request( pathFor(SessionPaths.message, { sessionID: session.id, messageID: missingMessage }), @@ -187,18 +259,19 @@ describe("session HttpApi", () => { data: { message: `Message not found: ${missingMessage}` }, }) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "serves read routes", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { - const headers = { "x-opencode-directory": tmp.path } - const parent = yield* createSession(tmp.path, { title: "parent" }) - const child = yield* createSession(tmp.path, { title: "child", parentID: parent.id }) - const message = yield* createTextMessage(tmp.path, parent.id, "hello") - yield* createTextMessage(tmp.path, parent.id, "world") + const test = yield* TestInstance + const headers = { "x-opencode-directory": test.directory } + const parent = yield* createSession({ title: "parent" }) + const child = yield* createSession({ title: "child", parentID: parent.id }) + const message = yield* createTextMessage(parent.id, "hello") + yield* createTextMessage(parent.id, "world") const listed = yield* requestJson(`${SessionPaths.list}?roots=true`, { headers }) expect(listed.map((item) => item.id)).toContain(parent.id) @@ -250,88 +323,40 @@ describe("session HttpApi", () => { ), ).toMatchObject({ info: { id: message.info.id } }) - yield* Effect.promise(() => - WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const message = new SessionMessage.Assistant({ - id: SessionMessage.ID.create(), - type: "assistant", - agent: "build", - model: { - id: Modelv2.ID.make("model"), - providerID: Modelv2.ProviderID.make("provider"), - variant: Modelv2.VariantID.make("default"), - }, - time: { created: DateTime.makeUnsafe(1) }, - content: [], - }) - Database.use((db) => - db - .insert(SessionMessageTable) - .values([ - { - id: message.id, - session_id: parent.id, - type: message.type, - time_created: 1, - data: { - time: { created: 1 }, - agent: message.agent, - model: message.model, - content: message.content, - } as NonNullable<(typeof SessionMessageTable.$inferInsert)["data"]>, - }, - ]) - .run(), - ) - }, - }), - ) + yield* insertLegacyAssistantMessage(parent.id) expect( (yield* requestJson<{ items: SessionMessage.Message[] }>(`/api/session/${parent.id}/message`, { headers })) .items, ).toMatchObject([{ type: "assistant" }]) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "serves sessions with migrated summary diffs missing file details", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { - const session = yield* createSession(tmp.path, { title: "legacy diff" }) - yield* Effect.sync(() => - Database.use((db) => - db - .update(SessionTable) - .set({ - summary_additions: 1, - summary_deletions: 0, - summary_files: 1, - summary_diffs: [{ additions: 1, deletions: 0 }], - }) - .where(eq(SessionTable.id, session.id)) - .run(), - ), - ) + const test = yield* TestInstance + const session = yield* createSession({ title: "legacy diff" }) + yield* setLegacySummaryDiff(session.id) const response = yield* request(pathFor(SessionPaths.get, { sessionID: session.id }), { - headers: { "x-opencode-directory": tmp.path }, + headers: { "x-opencode-directory": test.directory }, }) expect(response.status).toBe(200) expect((yield* json(response)).summary?.diffs).toEqual([{ additions: 1, deletions: 0 }]) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "serves lifecycle mutation routes", - withTmp({ git: true, config: { formatter: false, lsp: false, share: "disabled" } }, (tmp) => + () => Effect.gen(function* () { - const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" } + const test = yield* TestInstance + const headers = { "x-opencode-directory": test.directory, "content-type": "application/json" } const createdEmpty = yield* requestJson(SessionPaths.create, { method: "POST", @@ -373,56 +398,48 @@ describe("session HttpApi", () => { }), ).toBe(true) }), - ), + { git: true, config: { formatter: false, lsp: false, share: "disabled" } }, ) - it.live( + it.instance( "persists selected workspace id when creating a session", - withTmp({ git: true, config: { formatter: false, lsp: false, share: "disabled" } }, (tmp) => + () => Effect.gen(function* () { + const test = yield* TestInstance Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true - const project = yield* Project.use.fromDirectory(tmp.path).pipe(Effect.provide(Project.defaultLayer)) + const project = yield* Project.use.fromDirectory(test.directory) const workspace = yield* createLocalWorkspace({ projectID: project.project.id, type: "session-create-workspace", - directory: path.join(tmp.path, ".workspace-local"), + directory: path.join(test.directory, ".workspace-local"), }) const created = yield* requestJson(`${SessionPaths.create}?workspace=${workspace.id}`, { method: "POST", - headers: { "x-opencode-directory": tmp.path, "content-type": "application/json" }, + headers: { "x-opencode-directory": test.directory, "content-type": "application/json" }, body: JSON.stringify({ title: "workspace session" }), }) const messages = yield* request( `${pathFor(SessionPaths.messages, { sessionID: created.id })}?workspace=${workspace.id}`, { - headers: { "x-opencode-directory": tmp.path }, + headers: { "x-opencode-directory": test.directory }, }, ) expect(created).toMatchObject({ id: created.id, workspaceID: workspace.id }) expect(messages.status).toBe(200) - expect( - yield* Effect.sync(() => - Database.use((db) => - db - .select({ workspaceID: SessionTable.workspace_id }) - .from(SessionTable) - .where(eq(SessionTable.id, created.id)) - .get(), - ), - ), - ).toEqual({ workspaceID: workspace.id }) + expect(yield* getWorkspaceID(created.id)).toEqual({ workspaceID: workspace.id }) }), - ), + { git: true, config: { formatter: false, lsp: false, share: "disabled" } }, ) - it.live( + it.instance( "validates archived timestamp values", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { - const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" } - const session = yield* createSession(tmp.path, { title: "archived" }) + const test = yield* TestInstance + const headers = { "x-opencode-directory": test.directory, "content-type": "application/json" } + const session = yield* createSession({ title: "archived" }) const body = JSON.stringify({ time: { archived: -1 } }) const response = yield* request(pathFor(SessionPaths.update, { sessionID: session.id }), { @@ -433,30 +450,35 @@ describe("session HttpApi", () => { expect(response.status).toBe(200) expect((yield* json(response)).time.archived).toBe(-1) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "uses project-scoped path and directory precedence", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { - const currentDir = path.join(tmp.path, "packages", "opencode", "src") + const test = yield* TestInstance + const currentDir = path.join(test.directory, "packages", "opencode", "src") yield* Effect.promise(() => mkdir(currentDir, { recursive: true })) - const pathSession = yield* createSession(currentDir) - const pathlessSession = yield* createSession(currentDir) - yield* Effect.sync(() => - Database.use((db) => - db.update(SessionTable).set({ path: null }).where(eq(SessionTable.id, pathlessSession.id)).run(), - ), + const store = yield* InstanceStore.Service + const { pathSession, pathlessSession } = yield* store.provide( + { directory: currentDir }, + Effect.gen(function* () { + return { + pathSession: yield* createSession(), + pathlessSession: yield* createSession(), + } + }).pipe(Effect.provideService(TestInstance, { directory: currentDir }), Effect.provide(Session.defaultLayer)), ) + yield* clearSessionPath(pathlessSession.id) const query = new URLSearchParams({ scope: "project", path: "packages/opencode/src", directory: currentDir, }) - const headers = { "x-opencode-directory": tmp.path } + const headers = { "x-opencode-directory": test.directory } const sessions = (yield* json( yield* request(`${SessionPaths.list}?${query}`, { headers }), )).map((item) => item.id) @@ -464,17 +486,18 @@ describe("session HttpApi", () => { expect(sessions).toContain(pathSession.id) expect(sessions).not.toContain(pathlessSession.id) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "serves paginated message link headers", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { - const headers = { "x-opencode-directory": tmp.path } - const session = yield* createSession(tmp.path, { title: "messages" }) - yield* createTextMessage(tmp.path, session.id, "first") - yield* createTextMessage(tmp.path, session.id, "second") + const test = yield* TestInstance + const headers = { "x-opencode-directory": test.directory } + const session = yield* createSession({ title: "messages" }) + yield* createTextMessage(session.id, "first") + yield* createTextMessage(session.id, "second") const route = `${pathFor(SessionPaths.messages, { sessionID: session.id })}?limit=1` const response = yield* request(route, { headers }) @@ -483,17 +506,18 @@ describe("session HttpApi", () => { expect(response.headers.get("link")).toContain("limit=1") expect(response.headers.get("access-control-expose-headers")?.toLowerCase()).toContain("x-next-cursor") }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( + it.instance( "serves message mutation routes", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + () => Effect.gen(function* () { - const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" } - const session = yield* createSession(tmp.path, { title: "messages" }) - const first = yield* createTextMessage(tmp.path, session.id, "first") - const second = yield* createTextMessage(tmp.path, session.id, "second") + const test = yield* TestInstance + const headers = { "x-opencode-directory": test.directory, "content-type": "application/json" } + const session = yield* createSession({ title: "messages" }) + const first = yield* createTextMessage(session.id, "first") + const second = yield* createTextMessage(session.id, "second") const updated = yield* requestJson( pathFor(SessionPaths.updatePart, { @@ -527,15 +551,42 @@ describe("session HttpApi", () => { ), ).toBe(true) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) - it.live( - "serves remaining non-LLM session mutation routes", - withTmp({ git: true, config: { formatter: false, lsp: false } }, (tmp) => + it.instance( + "rejects part updates whose path and body ids disagree", + () => Effect.gen(function* () { - const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" } - const session = yield* createSession(tmp.path, { title: "remaining" }) + const test = yield* TestInstance + const headers = { "x-opencode-directory": test.directory, "content-type": "application/json" } + const session = yield* createSession({ title: "part mismatch" }) + const message = yield* createTextMessage(session.id, "first") + const response = yield* request( + pathFor(SessionPaths.updatePart, { + sessionID: session.id, + messageID: message.info.id, + partID: message.part.id, + }), + { + method: "PATCH", + headers, + body: JSON.stringify({ ...message.part, id: PartID.ascending() }), + }, + ) + + expect(response.status).toBe(400) + }), + { git: true, config: { formatter: false, lsp: false } }, + ) + + it.instance( + "serves remaining non-LLM session mutation routes", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const headers = { "x-opencode-directory": test.directory, "content-type": "application/json" } + const session = yield* createSession({ title: "remaining" }) expect( yield* requestJson(pathFor(SessionPaths.revert, { sessionID: session.id }), { @@ -566,6 +617,6 @@ describe("session HttpApi", () => { ), ).toBe(true) }), - ), + { git: true, config: { formatter: false, lsp: false } }, ) }) diff --git a/packages/opencode/test/server/httpapi-sync.test.ts b/packages/opencode/test/server/httpapi-sync.test.ts index cd626c28f4..0b59345537 100644 --- a/packages/opencode/test/server/httpapi-sync.test.ts +++ b/packages/opencode/test/server/httpapi-sync.test.ts @@ -1,29 +1,25 @@ -import { afterEach, describe, expect, mock, spyOn, test } from "bun:test" +import { afterEach, describe, expect, mock, spyOn } from "bun:test" import { Context, Effect } from "effect" import { Flag } from "@opencode-ai/core/flag/flag" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { Server } from "../../src/server/server" import { SyncPaths } from "../../src/server/routes/instance/httpapi/groups/sync" import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" import { Session } from "@/session/session" import * as Log from "@opencode-ai/core/util/log" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) const originalWorkspaces = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES const context = Context.empty() as Context.Context +const it = testEffect(Session.defaultLayer) function app() { return Server.Default().app } -function runSession(fx: Effect.Effect) { - return Effect.runPromise(fx.pipe(Effect.provide(Session.defaultLayer))) -} - afterEach(async () => { mock.restore() Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces @@ -32,111 +28,138 @@ afterEach(async () => { }) describe("sync HttpApi", () => { - test("serves sync routes", async () => { - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true - await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } }) - const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" } - const info = spyOn(Log.create({ service: "server.sync" }), "info") + it.instance( + "serves sync routes", + () => + Effect.gen(function* () { + Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true + const tmp = yield* TestInstance + const headers = { "x-opencode-directory": tmp.directory, "content-type": "application/json" } + const info = spyOn(Log.create({ service: "server.sync" }), "info") + const session = yield* Session.Service.use((svc) => svc.create({ title: "sync" })) - const session = await WithInstance.provide({ - directory: tmp.path, - fn: async () => runSession(Session.Service.use((svc) => svc.create({ title: "sync" }))), - }) + const started = yield* Effect.promise(() => + Promise.resolve(app().request(SyncPaths.start, { method: "POST", headers })), + ) + expect(started.status).toBe(200) + expect(yield* Effect.promise(() => started.json())).toBe(true) - const started = await app().request(SyncPaths.start, { method: "POST", headers }) - expect(started.status).toBe(200) - expect(await started.json()).toBe(true) + const history = yield* Effect.promise(() => + Promise.resolve( + app().request(SyncPaths.history, { + method: "POST", + headers, + body: JSON.stringify({}), + }), + ), + ) + expect(history.status).toBe(200) + const rows = (yield* Effect.promise(() => history.json())) as Array<{ + id: string + aggregate_id: string + seq: number + type: string + data: Record + }> + expect(rows.map((row) => row.aggregate_id)).toContain(session.id) - const history = await app().request(SyncPaths.history, { - method: "POST", - headers, - body: JSON.stringify({}), - }) - expect(history.status).toBe(200) - const rows = (await history.json()) as Array<{ - id: string - aggregate_id: string - seq: number - type: string - data: Record - }> - expect(rows.map((row) => row.aggregate_id)).toContain(session.id) - - const replayed = await app().request(SyncPaths.replay, { - method: "POST", - headers, - body: JSON.stringify({ - directory: tmp.path, - events: rows - .filter((row) => row.aggregate_id === session.id) - .map((row) => ({ - id: row.id, - aggregateID: row.aggregate_id, - seq: row.seq, - type: row.type, - data: row.data, - })), + const replayed = yield* Effect.promise(() => + Promise.resolve( + app().request(SyncPaths.replay, { + method: "POST", + headers, + body: JSON.stringify({ + directory: tmp.directory, + events: rows + .filter((row) => row.aggregate_id === session.id) + .map((row) => ({ + id: row.id, + aggregateID: row.aggregate_id, + seq: row.seq, + type: row.type, + data: row.data, + })), + }), + }), + ), + ) + expect(replayed.status).toBe(200) + expect(yield* Effect.promise(() => replayed.json())).toEqual({ sessionID: session.id }) + expect(info.mock.calls.some(([message]) => message === "sync replay requested")).toBe(true) + expect(info.mock.calls.some(([message]) => message === "sync replay complete")).toBe(true) }), - }) - expect(replayed.status).toBe(200) - expect(await replayed.json()).toEqual({ sessionID: session.id }) - expect(info.mock.calls.some(([message]) => message === "sync replay requested")).toBe(true) - expect(info.mock.calls.some(([message]) => message === "sync replay complete")).toBe(true) - }) + { git: true, config: { formatter: false, lsp: false } }, + ) - test("validates seq values", async () => { - await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } }) - const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" } - const cases = [ - { - path: SyncPaths.history, - body: { aggregate: -1 }, - }, - { - path: SyncPaths.history, - body: { aggregate: 1.5 }, - }, - { - path: SyncPaths.replay, - body: { - directory: tmp.path, - events: [{ id: "event", aggregateID: "session", seq: -1, type: "session.created", data: {} }], - }, - }, - { - path: SyncPaths.replay, - body: { - directory: tmp.path, - events: [{ id: "event", aggregateID: "session", seq: 1.5, type: "session.created", data: {} }], - }, - }, - ] + it.instance( + "validates seq values", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const headers = { "x-opencode-directory": tmp.directory, "content-type": "application/json" } + const cases = [ + { + path: SyncPaths.history, + body: { aggregate: -1 }, + }, + { + path: SyncPaths.history, + body: { aggregate: 1.5 }, + }, + { + path: SyncPaths.replay, + body: { + directory: tmp.directory, + events: [{ id: "event", aggregateID: "session", seq: -1, type: "session.created", data: {} }], + }, + }, + { + path: SyncPaths.replay, + body: { + directory: tmp.directory, + events: [{ id: "event", aggregateID: "session", seq: 1.5, type: "session.created", data: {} }], + }, + }, + ] - for (const item of cases) { - const response = await app().request(item.path, { - method: "POST", - headers, - body: JSON.stringify(item.body), - }) - expect(response.status).toBe(400) - } - }) - - test.todo("returns structured validation errors", async () => { - await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } }) - const response = await ExperimentalHttpApiServer.webHandler().handler( - new Request(`http://localhost${SyncPaths.history}`, { - method: "POST", - headers: { "x-opencode-directory": tmp.path, "content-type": "application/json" }, - body: JSON.stringify({ aggregate: -1 }), + for (const item of cases) { + const response = yield* Effect.promise(() => + Promise.resolve( + app().request(item.path, { + method: "POST", + headers, + body: JSON.stringify(item.body), + }), + ), + ) + expect(response.status).toBe(400) + } }), - context, - ) + { git: true, config: { formatter: false, lsp: false } }, + ) - expect(response.status).toBe(400) - expect(response.headers.get("content-type") ?? "").toContain("application/json") - const body = (await response.json()) as Record - expect(body.success).toBe(false) - expect(Array.isArray(body.error) || Array.isArray(body.errors)).toBe(true) - }) + it.instance.skip( + "returns structured validation errors", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const response = yield* Effect.promise(() => + ExperimentalHttpApiServer.webHandler().handler( + new Request(`http://localhost${SyncPaths.history}`, { + method: "POST", + headers: { "x-opencode-directory": tmp.directory, "content-type": "application/json" }, + body: JSON.stringify({ aggregate: -1 }), + }), + context, + ), + ) + + expect(response.status).toBe(400) + expect(response.headers.get("content-type") ?? "").toContain("application/json") + const body = (yield* Effect.promise(() => response.json())) as Record + expect(body.success).toBe(false) + expect(Array.isArray(body.error) || Array.isArray(body.errors)).toBe(true) + }), + { git: true, config: { formatter: false, lsp: false } }, + ) }) diff --git a/packages/opencode/test/server/httpapi-ui.test.ts b/packages/opencode/test/server/httpapi-ui.test.ts index 256c450193..74fc230042 100644 --- a/packages/opencode/test/server/httpapi-ui.test.ts +++ b/packages/opencode/test/server/httpapi-ui.test.ts @@ -1,5 +1,5 @@ import { createHash } from "node:crypto" -import { afterEach, describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import { Flag } from "@opencode-ai/core/flag/flag" import * as Log from "@opencode-ai/core/util/log" import { ConfigProvider, Effect, Layer } from "effect" @@ -18,24 +18,33 @@ import { authorizationRouterMiddleware } from "../../src/server/routes/instance/ import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" import { serveEmbeddedUIEffect, serveUIEffect } from "../../src/server/shared/ui" import { Server } from "../../src/server/server" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) -const original = { - OPENCODE_DISABLE_EMBEDDED_WEB_UI: Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI, - OPENCODE_SERVER_PASSWORD: Flag.OPENCODE_SERVER_PASSWORD, - OPENCODE_SERVER_USERNAME: Flag.OPENCODE_SERVER_USERNAME, - envPassword: process.env.OPENCODE_SERVER_PASSWORD, - envUsername: process.env.OPENCODE_SERVER_USERNAME, -} +const testStateLayer = Layer.effectDiscard( + Effect.gen(function* () { + const original = { + OPENCODE_DISABLE_EMBEDDED_WEB_UI: Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI, + OPENCODE_SERVER_PASSWORD: Flag.OPENCODE_SERVER_PASSWORD, + OPENCODE_SERVER_USERNAME: Flag.OPENCODE_SERVER_USERNAME, + envPassword: process.env.OPENCODE_SERVER_PASSWORD, + envUsername: process.env.OPENCODE_SERVER_USERNAME, + } -afterEach(() => { - Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = original.OPENCODE_DISABLE_EMBEDDED_WEB_UI - Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD - Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME - restoreEnv("OPENCODE_SERVER_PASSWORD", original.envPassword) - restoreEnv("OPENCODE_SERVER_USERNAME", original.envUsername) -}) + yield* Effect.addFinalizer(() => + Effect.sync(() => { + Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = original.OPENCODE_DISABLE_EMBEDDED_WEB_UI + Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD + Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME + restoreEnv("OPENCODE_SERVER_PASSWORD", original.envPassword) + restoreEnv("OPENCODE_SERVER_USERNAME", original.envUsername) + }), + ) + }), +) + +const it = testEffect(Layer.mergeAll(testStateLayer, AppFileSystem.defaultLayer)) function restoreEnv(key: string, value: string | undefined) { if (value === undefined) { @@ -61,9 +70,13 @@ function app(input?: { password?: string; username?: string }) { ).handler return { request(input: string | URL | Request, init?: RequestInit) { - return handler( - input instanceof Request ? input : new Request(new URL(input, "http://localhost"), init), - ExperimentalHttpApiServer.context, + return Effect.promise(() => + Promise.resolve( + handler( + input instanceof Request ? input : new Request(new URL(input, "http://localhost"), init), + ExperimentalHttpApiServer.context, + ), + ), ) }, } @@ -95,9 +108,13 @@ function uiApp(input?: { password?: string; username?: string; client?: Layer.La ).handler return { request(input: string | URL | Request, init?: RequestInit) { - return handler( - input instanceof Request ? input : new Request(new URL(input, "http://localhost"), init), - ExperimentalHttpApiServer.context, + return Effect.promise(() => + Promise.resolve( + handler( + input instanceof Request ? input : new Request(new URL(input, "http://localhost"), init), + ExperimentalHttpApiServer.context, + ), + ), ) }, } @@ -113,32 +130,38 @@ function httpClient(response: Response, onRequest?: (request: HttpClientRequest. ) } +function responseText(response: Response) { + return Effect.promise(() => response.text()) +} + describe("HttpApi UI fallback", () => { - test("serves the web UI through the experimental backend", async () => { - Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true - let proxiedUrl: string | undefined + it.live("serves the web UI through the experimental backend", () => + Effect.gen(function* () { + Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true + let proxiedUrl: string | undefined - const response = await uiApp({ - client: httpClient( - new Response("opencode", { headers: { "content-type": "text/html" } }), - (request) => { - proxiedUrl = request.url - }, - ), - }).request("/") + const response = yield* uiApp({ + client: httpClient( + new Response("opencode", { headers: { "content-type": "text/html" } }), + (request) => { + proxiedUrl = request.url + }, + ), + }).request("/") - expect(response.status).toBe(200) - expect(response.headers.get("content-type")).toContain("text/html") - expect(await response.text()).toBe("opencode") - expect(proxiedUrl).toBe("https://app.opencode.ai/") - }) + expect(response.status).toBe(200) + expect(response.headers.get("content-type")).toContain("text/html") + expect(yield* responseText(response)).toBe("opencode") + expect(proxiedUrl).toBe("https://app.opencode.ai/") + }), + ) - test("strips upstream transfer encoding headers from proxied assets", async () => { - Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true - let proxiedUrl: string | undefined + it.live("strips upstream transfer encoding headers from proxied assets", () => + Effect.gen(function* () { + Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true + let proxiedUrl: string | undefined - const response = await Effect.runPromise( - Effect.gen(function* () { + const response = yield* Effect.gen(function* () { const fs = yield* AppFileSystem.Service const client = yield* HttpClient.HttpClient return yield* serveUIEffect(HttpServerRequest.fromWeb(new Request("http://localhost/assets/app.js")), { @@ -147,48 +170,45 @@ describe("HttpApi UI fallback", () => { }) }).pipe( Effect.provide( - Layer.mergeAll( - AppFileSystem.defaultLayer, - Layer.succeed( - HttpClient.HttpClient, - HttpClient.make((request) => { - proxiedUrl = request.url - return Effect.succeed( - HttpClientResponse.fromWeb( - request, - new Response("console.log('ok')", { - headers: { - "content-encoding": "br", - "content-length": "999", - "content-type": "text/javascript", - }, - }), - ), - ) - }), - ), + Layer.succeed( + HttpClient.HttpClient, + HttpClient.make((request) => { + proxiedUrl = request.url + return Effect.succeed( + HttpClientResponse.fromWeb( + request, + new Response("console.log('ok')", { + headers: { + "content-encoding": "br", + "content-length": "999", + "content-type": "text/javascript", + }, + }), + ), + ) + }), ), ), Effect.map(HttpServerResponse.toWeb), - ), - ) + ) - expect(response.status).toBe(200) - expect(proxiedUrl).toBe("https://app.opencode.ai/assets/app.js") - expect(response.headers.get("content-encoding")).toBeNull() - expect(response.headers.get("content-length")).not.toBe("999") - expect(response.headers.get("content-type")).toContain("text/javascript") - expect(await response.text()).toBe("console.log('ok')") - }) + expect(response.status).toBe(200) + expect(proxiedUrl).toBe("https://app.opencode.ai/assets/app.js") + expect(response.headers.get("content-encoding")).toBeNull() + expect(response.headers.get("content-length")).not.toBe("999") + expect(response.headers.get("content-type")).toContain("text/javascript") + expect(yield* responseText(response)).toBe("console.log('ok')") + }), + ) // Regression for #25698 (Ope): upstream `transfer-encoding: chunked` was // forwarded through the proxy while the proxy itself re-frames the body, // causing browsers to fail with `ERR_INVALID_CHUNKED_ENCODING`. - test("strips upstream transfer-encoding header from proxied assets", async () => { - Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true + it.live("strips upstream transfer-encoding header from proxied assets", () => + Effect.gen(function* () { + Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true - const response = await Effect.runPromise( - Effect.gen(function* () { + const response = yield* Effect.gen(function* () { const fs = yield* AppFileSystem.Service const client = yield* HttpClient.HttpClient return yield* serveUIEffect(HttpServerRequest.fromWeb(new Request("http://localhost/")), { @@ -197,161 +217,166 @@ describe("HttpApi UI fallback", () => { }) }).pipe( Effect.provide( - Layer.mergeAll( - AppFileSystem.defaultLayer, - Layer.succeed( - HttpClient.HttpClient, - HttpClient.make((request) => - Effect.succeed( - HttpClientResponse.fromWeb( - request, - new Response("opencode", { - headers: { - "transfer-encoding": "chunked", - "content-type": "text/html", - }, - }), - ), + Layer.succeed( + HttpClient.HttpClient, + HttpClient.make((request) => + Effect.succeed( + HttpClientResponse.fromWeb( + request, + new Response("opencode", { + headers: { + "transfer-encoding": "chunked", + "content-type": "text/html", + }, + }), ), ), ), ), ), Effect.map(HttpServerResponse.toWeb), - ), - ) + ) - expect(response.status).toBe(200) - expect(response.headers.get("transfer-encoding")).toBeNull() - expect(await response.text()).toBe("opencode") - }) + expect(response.status).toBe(200) + expect(response.headers.get("transfer-encoding")).toBeNull() + expect(yield* responseText(response)).toBe("opencode") + }), + ) - test("serves embedded UI assets when Bun can read them but access reports missing", async () => { - let readPath: string | undefined + it.live("serves embedded UI assets when Bun can read them but access reports missing", () => + Effect.gen(function* () { + let readPath: string | undefined - const response = await Effect.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* serveEmbeddedUIEffect( - "/assets/app.js", - { - ...fs, - existsSafe: () => Effect.die("embedded UI should not rely on filesystem access checks"), - readFile: (path) => { - readPath = path - return path === "/$bunfs/root/assets/app.js" - ? Effect.succeed(new TextEncoder().encode("console.log('embedded')")) - : Effect.die(`unexpected embedded UI path: ${path}`) - }, + const fs = yield* AppFileSystem.Service + const response = yield* serveEmbeddedUIEffect( + "/assets/app.js", + { + ...fs, + existsSafe: () => Effect.die("embedded UI should not rely on filesystem access checks"), + readFile: (path) => { + readPath = path + return path === "/$bunfs/root/assets/app.js" + ? Effect.succeed(new TextEncoder().encode("console.log('embedded')")) + : Effect.die(`unexpected embedded UI path: ${path}`) }, - { "assets/app.js": "/$bunfs/root/assets/app.js" }, - ) - }).pipe(Effect.provide(AppFileSystem.defaultLayer), Effect.map(HttpServerResponse.toWeb)), - ) + }, + { "assets/app.js": "/$bunfs/root/assets/app.js" }, + ).pipe(Effect.map(HttpServerResponse.toWeb)) - expect(response.status).toBe(200) - expect(readPath).toBe("/$bunfs/root/assets/app.js") - expect(response.headers.get("content-type")).toContain("text/javascript") - expect(await response.text()).toBe("console.log('embedded')") - }) + expect(response.status).toBe(200) + expect(readPath).toBe("/$bunfs/root/assets/app.js") + expect(response.headers.get("content-type")).toContain("text/javascript") + expect(yield* responseText(response)).toBe("console.log('embedded')") + }), + ) - test("allows embedded UI terminal wasm and theme preload CSP", async () => { - const script = 'document.documentElement.dataset.theme = "dark"' + it.live("allows embedded UI terminal wasm and theme preload CSP", () => + Effect.gen(function* () { + const script = 'document.documentElement.dataset.theme = "dark"' - const response = await Effect.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* serveEmbeddedUIEffect( - "/", - { - ...fs, - readFile: (path) => { - return path === "/$bunfs/root/index.html" - ? Effect.succeed( - new TextEncoder().encode( - ``, - ), - ) - : Effect.die(`unexpected embedded UI path: ${path}`) - }, + const fs = yield* AppFileSystem.Service + const response = yield* serveEmbeddedUIEffect( + "/", + { + ...fs, + readFile: (path) => { + return path === "/$bunfs/root/index.html" + ? Effect.succeed( + new TextEncoder().encode( + ``, + ), + ) + : Effect.die(`unexpected embedded UI path: ${path}`) }, - { "index.html": "/$bunfs/root/index.html" }, - ) - }).pipe(Effect.provide(AppFileSystem.defaultLayer), Effect.map(HttpServerResponse.toWeb)), - ) + }, + { "index.html": "/$bunfs/root/index.html" }, + ).pipe(Effect.map(HttpServerResponse.toWeb)) - const csp = response.headers.get("content-security-policy") ?? "" - expect(csp).toContain("script-src 'self' 'wasm-unsafe-eval'") - expect(csp).toContain(`'sha256-${createHash("sha256").update(script).digest("base64")}'`) - expect(csp).toContain("connect-src * data:") - }) + const csp = response.headers.get("content-security-policy") ?? "" + expect(csp).toContain("script-src 'self' 'wasm-unsafe-eval'") + expect(csp).toContain(`'sha256-${createHash("sha256").update(script).digest("base64")}'`) + expect(csp).toContain("connect-src * data:") + }), + ) - test("keeps matched API routes ahead of the UI fallback", async () => { - const response = await Server.Default().app.request("/session/ses_nope") + it.live("keeps matched API routes ahead of the UI fallback", () => + Effect.gen(function* () { + const response = yield* Effect.promise(() => Promise.resolve(Server.Default().app.request("/session/ses_nope"))) - expect(response.status).toBe(404) - }) + expect(response.status).toBe(404) + }), + ) - test("requires server password for the web UI", async () => { - Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true + it.live("requires server password for the web UI", () => + Effect.gen(function* () { + Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true - const response = await uiApp({ password: "secret", username: "opencode" }).request("/") + const response = yield* uiApp({ password: "secret", username: "opencode" }).request("/") - expect(response.status).toBe(401) - expect(response.headers.get("www-authenticate")).toBe('Basic realm="Secure Area"') - }) + expect(response.status).toBe(401) + expect(response.headers.get("www-authenticate")).toBe('Basic realm="Secure Area"') + }), + ) - test("accepts auth token for the web UI", async () => { - Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true + it.live("accepts auth token for the web UI", () => + Effect.gen(function* () { + Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true - const response = await uiApp({ - password: "secret", - username: "opencode", - client: httpClient(new Response("opencode", { headers: { "content-type": "text/html" } })), - }).request(`/?auth_token=${btoa("opencode:secret")}`) + const response = yield* uiApp({ + password: "secret", + username: "opencode", + client: httpClient(new Response("opencode", { headers: { "content-type": "text/html" } })), + }).request(`/?auth_token=${btoa("opencode:secret")}`) - expect(response.status).toBe(200) - expect(await response.text()).toBe("opencode") - }) + expect(response.status).toBe(200) + expect(yield* responseText(response)).toBe("opencode") + }), + ) - test("accepts basic auth for the web UI", async () => { - Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true + it.live("accepts basic auth for the web UI", () => + Effect.gen(function* () { + Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true - const response = await uiApp({ password: "secret", username: "opencode" }).request("/", { - headers: { authorization: `Basic ${btoa("opencode:secret")}` }, - }) + const response = yield* uiApp({ password: "secret", username: "opencode" }).request("/", { + headers: { authorization: `Basic ${btoa("opencode:secret")}` }, + }) - expect(response.status).toBe(200) - }) + expect(response.status).toBe(200) + }), + ) // Regression for #25698 (Ope): the browser fetches the PWA manifest and // its icons via flows that don't carry app-managed credentials (the // `` request is not under page-auth control), so the // server returning 401 breaks PWA install. These specific public assets // should bypass auth. - test("serves the PWA manifest without auth even when a server password is set", async () => { - Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true + it.live("serves the PWA manifest without auth even when a server password is set", () => + Effect.gen(function* () { + Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true - for (const path of ["/site.webmanifest", "/web-app-manifest-192x192.png", "/web-app-manifest-512x512.png"]) { - const response = await uiApp({ - password: "secret", - username: "opencode", - client: httpClient(new Response("ok")), - }).request(path) - expect(response.status).not.toBe(401) - } - }) + for (const path of ["/site.webmanifest", "/web-app-manifest-192x192.png", "/web-app-manifest-512x512.png"]) { + const response = yield* uiApp({ + password: "secret", + username: "opencode", + client: httpClient(new Response("ok")), + }).request(path) + expect(response.status).not.toBe(401) + } + }), + ) - test("allows web UI preflight without auth", async () => { - const response = await app({ password: "secret", username: "opencode" }).request("/", { - method: "OPTIONS", - headers: { - origin: "http://localhost:3000", - "access-control-request-method": "GET", - }, - }) + it.live("allows web UI preflight without auth", () => + Effect.gen(function* () { + const response = yield* app({ password: "secret", username: "opencode" }).request("/", { + method: "OPTIONS", + headers: { + origin: "http://localhost:3000", + "access-control-request-method": "GET", + }, + }) - expect(response.status).toBe(204) - expect(response.headers.get("access-control-allow-origin")).toBe("http://localhost:3000") - }) + expect(response.status).toBe(204) + expect(response.headers.get("access-control-allow-origin")).toBe("http://localhost:3000") + }), + ) }) diff --git a/packages/opencode/test/server/negative-tokens-regression.test.ts b/packages/opencode/test/server/negative-tokens-regression.test.ts index 77ad1bc279..290023ead7 100644 --- a/packages/opencode/test/server/negative-tokens-regression.test.ts +++ b/packages/opencode/test/server/negative-tokens-regression.test.ts @@ -5,11 +5,10 @@ // negative. The pre-fix `safe()` clamp only guarded against non-finite. The // strict `NonNegativeInt` schema then made every load of the message list // fail to encode, killing Desktop boot for every user with such a row. -import { afterEach, describe, expect } from "bun:test" +import { describe, expect } from "bun:test" import { Effect } from "effect" import { eq } from "drizzle-orm" import { ModelID, ProviderID } from "../../src/provider/schema" -import { WithInstance } from "../../src/project/with-instance" import { Server } from "../../src/server/server" import { SessionPaths } from "../../src/server/routes/instance/httpapi/groups/session" import { Session } from "@/session/session" @@ -17,81 +16,66 @@ import { MessageID, PartID } from "../../src/session/schema" import * as Database from "@/storage/db" import { PartTable } from "@/session/session.sql" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { it } from "../lib/effect" +import { TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" -afterEach(async () => { - await disposeAllInstances() - await resetDatabase() -}) +const it = testEffect(Session.defaultLayer) -function seedNegativeTokenSession(directory: string) { - return Effect.promise(async () => - WithInstance.provide({ - directory, - fn: () => - Effect.runPromise( - Effect.gen(function* () { - const session = yield* Session.Service - const info = yield* session.create({}) - const message = yield* session.updateMessage({ - id: MessageID.ascending(), - role: "user", - sessionID: info.id, - agent: "build", - model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") }, - time: { created: Date.now() }, - }) - const partID = PartID.ascending() - yield* session.updatePart({ - id: partID, - sessionID: info.id, - messageID: message.id, - type: "step-finish", - reason: "stop", - cost: 0, - tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, - }) +function seedNegativeTokenSession() { + return Effect.gen(function* () { + const session = yield* Session.Service + const info = yield* session.create({}) + const message = yield* session.updateMessage({ + id: MessageID.ascending(), + role: "user", + sessionID: info.id, + agent: "build", + model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") }, + time: { created: Date.now() }, + }) + const partID = PartID.ascending() + yield* session.updatePart({ + id: partID, + sessionID: info.id, + messageID: message.id, + type: "step-finish", + reason: "stop", + cost: 0, + tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, + }) - // Bypass the schema with a direct SQL update to install the - // negative `output` value we want to test loading. - Database.use((db) => - db - .update(PartTable) - .set({ - data: { - type: "step-finish", - reason: "stop", - cost: 0, - tokens: { input: 0, output: -42, reasoning: 0, cache: { read: 0, write: 0 } }, - } as never, - }) - .where(eq(PartTable.id, partID)) - .run(), - ) + // Bypass the schema with a direct SQL update to install the + // negative `output` value we want to test loading. + Database.use((db) => + db + .update(PartTable) + .set({ + data: { + type: "step-finish", + reason: "stop", + cost: 0, + tokens: { input: 0, output: -42, reasoning: 0, cache: { read: 0, write: 0 } }, + } as never, + }) + .where(eq(PartTable.id, partID)) + .run(), + ) - return info.id - }).pipe(Effect.provide(Session.defaultLayer)), - ), - }), - ) + return info.id + }) } describe("messages endpoint tolerates legacy negative token counts", () => { - it.live( + it.instance( "returns 200 even when a step-finish part has tokens.output < 0", - Effect.acquireRelease( - Effect.promise(() => tmpdir({ config: { formatter: false, lsp: false } })), - (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), - ).pipe( - Effect.flatMap((tmp) => - Effect.gen(function* () { - const sessionID = yield* seedNegativeTokenSession(tmp.path) - const url = `${SessionPaths.messages.replace(":sessionID", sessionID)}?limit=80&directory=${encodeURIComponent(tmp.path)}` - const res = yield* Effect.promise(async () => Server.Default().app.request(url)) - expect(res.status, "messages endpoint 400'd on legacy negative tokens").not.toBe(400) - }), - ), - ), + Effect.gen(function* () { + yield* Effect.addFinalizer(() => Effect.promise(() => resetDatabase())) + const test = yield* TestInstance + const sessionID = yield* seedNegativeTokenSession() + const url = `${SessionPaths.messages.replace(":sessionID", sessionID)}?limit=80&directory=${encodeURIComponent(test.directory)}` + const res = yield* Effect.promise(async () => Server.Default().app.request(url)) + expect(res.status, "messages endpoint 400'd on legacy negative tokens").not.toBe(400) + }), + { git: true, config: { formatter: false, lsp: false } }, ) }) diff --git a/packages/opencode/test/server/project-init-git.test.ts b/packages/opencode/test/server/project-init-git.test.ts index 48e28aa5ac..c3e77fb2dd 100644 --- a/packages/opencode/test/server/project-init-git.test.ts +++ b/packages/opencode/test/server/project-init-git.test.ts @@ -1,113 +1,120 @@ -import { afterEach, describe, expect, test } from "bun:test" -import { Effect } from "effect" +import { afterEach, describe, expect } from "bun:test" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { Effect, Layer } from "effect" import path from "path" -import { GlobalBus } from "../../src/bus/global" +import { InstanceRef } from "../../src/effect/instance-ref" +import { InstanceBootstrap } from "../../src/project/bootstrap-service" +import { InstanceStore } from "../../src/project/instance-store" +import { GlobalBus, type GlobalEvent } from "../../src/bus/global" import { Snapshot } from "../../src/snapshot" import { Server } from "../../src/server/server" -import { Filesystem } from "@/util/filesystem" import * as Log from "@opencode-ai/core/util/log" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, provideInstance, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) afterEach(async () => { + await disposeAllInstances() await resetDatabase() }) -const disposedEvents = (seen: { directory?: string; payload: { type: string } }[], dir: string) => +const noopBootstrap = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void })) +const testInstanceStore = InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrap)) + +const it = testEffect(Layer.mergeAll(AppFileSystem.defaultLayer, Snapshot.defaultLayer, testInstanceStore)) + +function request(directory: string, url: string, init: RequestInit = {}) { + return Effect.promise(() => { + const headers = new Headers(init.headers) + headers.set("x-opencode-directory", directory) + return Promise.resolve(Server.Default().app.request(url, { ...init, headers })) + }) +} + +function json(response: Response) { + return Effect.promise(() => response.json() as Promise) +} + +function collectGlobalEvents() { + return Effect.acquireRelease( + Effect.sync(() => { + const seen: GlobalEvent[] = [] + const on = (event: GlobalEvent) => { + seen.push(event) + } + GlobalBus.on("event", on) + return { seen, on } + }), + ({ on }) => Effect.sync(() => GlobalBus.off("event", on)), + ) +} + +const disposedEvents = (seen: GlobalEvent[], dir: string) => seen.filter((evt) => evt.directory === dir && evt.payload.type === "server.instance.disposed").length describe("project.initGit endpoint", () => { - test("initializes git and reloads immediately", async () => { - await using tmp = await tmpdir() - const app = Server.Default().app - const seen: { directory?: string; payload: { type: string } }[] = [] - const fn = (evt: { directory?: string; payload: { type: string } }) => { - seen.push(evt) - } - GlobalBus.on("event", fn) + it.instance("initializes git and reloads immediately", () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const fs = yield* AppFileSystem.Service + const events = yield* collectGlobalEvents() - try { - const init = await app.request("/project/git/init", { + const init = yield* request(tmp.directory, "/project/git/init", { method: "POST", - headers: { - "x-opencode-directory": tmp.path, - }, }) - const body = await init.json() + const body = yield* json(init) expect(init.status).toBe(200) expect(body).toMatchObject({ id: "global", vcs: "git", - worktree: tmp.path, + worktree: tmp.directory, }) // Reload behavior: bus emits exactly one server.instance.disposed for the directory. - expect(disposedEvents(seen, tmp.path)).toBe(1) - expect(await Filesystem.exists(path.join(tmp.path, ".git", "opencode"))).toBe(false) + expect(disposedEvents(events.seen, tmp.directory)).toBe(1) + expect(yield* fs.exists(path.join(tmp.directory, ".git", "opencode"))).toBe(false) - const current = await app.request("/project/current", { - headers: { - "x-opencode-directory": tmp.path, - }, - }) + const current = yield* request(tmp.directory, "/project/current") expect(current.status).toBe(200) - expect(await current.json()).toMatchObject({ + expect(yield* json(current)).toMatchObject({ id: "global", vcs: "git", - worktree: tmp.path, + worktree: tmp.directory, }) - expect( - await Effect.runPromise( - Snapshot.Service.use((svc) => svc.track()).pipe( - provideInstance(tmp.path), - Effect.provide(Snapshot.defaultLayer), - ), - ), - ).toBeTruthy() - } finally { - await disposeAllInstances() - GlobalBus.off("event", fn) - } - }) + const ctx = yield* InstanceStore.Service.use((store) => store.reload({ directory: tmp.directory })) + const tracked = yield* Snapshot.Service.use((snapshot) => snapshot.track()).pipe( + Effect.provideService(InstanceRef, ctx), + ) + expect(tracked).toBeTruthy() + }), + ) - test("does not reload when the project is already git", async () => { - await using tmp = await tmpdir({ git: true }) - const app = Server.Default().app - const seen: { directory?: string; payload: { type: string } }[] = [] - const fn = (evt: { directory?: string; payload: { type: string } }) => { - seen.push(evt) - } - GlobalBus.on("event", fn) + it.instance( + "does not reload when the project is already git", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const events = yield* collectGlobalEvents() - try { - const init = await app.request("/project/git/init", { - method: "POST", - headers: { - "x-opencode-directory": tmp.path, - }, - }) - expect(init.status).toBe(200) - expect(await init.json()).toMatchObject({ - vcs: "git", - worktree: tmp.path, - }) - expect(disposedEvents(seen, tmp.path)).toBe(0) + const init = yield* request(tmp.directory, "/project/git/init", { + method: "POST", + }) + expect(init.status).toBe(200) + expect(yield* json(init)).toMatchObject({ + vcs: "git", + worktree: tmp.directory, + }) + expect(disposedEvents(events.seen, tmp.directory)).toBe(0) - const current = await app.request("/project/current", { - headers: { - "x-opencode-directory": tmp.path, - }, - }) - expect(current.status).toBe(200) - expect(await current.json()).toMatchObject({ - vcs: "git", - worktree: tmp.path, - }) - } finally { - await disposeAllInstances() - GlobalBus.off("event", fn) - } - }) + const current = yield* request(tmp.directory, "/project/current") + expect(current.status).toBe(200) + expect(yield* json(current)).toMatchObject({ + vcs: "git", + worktree: tmp.directory, + }) + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/server/session-actions.test.ts b/packages/opencode/test/server/session-actions.test.ts index 1ccc9bc8e6..44e324b712 100644 --- a/packages/opencode/test/server/session-actions.test.ts +++ b/packages/opencode/test/server/session-actions.test.ts @@ -1,28 +1,14 @@ -import { afterEach, describe, expect, mock, test } from "bun:test" +import { afterEach, describe, expect, mock } from "bun:test" import { Effect } from "effect" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { Server } from "../../src/server/server" import { Session as SessionNs } from "@/session/session" -import type { SessionID } from "../../src/session/schema" import * as Log from "@opencode-ai/core/util/log" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) -function run(fx: Effect.Effect) { - return Effect.runPromise(fx.pipe(Effect.provide(SessionNs.defaultLayer))) -} - -const svc = { - ...SessionNs, - create(input?: SessionNs.CreateInput) { - return run(SessionNs.Service.use((svc) => svc.create(input))) - }, - remove(id: SessionID) { - return run(SessionNs.Service.use((svc) => svc.remove(id))) - }, -} +const it = testEffect(SessionNs.defaultLayer) afterEach(async () => { mock.restore() @@ -30,21 +16,28 @@ afterEach(async () => { }) describe("session action routes", () => { - test("abort route returns success", async () => { - await using tmp = await tmpdir({ git: true }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const session = await svc.create({}) - const app = Server.Default().app + it.instance( + "abort route returns success", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const session = yield* Effect.acquireRelease( + SessionNs.Service.use((svc) => svc.create({})), + (created) => SessionNs.Service.use((svc) => svc.remove(created.id)).pipe(Effect.ignore), + ) - const res = await app.request(`/session/${session.id}/abort`, { method: "POST" }) + const res = yield* Effect.promise(() => + Promise.resolve( + Server.Default().app.request(`/session/${session.id}/abort`, { + method: "POST", + headers: { "x-opencode-directory": test.directory }, + }), + ), + ) expect(res.status).toBe(200) - expect(await res.json()).toBe(true) - - await svc.remove(session.id) - }, - }) - }) + expect(yield* Effect.promise(() => res.json())).toBe(true) + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/server/session-diff-missing-patch.test.ts b/packages/opencode/test/server/session-diff-missing-patch.test.ts index 5f27a4e2fd..875c031d57 100644 --- a/packages/opencode/test/server/session-diff-missing-patch.test.ts +++ b/packages/opencode/test/server/session-diff-missing-patch.test.ts @@ -10,19 +10,20 @@ * asserts that GET /session//diff returns 200 with the row intact. */ import { afterEach, describe, expect } from "bun:test" -import { Effect } from "effect" +import { Effect, Layer } from "effect" import { Server } from "@/server/server" import { SessionPaths } from "@/server/routes/instance/httpapi/groups/session" import { Session } from "@/session/session" import { Storage } from "@/storage/storage" -import { WithInstance } from "@/project/with-instance" import { resetDatabase } from "../fixture/db" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { it } from "../lib/effect" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" import * as Log from "@opencode-ai/core/util/log" void Log.init({ print: false }) +const it = testEffect(Layer.mergeAll(Session.defaultLayer, Storage.defaultLayer)) + afterEach(async () => { await disposeAllInstances() await resetDatabase() @@ -32,50 +33,46 @@ function pathFor(template: string, params: Record) { return Object.entries(params).reduce((result, [key, value]) => result.replace(`:${key}`, value), template) } +const withSession = (input?: Parameters[0]) => + Effect.acquireRelease( + Session.Service.use((session) => session.create(input)), + (created) => Session.Service.use((session) => session.remove(created.id)).pipe(Effect.ignore), + ) + describe("session diff with missing patch (#26574)", () => { - it.live("GET /session//diff returns 200 when summary_diffs row has no patch", () => - Effect.gen(function* () { - const tmp = yield* Effect.acquireRelease( - Effect.promise(() => tmpdir({ git: true, config: { formatter: false, lsp: false } })), - (t) => Effect.promise(() => t[Symbol.asyncDispose]()), - ) + it.instance( + "GET /session//diff returns 200 when summary_diffs row has no patch", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const session = yield* withSession({ title: "missing-patch" }) - yield* Effect.promise(() => - WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const session = await Effect.runPromise( - Effect.provide( - Session.Service.use((s) => s.create({ title: "missing-patch" })), - Session.defaultLayer, - ), - ) + // Mimic legacy/imported on-disk shape: a diff entry with no + // `patch` text. Pre-fix the typed response encoder rejects + // this and returns 400. + yield* Storage.Service.use((storage) => + storage.write(["session_diff", session.id], [{ file: "legacy.txt", additions: 1, deletions: 0 }]), + ) - // Mimic legacy/imported on-disk shape: a diff entry with no - // `patch` text. Pre-fix the typed response encoder rejects - // this and returns 400. - await Effect.runPromise( - Effect.provide( - Storage.Service.use((s) => - s.write(["session_diff", session.id], [{ file: "legacy.txt", additions: 1, deletions: 0 }]), - ), - Storage.defaultLayer, - ), - ) + const response = yield* Effect.promise(() => + Promise.resolve( + Server.Default().app.request(pathFor(SessionPaths.diff, { sessionID: session.id }), { + headers: { "x-opencode-directory": test.directory }, + }), + ), + ) - const headers = { "x-opencode-directory": tmp.path } - const response = await Server.Default().app.request(pathFor(SessionPaths.diff, { sessionID: session.id }), { - headers, - }) - expect(response.status).toBe(200) - const body = (await response.json()) as Array<{ file: string; patch?: string; additions: number }> - expect(body).toHaveLength(1) - expect(body[0]?.file).toBe("legacy.txt") - expect(body[0]?.additions).toBe(1) - expect(body[0]?.patch).toBeUndefined() - }, - }), - ) - }), + expect(response.status).toBe(200) + const body = (yield* Effect.promise(() => response.json())) as Array<{ + file: string + patch?: string + additions: number + }> + expect(body).toHaveLength(1) + expect(body[0]?.file).toBe("legacy.txt") + expect(body[0]?.additions).toBe(1) + expect(body[0]?.patch).toBeUndefined() + }), + { git: true, config: { formatter: false, lsp: false } }, ) }) diff --git a/packages/opencode/test/server/session-list.test.ts b/packages/opencode/test/server/session-list.test.ts index 20478dde84..1bd3c66474 100644 --- a/packages/opencode/test/server/session-list.test.ts +++ b/packages/opencode/test/server/session-list.test.ts @@ -1,239 +1,229 @@ -import { afterEach, describe, expect, test } from "bun:test" -import { Effect } from "effect" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" +import { afterEach, describe, expect } from "bun:test" +import { Effect, Layer } from "effect" import { Session as SessionNs } from "@/session/session" import * as Log from "@opencode-ai/core/util/log" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" -import { Flag } from "@opencode-ai/core/flag/flag" +import { disposeAllInstances, provideInstance, TestInstance } from "../fixture/fixture" import { mkdir } from "fs/promises" import path from "path" import { Database } from "@/storage/db" import { SessionTable } from "@/session/session.sql" import { eq } from "drizzle-orm" +import { testEffect } from "../lib/effect" +import { Bus } from "@/bus" +import { Storage } from "@/storage/storage" +import { SyncEvent } from "@/sync" +import { RuntimeFlags } from "@/effect/runtime-flags" void Log.init({ print: false }) -const originalWorkspaces = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES +const it = testEffect( + SessionNs.layer.pipe( + Layer.provide(Bus.layer), + Layer.provide(Storage.defaultLayer), + Layer.provide(SyncEvent.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalWorkspaces: false })), + ), +) -function run(fx: Effect.Effect) { - return Effect.runPromise(fx.pipe(Effect.provide(SessionNs.defaultLayer))) -} - -const svc = { - ...SessionNs, - create(input?: SessionNs.CreateInput) { - return run(SessionNs.Service.use((svc) => svc.create(input))) - }, - list(input?: SessionNs.ListInput) { - return run(SessionNs.Service.use((svc) => svc.list(input))) - }, -} +const withSession = (input?: Parameters[0]) => + Effect.acquireRelease( + SessionNs.Service.use((session) => session.create(input)), + (created) => SessionNs.Service.use((session) => session.remove(created.id).pipe(Effect.ignore)), + ) afterEach(async () => { - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces await disposeAllInstances() }) describe("session.list", () => { - test("does not filter by directory when directory is omitted", async () => { - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = false - await using tmp = await tmpdir({ git: true }) - await mkdir(path.join(tmp.path, "packages", "opencode"), { recursive: true }) - await mkdir(path.join(tmp.path, "packages", "app"), { recursive: true }) + it.instance( + "does not filter by directory when directory is omitted", + () => + Effect.gen(function* () { + const test = yield* TestInstance + yield* Effect.promise(() => mkdir(path.join(test.directory, "packages", "opencode"), { recursive: true })) + yield* Effect.promise(() => mkdir(path.join(test.directory, "packages", "app"), { recursive: true })) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const root = await svc.create({ title: "root" }) + const root = yield* withSession({ title: "root" }) + const parent = yield* withSession({ title: "parent" }).pipe( + provideInstance(path.join(test.directory, "packages")), + ) + const current = yield* withSession({ title: "current" }).pipe( + provideInstance(path.join(test.directory, "packages", "opencode")), + ) + const sibling = yield* withSession({ title: "sibling" }).pipe( + provideInstance(path.join(test.directory, "packages", "app")), + ) - const parent = await WithInstance.provide({ - directory: path.join(tmp.path, "packages"), - fn: async () => svc.create({ title: "parent" }), - }) - const current = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "opencode"), - fn: async () => svc.create({ title: "current" }), - }) - const sibling = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "app"), - fn: async () => svc.create({ title: "sibling" }), - }) - - const ids = (await svc.list()).map((s) => s.id) + const ids = (yield* SessionNs.Service.use((session) => session.list())).map((session) => session.id) expect(ids).toContain(root.id) expect(ids).toContain(parent.id) expect(ids).toContain(current.id) expect(ids).toContain(sibling.id) - }, - }) - }) + }), + { git: true }, + ) - test("filters by directory when directory is provided", async () => { - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = false - await using tmp = await tmpdir({ git: true }) - await mkdir(path.join(tmp.path, "packages", "opencode"), { recursive: true }) - await mkdir(path.join(tmp.path, "packages", "app"), { recursive: true }) + it.instance( + "filters by directory when directory is provided", + () => + Effect.gen(function* () { + const test = yield* TestInstance + yield* Effect.promise(() => mkdir(path.join(test.directory, "packages", "opencode"), { recursive: true })) + yield* Effect.promise(() => mkdir(path.join(test.directory, "packages", "app"), { recursive: true })) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const root = await svc.create({ title: "root" }) + const root = yield* withSession({ title: "root" }) + const parent = yield* withSession({ title: "parent" }).pipe( + provideInstance(path.join(test.directory, "packages")), + ) + const current = yield* withSession({ title: "current" }).pipe( + provideInstance(path.join(test.directory, "packages", "opencode")), + ) + const sibling = yield* withSession({ title: "sibling" }).pipe( + provideInstance(path.join(test.directory, "packages", "app")), + ) - const parent = await WithInstance.provide({ - directory: path.join(tmp.path, "packages"), - fn: async () => svc.create({ title: "parent" }), - }) - const current = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "opencode"), - fn: async () => svc.create({ title: "current" }), - }) - const sibling = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "app"), - fn: async () => svc.create({ title: "sibling" }), - }) - - const ids = (await svc.list({ directory: path.join(tmp.path, "packages", "opencode") })).map((s) => s.id) + const ids = (yield* SessionNs.Service.use((session) => + session.list({ directory: path.join(test.directory, "packages", "opencode") }), + )).map((session) => session.id) expect(ids).not.toContain(root.id) expect(ids).not.toContain(parent.id) expect(ids).toContain(current.id) expect(ids).not.toContain(sibling.id) - }, - }) - }) + }), + { git: true }, + ) - test("filters by path and ignores directory when path is provided", async () => { - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = false - await using tmp = await tmpdir({ git: true }) - await mkdir(path.join(tmp.path, "packages", "opencode", "src", "deep"), { recursive: true }) - await mkdir(path.join(tmp.path, "packages", "app"), { recursive: true }) + it.instance( + "filters by path and ignores directory when path is provided", + () => + Effect.gen(function* () { + const test = yield* TestInstance + yield* Effect.promise(() => + mkdir(path.join(test.directory, "packages", "opencode", "src", "deep"), { recursive: true }), + ) + yield* Effect.promise(() => mkdir(path.join(test.directory, "packages", "app"), { recursive: true })) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const parent = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "opencode"), - fn: async () => svc.create({ title: "parent" }), - }) - const current = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "opencode", "src"), - fn: async () => svc.create({ title: "current" }), - }) - const deeper = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "opencode", "src", "deep"), - fn: async () => svc.create({ title: "deeper" }), - }) - const sibling = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "app"), - fn: async () => svc.create({ title: "sibling" }), - }) + const parent = yield* withSession({ title: "parent" }).pipe( + provideInstance(path.join(test.directory, "packages", "opencode")), + ) + const current = yield* withSession({ title: "current" }).pipe( + provideInstance(path.join(test.directory, "packages", "opencode", "src")), + ) + const deeper = yield* withSession({ title: "deeper" }).pipe( + provideInstance(path.join(test.directory, "packages", "opencode", "src", "deep")), + ) + const sibling = yield* withSession({ title: "sibling" }).pipe( + provideInstance(path.join(test.directory, "packages", "app")), + ) - const pathIDs = ( - await svc.list({ - directory: path.join(tmp.path, "packages", "app"), + const pathIDs = (yield* SessionNs.Service.use((session) => + session.list({ + directory: path.join(test.directory, "packages", "app"), path: "packages/opencode/src", - }) - ).map((s) => s.id) + }), + )).map((session) => session.id) expect(pathIDs).not.toContain(parent.id) expect(pathIDs).toContain(current.id) expect(pathIDs).toContain(deeper.id) expect(pathIDs).not.toContain(sibling.id) - }, - }) - }) + }), + { git: true }, + ) - test("falls back to directory when filtering legacy sessions without path", async () => { - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = false - await using tmp = await tmpdir({ git: true }) - await mkdir(path.join(tmp.path, "packages", "opencode", "src"), { recursive: true }) - await mkdir(path.join(tmp.path, "packages", "app"), { recursive: true }) + it.instance( + "falls back to directory when filtering legacy sessions without path", + () => + Effect.gen(function* () { + const test = yield* TestInstance + yield* Effect.promise(() => + mkdir(path.join(test.directory, "packages", "opencode", "src"), { recursive: true }), + ) + yield* Effect.promise(() => mkdir(path.join(test.directory, "packages", "app"), { recursive: true })) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const current = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "opencode", "src"), - fn: async () => svc.create({ title: "legacy-current" }), - }) - const sibling = await WithInstance.provide({ - directory: path.join(tmp.path, "packages", "app"), - fn: async () => svc.create({ title: "legacy-sibling" }), - }) + const current = yield* withSession({ title: "legacy-current" }).pipe( + provideInstance(path.join(test.directory, "packages", "opencode", "src")), + ) + const sibling = yield* withSession({ title: "legacy-sibling" }).pipe( + provideInstance(path.join(test.directory, "packages", "app")), + ) - Database.use((db) => db.update(SessionTable).set({ path: null }).where(eq(SessionTable.id, current.id)).run()) - Database.use((db) => db.update(SessionTable).set({ path: null }).where(eq(SessionTable.id, sibling.id)).run()) + yield* Effect.sync(() => + Database.use((db) => + db.update(SessionTable).set({ path: null }).where(eq(SessionTable.id, current.id)).run(), + ), + ) + yield* Effect.sync(() => + Database.use((db) => + db.update(SessionTable).set({ path: null }).where(eq(SessionTable.id, sibling.id)).run(), + ), + ) - const pathIDs = ( - await svc.list({ - directory: path.join(tmp.path, "packages", "opencode", "src"), + const pathIDs = (yield* SessionNs.Service.use((session) => + session.list({ + directory: path.join(test.directory, "packages", "opencode", "src"), path: "packages/opencode/src", - }) - ).map((s) => s.id) + }), + )).map((session) => session.id) expect(pathIDs).toContain(current.id) expect(pathIDs).not.toContain(sibling.id) - }, - }) - }) + }), + { git: true }, + ) - test("filters root sessions", async () => { - await using tmp = await tmpdir({ git: true }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const root = await svc.create({ title: "root-session" }) - const child = await svc.create({ title: "child-session", parentID: root.id }) + it.instance( + "filters root sessions", + () => + Effect.gen(function* () { + const root = yield* withSession({ title: "root-session" }) + const child = yield* withSession({ title: "child-session", parentID: root.id }) - const sessions = await svc.list({ roots: true }) - const ids = sessions.map((s) => s.id) + const sessions = yield* SessionNs.Service.use((session) => session.list({ roots: true })) + const ids = sessions.map((session) => session.id) expect(ids).toContain(root.id) expect(ids).not.toContain(child.id) - }, - }) - }) + }), + { git: true }, + ) - test("filters by start time", async () => { - await using tmp = await tmpdir({ git: true }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await svc.create({ title: "new-session" }) - const futureStart = Date.now() + 86400000 - - const sessions = await svc.list({ start: futureStart }) + it.instance( + "filters by start time", + () => + Effect.gen(function* () { + yield* withSession({ title: "new-session" }) + const sessions = yield* SessionNs.Service.use((session) => session.list({ start: Date.now() + 86400000 })) expect(sessions.length).toBe(0) - }, - }) - }) + }), + { git: true }, + ) - test("filters by search term", async () => { - await using tmp = await tmpdir({ git: true }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await svc.create({ title: "unique-search-term-abc" }) - await svc.create({ title: "other-session-xyz" }) + it.instance( + "filters by search term", + () => + Effect.gen(function* () { + yield* withSession({ title: "unique-search-term-abc" }) + yield* withSession({ title: "other-session-xyz" }) - const sessions = await svc.list({ search: "unique-search" }) - const titles = sessions.map((s) => s.title) + const sessions = yield* SessionNs.Service.use((session) => session.list({ search: "unique-search" })) + const titles = sessions.map((session) => session.title) expect(titles).toContain("unique-search-term-abc") expect(titles).not.toContain("other-session-xyz") - }, - }) - }) + }), + { git: true }, + ) - test("respects limit parameter", async () => { - await using tmp = await tmpdir({ git: true }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await svc.create({ title: "session-1" }) - await svc.create({ title: "session-2" }) - await svc.create({ title: "session-3" }) + it.instance( + "respects limit parameter", + () => + Effect.gen(function* () { + yield* withSession({ title: "session-1" }) + yield* withSession({ title: "session-2" }) + yield* withSession({ title: "session-3" }) - const sessions = await svc.list({ limit: 2 }) + const sessions = yield* SessionNs.Service.use((session) => session.list({ limit: 2 })) expect(sessions.length).toBe(2) - }, - }) - }) + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/server/session-messages.test.ts b/packages/opencode/test/server/session-messages.test.ts index f5ee5bdcb0..e603accbbe 100644 --- a/packages/opencode/test/server/session-messages.test.ts +++ b/packages/opencode/test/server/session-messages.test.ts @@ -1,191 +1,179 @@ -import { afterEach, describe, expect, test } from "bun:test" +import { afterEach, describe, expect } from "bun:test" import { Effect } from "effect" -import { WithInstance } from "../../src/project/with-instance" import { Server } from "../../src/server/server" import { Session as SessionNs } from "@/session/session" import { MessageV2 } from "../../src/session/message-v2" +import { ModelID, ProviderID } from "../../src/provider/schema" import { MessageID, PartID, type SessionID } from "../../src/session/schema" import * as Log from "@opencode-ai/core/util/log" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) -function run(fx: Effect.Effect) { - return Effect.runPromise(fx.pipe(Effect.provide(SessionNs.defaultLayer))) -} +const it = testEffect(SessionNs.defaultLayer) -const svc = { - ...SessionNs, - create(input?: SessionNs.CreateInput) { - return run(SessionNs.Service.use((svc) => svc.create(input))) - }, - remove(id: SessionID) { - return run(SessionNs.Service.use((svc) => svc.remove(id))) - }, - updateMessage(msg: T) { - return run(SessionNs.Service.use((svc) => svc.updateMessage(msg))) - }, - updatePart(part: T) { - return run(SessionNs.Service.use((svc) => svc.updatePart(part))) - }, +const model = { + providerID: ProviderID.make("test"), + modelID: ModelID.make("test"), } afterEach(async () => { await disposeAllInstances() }) -async function withoutWatcher(fn: () => Promise) { - if (process.platform !== "win32") return fn() - const prev = process.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER - process.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER = "true" - try { - return await fn() - } finally { - if (prev === undefined) delete process.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER - else process.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER = prev - } +const withoutWatcher = (effect: Effect.Effect) => { + if (process.platform !== "win32") return effect + return Effect.acquireUseRelease( + Effect.sync(() => { + const previous = process.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER + process.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER = "true" + return previous + }), + () => effect, + (previous) => + Effect.sync(() => { + if (previous === undefined) delete process.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER + else process.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER = previous + }), + ) } -async function fill(sessionID: SessionID, count: number, time = (i: number) => Date.now() + i) { - const ids = [] as MessageID[] - for (let i = 0; i < count; i++) { - const id = MessageID.ascending() - ids.push(id) - await svc.updateMessage({ - id, - sessionID, - role: "user", - time: { created: time(i) }, - agent: "test", - model: { providerID: "test", modelID: "test" }, - tools: {}, - mode: "", - } as unknown as MessageV2.Info) - await svc.updatePart({ - id: PartID.ascending(), - sessionID, - messageID: id, - type: "text", - text: `m${i}`, - }) - } - return ids +const sessionScoped = Effect.acquireRelease( + SessionNs.Service.use((svc) => svc.create({})), + (session) => SessionNs.Service.use((svc) => svc.remove(session.id)).pipe(Effect.ignore), +) + +const fill = Effect.fn("SessionMessagesTest.fill")(function* ( + sessionID: SessionID, + count: number, + time = (i: number) => Date.now() + i, +) { + const session = yield* SessionNs.Service + return yield* Effect.forEach( + Array.from({ length: count }, (_, i) => i), + (i) => + Effect.gen(function* () { + const id = MessageID.ascending() + yield* session.updateMessage({ + id, + sessionID, + role: "user", + time: { created: time(i) }, + agent: "test", + model, + tools: {}, + } satisfies MessageV2.User) + yield* session.updatePart({ + id: PartID.ascending(), + sessionID, + messageID: id, + type: "text", + text: `m${i}`, + } satisfies MessageV2.TextPart) + return id + }), + ) +}) + +function request(path: string) { + return Effect.promise(() => Promise.resolve(Server.Default().app.request(path))) +} + +function json(response: Response) { + return Effect.promise(() => response.json() as Promise) } describe("session messages endpoint", () => { - test("returns cursor headers for older pages", async () => { - await using tmp = await tmpdir({ git: true }) - await withoutWatcher(() => - WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const session = await svc.create({}) - const ids = await fill(session.id, 5) - const app = Server.Default().app + it.instance( + "returns cursor headers for older pages", + withoutWatcher( + Effect.gen(function* () { + const session = yield* sessionScoped + const ids = yield* fill(session.id, 5) - const a = await app.request(`/session/${session.id}/message?limit=2`) - expect(a.status).toBe(200) - const aBody = (await a.json()) as MessageV2.WithParts[] - expect(aBody.map((item) => item.info.id)).toEqual(ids.slice(-2)) - const cursor = a.headers.get("x-next-cursor") - expect(cursor).toBeTruthy() - expect(a.headers.get("link")).toContain('rel="next"') + const a = yield* request(`/session/${session.id}/message?limit=2`) + expect(a.status).toBe(200) + const aBody = yield* json(a) + expect(aBody.map((item) => item.info.id)).toEqual(ids.slice(-2)) + const cursor = a.headers.get("x-next-cursor") + expect(cursor).toBeTruthy() + expect(a.headers.get("link")).toContain('rel="next"') - const b = await app.request(`/session/${session.id}/message?limit=2&before=${encodeURIComponent(cursor!)}`) - expect(b.status).toBe(200) - const bBody = (await b.json()) as MessageV2.WithParts[] - expect(bBody.map((item) => item.info.id)).toEqual(ids.slice(-4, -2)) - - await svc.remove(session.id) - }, + const b = yield* request(`/session/${session.id}/message?limit=2&before=${encodeURIComponent(cursor!)}`) + expect(b.status).toBe(200) + const bBody = yield* json(b) + expect(bBody.map((item) => item.info.id)).toEqual(ids.slice(-4, -2)) }), - ) - }) + ), + { git: true }, + ) - test("keeps full-history responses when limit is omitted", async () => { - await using tmp = await tmpdir({ git: true }) - await withoutWatcher(() => - WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const session = await svc.create({}) - const ids = await fill(session.id, 3) - const app = Server.Default().app + it.instance( + "keeps full-history responses when limit is omitted", + withoutWatcher( + Effect.gen(function* () { + const session = yield* sessionScoped + const ids = yield* fill(session.id, 3) - const res = await app.request(`/session/${session.id}/message`) - expect(res.status).toBe(200) - const body = (await res.json()) as MessageV2.WithParts[] - expect(body.map((item) => item.info.id)).toEqual(ids) - - await svc.remove(session.id) - }, + const res = yield* request(`/session/${session.id}/message`) + expect(res.status).toBe(200) + const body = yield* json(res) + expect(body.map((item) => item.info.id)).toEqual(ids) }), - ) - }) + ), + { git: true }, + ) - test("rejects invalid cursors and missing sessions", async () => { - await using tmp = await tmpdir({ git: true }) - await withoutWatcher(() => - WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const session = await svc.create({}) - const app = Server.Default().app + it.instance( + "rejects invalid cursors and missing sessions", + withoutWatcher( + Effect.gen(function* () { + const session = yield* sessionScoped - const bad = await app.request(`/session/${session.id}/message?limit=2&before=bad`) - expect(bad.status).toBe(400) + const bad = yield* request(`/session/${session.id}/message?limit=2&before=bad`) + expect(bad.status).toBe(400) - const miss = await app.request(`/session/ses_missing/message?limit=2`) - expect(miss.status).toBe(404) - - await svc.remove(session.id) - }, + const miss = yield* request(`/session/ses_missing/message?limit=2`) + expect(miss.status).toBe(404) }), - ) - }) + ), + { git: true }, + ) - test("does not truncate large legacy limit requests", async () => { - await using tmp = await tmpdir({ git: true }) - await withoutWatcher(() => - WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const session = await svc.create({}) - await fill(session.id, 520) - const app = Server.Default().app + it.instance( + "does not truncate large legacy limit requests", + withoutWatcher( + Effect.gen(function* () { + const session = yield* sessionScoped + yield* fill(session.id, 520) - const res = await app.request(`/session/${session.id}/message?limit=510`) - expect(res.status).toBe(200) - const body = (await res.json()) as MessageV2.WithParts[] - expect(body).toHaveLength(510) - - await svc.remove(session.id) - }, + const res = yield* request(`/session/${session.id}/message?limit=510`) + expect(res.status).toBe(200) + const body = yield* json(res) + expect(body).toHaveLength(510) }), - ) - }) + ), + { git: true }, + ) - test("accepts directory query used by workspace routing", async () => { - await using tmp = await tmpdir({ git: true }) - await withoutWatcher(() => - WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const session = await svc.create({}) - await fill(session.id, 1) - const app = Server.Default().app + it.instance( + "accepts directory query used by workspace routing", + withoutWatcher( + Effect.gen(function* () { + const tmp = yield* TestInstance + const session = yield* sessionScoped + yield* fill(session.id, 1) - const res = await app.request( - `/session/${session.id}/message?limit=80&directory=${encodeURIComponent(tmp.path)}`, - ) - expect(res.status).toBe(200) - const body = await res.json() - expect(Array.isArray(body)).toBe(true) - expect(body).toHaveLength(1) - - await svc.remove(session.id) - }, + const res = yield* request( + `/session/${session.id}/message?limit=80&directory=${encodeURIComponent(tmp.directory)}`, + ) + expect(res.status).toBe(200) + const body = yield* json(res) + expect(Array.isArray(body)).toBe(true) + expect(body).toHaveLength(1) }), - ) - }) + ), + { git: true }, + ) }) diff --git a/packages/opencode/test/server/session-select.test.ts b/packages/opencode/test/server/session-select.test.ts index 13edca1458..9e24ed0ecc 100644 --- a/packages/opencode/test/server/session-select.test.ts +++ b/packages/opencode/test/server/session-select.test.ts @@ -1,101 +1,93 @@ -import { afterEach, describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import { Effect } from "effect" -import { Session as SessionNs } from "@/session/session" -import type { SessionID } from "../../src/session/schema" +import { Session } from "@/session/session" import * as Log from "@opencode-ai/core/util/log" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { Server } from "../../src/server/server" -import { disposeAllInstances, tmpdir } from "../fixture/fixture" +import { TestInstance } from "../fixture/fixture" +import { testEffect } from "../lib/effect" void Log.init({ print: false }) -function run(fx: Effect.Effect) { - return Effect.runPromise(fx.pipe(Effect.provide(SessionNs.defaultLayer))) -} - -const svc = { - ...SessionNs, - create(input?: SessionNs.CreateInput) { - return run(SessionNs.Service.use((svc) => svc.create(input))) - }, - remove(id: SessionID) { - return run(SessionNs.Service.use((svc) => svc.remove(id))) - }, -} - -afterEach(async () => { - await disposeAllInstances() -}) +const it = testEffect(Session.defaultLayer) describe("tui.selectSession endpoint", () => { - test("should return 200 when called with valid session", async () => { - await using tmp = await tmpdir({ git: true }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - // #given - const session = await svc.create({}) + it.instance( + "should return 200 when called with valid session", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance + const session = yield* Session.Service.use((svc) => svc.create({})) - // #when const app = Server.Default().app - const response = await app.request("/tui/select-session", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ sessionID: session.id }), - }) + const response = yield* Effect.promise(() => + Promise.resolve( + app.request("/tui/select-session", { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-opencode-directory": tmp.directory, + }, + body: JSON.stringify({ sessionID: session.id }), + }), + ), + ) - // #then expect(response.status).toBe(200) - const body = await response.json() + const body = yield* Effect.promise(() => response.json()) expect(body).toBe(true) + }), + { git: true }, + ) - await svc.remove(session.id) - }, - }) - }) - - test("should return 404 when session does not exist", async () => { - await using tmp = await tmpdir({ git: true }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - // #given + it.instance( + "should return 404 when session does not exist", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance const nonExistentSessionID = "ses_nonexistent123" - // #when const app = Server.Default().app - const response = await app.request("/tui/select-session", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ sessionID: nonExistentSessionID }), - }) + const response = yield* Effect.promise(() => + Promise.resolve( + app.request("/tui/select-session", { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-opencode-directory": tmp.directory, + }, + body: JSON.stringify({ sessionID: nonExistentSessionID }), + }), + ), + ) - // #then expect(response.status).toBe(404) - }, - }) - }) + }), + { git: true }, + ) - test("should return 400 when session ID format is invalid", async () => { - await using tmp = await tmpdir({ git: true }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - // #given + it.instance( + "should return 400 when session ID format is invalid", + () => + Effect.gen(function* () { + const tmp = yield* TestInstance const invalidSessionID = "invalid_session_id" - // #when const app = Server.Default().app - const response = await app.request("/tui/select-session", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ sessionID: invalidSessionID }), - }) + const response = yield* Effect.promise(() => + Promise.resolve( + app.request("/tui/select-session", { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-opencode-directory": tmp.directory, + }, + body: JSON.stringify({ sessionID: invalidSessionID }), + }), + ), + ) - // #then expect(response.status).toBe(400) - }, - }) - }) + }), + { git: true }, + ) }) diff --git a/packages/opencode/test/server/worktree-endpoint-repro.test.ts b/packages/opencode/test/server/worktree-endpoint-repro.test.ts index e95d706d54..a1f6bf45a8 100644 --- a/packages/opencode/test/server/worktree-endpoint-repro.test.ts +++ b/packages/opencode/test/server/worktree-endpoint-repro.test.ts @@ -1,13 +1,14 @@ import { describe, expect } from "bun:test" -import { Effect, Layer } from "effect" +import { Effect, Layer, Queue } from "effect" import { HttpRouter } from "effect/unstable/http" import { Flag } from "@opencode-ai/core/flag/flag" +import { GlobalBus, type GlobalEvent } from "@/bus/global" +import { Worktree } from "@/worktree" import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" import { ExperimentalPaths } from "../../src/server/routes/instance/httpapi/groups/experimental" import { WorkspacePaths } from "../../src/server/routes/instance/httpapi/groups/workspace" -import { withTimeout } from "../../src/util/timeout" import { resetDatabase } from "../fixture/db" -import { TestInstance } from "../fixture/fixture" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" const stateLayer = Layer.effectDiscard( @@ -28,7 +29,10 @@ const stateLayer = Layer.effectDiscard( ) const it = testEffect(stateLayer) +const worktreeTest = process.platform === "win32" ? it.instance.skip : it.instance type TestServer = ReturnType +type CreatedWorktree = { directory: string } +type ScopedWorktree = { directory: string; body: CreatedWorktree; ready: Effect.Effect } function serverScoped() { return Effect.acquireRelease( @@ -44,14 +48,106 @@ function request(server: TestServer, input: string, init?: RequestInit) { } function withRequestTimeout(effect: Effect.Effect, label: string, ms = 5_000) { - return Effect.promise(() => withTimeout(Effect.runPromise(effect), ms, label)) + return effect.pipe( + Effect.timeoutOrElse({ + duration: `${ms} millis`, + orElse: () => Effect.fail(new Error(`${label} timed out after ${ms}ms`)), + }), + ) +} + +function json(response: Response) { + return Effect.promise(() => response.json() as Promise) +} + +function readyWatcher() { + return Effect.gen(function* () { + const events = yield* Queue.bounded(1) + const on = (event: GlobalEvent) => { + if (event.payload.type === Worktree.Event.Ready.type) Queue.offerUnsafe(events, event) + } + + GlobalBus.on("event", on) + yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", on))) + + return (directory: string) => + Effect.gen(function* () { + while (true) { + const event = yield* Queue.take(events) + if (event.directory === directory) return + } + }).pipe( + Effect.timeoutOrElse({ + duration: "10 seconds", + orElse: () => Effect.fail(new Error(`timed out waiting for worktree.ready: ${directory}`)), + }), + ) + }) +} + +function removeCreatedWorktree(input: { + server: TestServer + rootDirectory: string + worktreeDirectory: string + ready: Effect.Effect +}) { + return Effect.gen(function* () { + yield* input.ready.pipe(Effect.timeout("1 second"), Effect.ignore) + yield* Effect.promise(() => disposeAllInstances()).pipe(Effect.ignore) + + const removed = yield* request( + input.server, + `${ExperimentalPaths.worktree}?directory=${encodeURIComponent(input.rootDirectory)}`, + { + method: "DELETE", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ directory: input.worktreeDirectory }), + }, + ) + if (removed.status !== 200) { + const message = yield* Effect.promise(() => removed.text()) + throw new Error(`failed to remove worktree: ${removed.status} ${message}`) + } + const ok = yield* json(removed) + if (!ok) throw new Error(`failed to remove worktree ${input.worktreeDirectory}`) + }) +} + +function createWorktreeScoped(input: { + server: TestServer + directory: string + path: string + init: RequestInit + timeoutLabel: string + timeoutMs?: number +}) { + return Effect.acquireRelease( + Effect.gen(function* () { + const waitReady = yield* readyWatcher() + const response = yield* withRequestTimeout( + request(input.server, input.path, input.init), + input.timeoutLabel, + input.timeoutMs, + ) + expect(response.status).toBe(200) + const body = yield* json(response) + return { directory: body.directory, body, ready: waitReady(body.directory) } satisfies ScopedWorktree + }), + (created) => + removeCreatedWorktree({ + server: input.server, + rootDirectory: input.directory, + worktreeDirectory: created.directory, + ready: created.ready, + }).pipe(Effect.orDie), + ).pipe(Effect.map((created) => created.body)) } function setProjectStartCommand(input: { server: TestServer; directory: string; command: string }) { return Effect.gen(function* () { const current = yield* request(input.server, `/project/current?directory=${encodeURIComponent(input.directory)}`) expect(current.status).toBe(200) - const project = (yield* Effect.promise(() => current.json())) as { id: string } + const project = yield* json<{ id: string }>(current) const updated = yield* request( input.server, `/project/${project.id}?directory=${encodeURIComponent(input.directory)}`, @@ -66,47 +162,51 @@ function setProjectStartCommand(input: { server: TestServer; directory: string; } describe("worktree endpoint reproduction", () => { - it.instance( + worktreeTest( "direct HttpApi worktree create returns without waiting for boot", () => Effect.gen(function* () { const test = yield* TestInstance const server = yield* serverScoped() - const response = yield* withRequestTimeout( - request(server, `${ExperimentalPaths.worktree}?directory=${encodeURIComponent(test.directory)}`, { + const response = yield* createWorktreeScoped({ + server, + directory: test.directory, + path: `${ExperimentalPaths.worktree}?directory=${encodeURIComponent(test.directory)}`, + init: { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({}), - }), - "direct worktree create", - ) + }, + timeoutLabel: "direct worktree create", + }) - expect(response.status).toBe(200) - expect(yield* Effect.promise(() => response.json())).toMatchObject({ directory: expect.any(String) }) + expect(response).toMatchObject({ directory: expect.any(String) }) }), { git: true }, ) - it.instance( + worktreeTest( "workspace worktree create does not hang", () => Effect.gen(function* () { const test = yield* TestInstance const server = yield* serverScoped() - const response = yield* withRequestTimeout( - request(server, `${WorkspacePaths.list}?directory=${encodeURIComponent(test.directory)}`, { + const response = yield* createWorktreeScoped({ + server, + directory: test.directory, + path: `${WorkspacePaths.list}?directory=${encodeURIComponent(test.directory)}`, + init: { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ type: "worktree", branch: null }), - }), - "workspace worktree create", - 8_000, - ) + }, + timeoutLabel: "workspace worktree create", + timeoutMs: 8_000, + }) - expect(response.status).toBe(200) - expect(yield* Effect.promise(() => response.json())).toMatchObject({ + expect(response).toMatchObject({ type: "worktree", directory: expect.any(String), }) @@ -114,7 +214,7 @@ describe("worktree endpoint reproduction", () => { { git: true }, ) - it.instance( + worktreeTest( "workspace worktree create returns without waiting for project start command", () => Effect.gen(function* () { @@ -127,17 +227,19 @@ describe("worktree endpoint reproduction", () => { }) const started = Date.now() - const response = yield* withRequestTimeout( - request(server, `${WorkspacePaths.list}?directory=${encodeURIComponent(test.directory)}`, { + yield* createWorktreeScoped({ + server, + directory: test.directory, + path: `${WorkspacePaths.list}?directory=${encodeURIComponent(test.directory)}`, + init: { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ type: "worktree", branch: null }), - }), - "workspace worktree create with project start command", - 6_000, - ) + }, + timeoutLabel: "workspace worktree create with project start command", + timeoutMs: 6_000, + }) - expect(response.status).toBe(200) expect(Date.now() - started).toBeLessThan(1_500) }), { git: true }, diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index c7f349d5ce..d8a4167902 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -28,6 +28,7 @@ import { testEffect } from "../lib/effect" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { TestConfig } from "../fixture/config" import { SyncEvent } from "@/sync" +import { RuntimeFlags } from "@/effect/runtime-flags" void Log.init({ print: false }) @@ -225,6 +226,7 @@ const deps = Layer.mergeAll( Bus.layer, Config.defaultLayer, SyncEvent.defaultLayer, + RuntimeFlags.layer({ experimentalEventSystem: true }), ) const env = Layer.mergeAll( @@ -257,6 +259,7 @@ function compactionProcessLayer(options?: CompactionProcessOptions) { ? SessionProcessorModule.SessionProcessor.layer.pipe( Layer.provide(summary), Layer.provide(Image.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), Layer.provide(status), ) : layer(options?.result ?? "continue") @@ -272,6 +275,7 @@ function compactionProcessLayer(options?: CompactionProcessOptions) { Layer.provide(bus), Layer.provide(options?.config ?? Config.defaultLayer), Layer.provide(SyncEvent.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), ) } @@ -926,12 +930,12 @@ describe("session.compaction.process", () => { ) itCompaction.instance( - "does not persist tail_start_id for serialized recent turns", + "persists tail_start_id for retained recent turns", Effect.gen(function* () { const ssn = yield* SessionNs.Service const session = yield* ssn.create({}) yield* createUserMessage(session.id, "first") - yield* createUserMessage(session.id, "second") + const keep = yield* createUserMessage(session.id, "second") yield* createUserMessage(session.id, "third") yield* createSummaryCompaction(session.id) @@ -947,18 +951,18 @@ describe("session.compaction.process", () => { const part = yield* readCompactionPart(session.id) expect(part?.type).toBe("compaction") - expect(part?.tail_start_id).toBeUndefined() + expect(part?.tail_start_id).toBe(keep.id) }).pipe(withCompaction({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 10_000 }) })), ) itCompaction.instance( - "does not persist tail_start_id when shrinking serialized tail", + "shrinks retained tail to fit preserve token budget", Effect.gen(function* () { const ssn = yield* SessionNs.Service const session = yield* ssn.create({}) yield* createUserMessage(session.id, "first") yield* createUserMessage(session.id, "x".repeat(2_000)) - yield* createUserMessage(session.id, "tiny") + const keep = yield* createUserMessage(session.id, "tiny") yield* createSummaryCompaction(session.id) const msgs = yield* ssn.messages({ sessionID: session.id }) @@ -973,7 +977,7 @@ describe("session.compaction.process", () => { const part = yield* readCompactionPart(session.id) expect(part?.type).toBe("compaction") - expect(part?.tail_start_id).toBeUndefined() + expect(part?.tail_start_id).toBe(keep.id) }).pipe(withCompaction({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 100 }) })), ) @@ -1005,7 +1009,7 @@ describe("session.compaction.process", () => { ) itCompaction.instance( - "serializes retained tail media as text in the summary input", + "falls back to full summary when retained tail media exceeds preserve token budget", () => { const stub = llm() let captured = "" @@ -1078,16 +1082,15 @@ describe("session.compaction.process", () => { const part = yield* readCompactionPart(session.id) expect(part?.type).toBe("compaction") - expect(part?.tail_start_id).toBeUndefined() + expect(part?.tail_start_id).toBe(keep.id) expect(captured).toContain("zzzz") - expect(captured).toContain("keep tail") + expect(captured).not.toContain("keep tail") const filtered = MessageV2.filterCompacted(MessageV2.stream(session.id)) - expect(filtered.map((msg) => msg.info.id)).toEqual([parent!, expect.any(String)]) + expect(filtered.map((msg) => msg.info.id).slice(0, 3)).toEqual([parent!, expect.any(String), keep.id]) expect(filtered[1]?.info.role).toBe("assistant") expect(filtered[1]?.info.role === "assistant" ? filtered[1].info.summary : false).toBe(true) expect(filtered.map((msg) => msg.info.id)).not.toContain(large.id) - expect(filtered.map((msg) => msg.info.id)).not.toContain(keep.id) }).pipe(withCompaction({ llm: stub.layer, config: cfg({ tail_turns: 1, preserve_recent_tokens: 100 }) })) }, { git: true }, @@ -1354,13 +1357,13 @@ describe("session.compaction.process", () => { ) itCompaction.instance( - "summarizes the head while serializing recent tail into summary input", + "summarizes only the head while keeping recent tail out of summary input", () => { const stub = llm() - let captured: LLM.StreamInput["messages"] = [] + let captured = "" stub.push( reply("summary", (input) => { - captured = input.messages + captured = JSON.stringify(input.messages) }), ) return Effect.gen(function* () { @@ -1381,15 +1384,10 @@ describe("session.compaction.process", () => { auto: false, }) - const head = JSON.stringify(captured.slice(0, -1)) - const prompt = JSON.stringify(captured.at(-1)) - expect(head).toContain("older context") - expect(head).not.toContain("keep this turn") - expect(head).not.toContain("and this one too") - expect(prompt).toContain("keep this turn") - expect(prompt).toContain("and this one too") - expect(prompt).toContain("recent-conversation-tail") - expect(prompt).not.toContain("What did we do so far?") + expect(captured).toContain("older context") + expect(captured).not.toContain("keep this turn") + expect(captured).not.toContain("and this one too") + expect(captured).not.toContain("What did we do so far?") }).pipe(withCompaction({ llm: stub.layer })) }, { git: true }, @@ -1437,7 +1435,7 @@ describe("session.compaction.process", () => { { git: true }, ) - itCompaction.instance("does not replay recent pre-compaction turns across repeated compactions", () => { + itCompaction.instance("keeps recent pre-compaction turns across repeated compactions", () => { const stub = llm() stub.push(reply("summary one")) stub.push(reply("summary two")) @@ -1468,8 +1466,8 @@ describe("session.compaction.process", () => { expect(ids).not.toContain(u1.id) expect(ids).not.toContain(u2.id) - expect(ids).not.toContain(u3.id) - expect(ids).not.toContain(u4.id) + expect(ids).toContain(u3.id) + expect(ids).toContain(u4.id) expect(filtered.some((msg) => msg.info.role === "assistant" && msg.info.summary)).toBe(true) expect( filtered.some((msg) => msg.info.role === "user" && msg.parts.some((part) => part.type === "compaction")), @@ -1478,7 +1476,7 @@ describe("session.compaction.process", () => { }) itCompaction.instance( - "ignores previous summaries when sizing the serialized tail", + "ignores previous summaries when sizing the retained tail", Effect.gen(function* () { const ssn = yield* SessionNs.Service const test = yield* TestInstance @@ -1517,7 +1515,7 @@ describe("session.compaction.process", () => { const part = yield* readCompactionPart(session.id) expect(part?.type).toBe("compaction") - expect(part?.tail_start_id).toBeUndefined() + expect(part?.tail_start_id).toBe(keep.id) }).pipe(withCompaction({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 500 }) })), ) }) @@ -1764,6 +1762,101 @@ describe("SessionNs.getUsage", () => { expect(result.cost).toBe(3 + 1.5) }) + test("uses matching context cost tier before over-200k fallback", () => { + const model = createModel({ + context: 1_000_000, + output: 32_000, + cost: { + input: 1, + output: 2, + cache: { read: 0.1, write: 0.5 }, + tiers: [ + { + input: 3, + output: 4, + cache: { read: 0.3, write: 1.5 }, + tier: { type: "context", size: 200_000 }, + }, + { + input: 5, + output: 6, + cache: { read: 0.5, write: 2.5 }, + tier: { type: "context", size: 500_000 }, + }, + ], + experimentalOver200K: { + input: 100, + output: 100, + cache: { read: 100, write: 100 }, + }, + }, + }) + const result = SessionNs.getUsage({ + model, + usage: { + inputTokens: 650_000, + outputTokens: 100_000, + totalTokens: 750_000, + inputTokenDetails: { + noCacheTokens: undefined, + cacheReadTokens: 100_000, + cacheWriteTokens: undefined, + }, + outputTokenDetails: { + textTokens: undefined, + reasoningTokens: undefined, + }, + }, + }) + + expect(result.tokens.input).toBe(550_000) + expect(result.cost).toBe(2.75 + 0.6 + 0.05) + }) + + test("falls back to over-200k pricing when no cost tier matches", () => { + const model = createModel({ + context: 1_000_000, + output: 32_000, + cost: { + input: 1, + output: 2, + cache: { read: 0.1, write: 0.5 }, + tiers: [ + { + input: 5, + output: 6, + cache: { read: 0.5, write: 2.5 }, + tier: { type: "context", size: 500_000 }, + }, + ], + experimentalOver200K: { + input: 3, + output: 4, + cache: { read: 0.3, write: 1.5 }, + }, + }, + }) + const result = SessionNs.getUsage({ + model, + usage: { + inputTokens: 300_000, + outputTokens: 100_000, + totalTokens: 400_000, + inputTokenDetails: { + noCacheTokens: undefined, + cacheReadTokens: undefined, + cacheWriteTokens: undefined, + }, + outputTokenDetails: { + textTokens: undefined, + reasoningTokens: undefined, + }, + }, + }) + + expect(result.cost).toBe(0.9 + 0.4) + }) + test.each(["@ai-sdk/anthropic", "@ai-sdk/amazon-bedrock", "@ai-sdk/google-vertex/anthropic"])( "computes total from components for %s models", (npm) => { diff --git a/packages/opencode/test/session/llm.test.ts b/packages/opencode/test/session/llm.test.ts index 2879d04812..4a6b1e8b7f 100644 --- a/packages/opencode/test/session/llm.test.ts +++ b/packages/opencode/test/session/llm.test.ts @@ -277,6 +277,25 @@ async function loadFixture(providerID: string, modelID: string) { return { provider, model } } +function configModel(model: ModelsDev.Model) { + return { + id: model.id, + name: model.name, + family: model.family, + release_date: model.release_date, + attachment: model.attachment, + reasoning: model.reasoning, + temperature: model.temperature, + tool_call: model.tool_call, + interleaved: model.interleaved, + cost: model.cost ? { ...model.cost, tiers: undefined } : undefined, + limit: model.limit, + modalities: model.modalities, + status: model.status, + provider: model.provider, + } +} + function createEventStream(chunks: unknown[], includeDone = false) { const lines = chunks.map((chunk) => `data: ${typeof chunk === "string" ? chunk : JSON.stringify(chunk)}`) if (includeDone) { @@ -617,7 +636,7 @@ describe("session.llm.stream", () => { npm: "@ai-sdk/openai", api: "https://api.openai.com/v1", models: { - [model.id]: model, + [model.id]: configModel(model), }, options: { apiKey: "test-openai-key", @@ -733,7 +752,7 @@ describe("session.llm.stream", () => { npm: "@ai-sdk/openai", api: "https://api.openai.com/v1", models: { - [model.id]: model, + [model.id]: configModel(model), }, options: { apiKey: "test-openai-key", @@ -970,7 +989,7 @@ describe("session.llm.stream", () => { npm: "@ai-sdk/anthropic", api: "https://api.anthropic.com/v1", models: { - [model.id]: model, + [model.id]: configModel(model), }, options: { apiKey: "test-anthropic-key", diff --git a/packages/opencode/test/session/messages-pagination.test.ts b/packages/opencode/test/session/messages-pagination.test.ts index e1714a9015..e558d07b50 100644 --- a/packages/opencode/test/session/messages-pagination.test.ts +++ b/packages/opencode/test/session/messages-pagination.test.ts @@ -1,9 +1,10 @@ import { describe, expect, test } from "bun:test" -import { Effect } from "effect" +import { Effect, Option } from "effect" import { Session as SessionNs } from "@/session/session" import { MessageV2 } from "../../src/session/message-v2" import { MessageID, PartID, type SessionID } from "../../src/session/schema" import { ModelID, ProviderID } from "../../src/provider/schema" +import { NotFoundError } from "@/storage/storage" import * as Log from "@opencode-ai/core/util/log" import { testEffect } from "../lib/effect" @@ -125,12 +126,12 @@ const addCompactionPart = Effect.fn("Test.addCompactionPart")(function* ( }) describe("MessageV2.page", () => { - it.instance("returns sync result", () => + it.instance("returns page result", () => withSession(({ sessionID }) => Effect.gen(function* () { yield* fill(sessionID, 2) - const result = MessageV2.page({ sessionID, limit: 10 }) + const result = yield* MessageV2.page({ sessionID, limit: 10 }) expect(result).toBeDefined() expect(result.items).toBeArray() }), @@ -142,18 +143,18 @@ describe("MessageV2.page", () => { Effect.gen(function* () { const ids = yield* fill(sessionID, 6) - const a = MessageV2.page({ sessionID, limit: 2 }) + const a = yield* MessageV2.page({ sessionID, limit: 2 }) expect(a.items.map((item) => item.info.id)).toEqual(ids.slice(-2)) expect(a.items.every((item) => item.parts.length === 1)).toBe(true) expect(a.more).toBe(true) expect(a.cursor).toBeTruthy() - const b = MessageV2.page({ sessionID, limit: 2, before: a.cursor! }) + const b = yield* MessageV2.page({ sessionID, limit: 2, before: a.cursor! }) expect(b.items.map((item) => item.info.id)).toEqual(ids.slice(-4, -2)) expect(b.more).toBe(true) expect(b.cursor).toBeTruthy() - const c = MessageV2.page({ sessionID, limit: 2, before: b.cursor! }) + const c = yield* MessageV2.page({ sessionID, limit: 2, before: b.cursor! }) expect(c.items.map((item) => item.info.id)).toEqual(ids.slice(0, 2)) expect(c.more).toBe(false) expect(c.cursor).toBeUndefined() @@ -166,7 +167,7 @@ describe("MessageV2.page", () => { Effect.gen(function* () { const ids = yield* fill(sessionID, 4) - const result = MessageV2.page({ sessionID, limit: 4 }) + const result = yield* MessageV2.page({ sessionID, limit: 4 }) expect(result.items.map((item) => item.info.id)).toEqual(ids) }), ), @@ -175,7 +176,7 @@ describe("MessageV2.page", () => { it.instance("returns empty items for session with no messages", () => withSession(({ sessionID }) => Effect.gen(function* () { - const result = MessageV2.page({ sessionID, limit: 10 }) + const result = yield* MessageV2.page({ sessionID, limit: 10 }) expect(result.items).toEqual([]) expect(result.more).toBe(false) expect(result.cursor).toBeUndefined() @@ -183,10 +184,12 @@ describe("MessageV2.page", () => { ), ) - it.instance("throws NotFoundError for non-existent session", () => + it.instance("fails with NotFoundError for non-existent session", () => Effect.gen(function* () { const fake = "non-existent-session" as SessionID - expect(() => MessageV2.page({ sessionID: fake, limit: 10 })).toThrow("NotFoundError") + const error = yield* Effect.flip(MessageV2.page({ sessionID: fake, limit: 10 })) + expect(error).toBeInstanceOf(NotFoundError) + expect(error.message).toBe(`Session not found: ${fake}`) }), ) @@ -195,7 +198,7 @@ describe("MessageV2.page", () => { Effect.gen(function* () { const ids = yield* fill(sessionID, 3) - const result = MessageV2.page({ sessionID, limit: 3 }) + const result = yield* MessageV2.page({ sessionID, limit: 3 }) expect(result.items.map((item) => item.info.id)).toEqual(ids) expect(result.more).toBe(false) expect(result.cursor).toBeUndefined() @@ -208,7 +211,7 @@ describe("MessageV2.page", () => { Effect.gen(function* () { const ids = yield* fill(sessionID, 5) - const result = MessageV2.page({ sessionID, limit: 1 }) + const result = yield* MessageV2.page({ sessionID, limit: 1 }) expect(result.items).toHaveLength(1) expect(result.items[0].info.id).toBe(ids[ids.length - 1]) expect(result.more).toBe(true) @@ -229,7 +232,7 @@ describe("MessageV2.page", () => { text: "extra", }) - const result = MessageV2.page({ sessionID, limit: 10 }) + const result = yield* MessageV2.page({ sessionID, limit: 10 }) expect(result.items).toHaveLength(1) expect(result.items[0].parts).toHaveLength(2) }), @@ -241,8 +244,8 @@ describe("MessageV2.page", () => { Effect.gen(function* () { const ids = yield* fill(sessionID, 4, (i: number) => 1000.5 + i) - const a = MessageV2.page({ sessionID, limit: 2 }) - const b = MessageV2.page({ sessionID, limit: 2, before: a.cursor! }) + const a = yield* MessageV2.page({ sessionID, limit: 2 }) + const b = yield* MessageV2.page({ sessionID, limit: 2, before: a.cursor! }) expect(a.items.map((item) => item.info.id)).toEqual(ids.slice(-2)) expect(b.items.map((item) => item.info.id)).toEqual(ids.slice(0, 2)) @@ -255,11 +258,11 @@ describe("MessageV2.page", () => { Effect.gen(function* () { const ids = yield* fill(sessionID, 4, () => 1000) - const a = MessageV2.page({ sessionID, limit: 2 }) + const a = yield* MessageV2.page({ sessionID, limit: 2 }) expect(a.items.map((item) => item.info.id)).toEqual(ids.slice(-2)) expect(a.more).toBe(true) - const b = MessageV2.page({ sessionID, limit: 2, before: a.cursor! }) + const b = yield* MessageV2.page({ sessionID, limit: 2, before: a.cursor! }) expect(b.items.map((item) => item.info.id)).toEqual(ids.slice(0, 2)) expect(b.more).toBe(false) }), @@ -274,8 +277,8 @@ describe("MessageV2.page", () => { yield* fill(a.id, 3) yield* fill(b.id, 2) - const resultA = MessageV2.page({ sessionID: a.id, limit: 10 }) - const resultB = MessageV2.page({ sessionID: b.id, limit: 10 }) + const resultA = yield* MessageV2.page({ sessionID: a.id, limit: 10 }) + const resultB = yield* MessageV2.page({ sessionID: b.id, limit: 10 }) expect(resultA.items).toHaveLength(3) expect(resultB.items).toHaveLength(2) expect(resultA.items.every((item) => item.info.sessionID === a.id)).toBe(true) @@ -291,7 +294,7 @@ describe("MessageV2.page", () => { Effect.gen(function* () { const ids = yield* fill(sessionID, 10) - const result = MessageV2.page({ sessionID, limit: 100 }) + const result = yield* MessageV2.page({ sessionID, limit: 100 }) expect(result.items).toHaveLength(10) expect(result.items.map((item) => item.info.id)).toEqual(ids) expect(result.more).toBe(false) @@ -458,7 +461,7 @@ describe("MessageV2.get", () => { Effect.gen(function* () { const [id] = yield* fill(sessionID, 1) - const result = MessageV2.get({ sessionID, messageID: id }) + const result = yield* MessageV2.get({ sessionID, messageID: id }) expect(result.info.id).toBe(id) expect(result.info.sessionID).toBe(sessionID) expect(result.info.role).toBe("user") @@ -468,10 +471,13 @@ describe("MessageV2.get", () => { ), ) - it.instance("throws NotFoundError for non-existent message", () => + it.instance("fails with NotFoundError for non-existent message", () => withSession(({ sessionID }) => Effect.gen(function* () { - expect(() => MessageV2.get({ sessionID, messageID: MessageID.ascending() })).toThrow("NotFoundError") + const messageID = MessageID.ascending() + const error = yield* Effect.flip(MessageV2.get({ sessionID, messageID })) + expect(error).toBeInstanceOf(NotFoundError) + expect(error.message).toBe(`Message not found: ${messageID}`) }), ), ) @@ -483,8 +489,10 @@ describe("MessageV2.get", () => { const b = yield* session.create({}) const [id] = yield* fill(a.id, 1) - expect(() => MessageV2.get({ sessionID: b.id, messageID: id })).toThrow("NotFoundError") - const result = MessageV2.get({ sessionID: a.id, messageID: id }) + const error = yield* Effect.flip(MessageV2.get({ sessionID: b.id, messageID: id })) + expect(error).toBeInstanceOf(NotFoundError) + expect(error.message).toBe(`Message not found: ${id}`) + const result = yield* MessageV2.get({ sessionID: a.id, messageID: id }) expect(result.info.id).toBe(id) yield* session.remove(a.id) @@ -505,7 +513,7 @@ describe("MessageV2.get", () => { text: "extra", }) - const result = MessageV2.get({ sessionID, messageID: id }) + const result = yield* MessageV2.get({ sessionID, messageID: id }) expect(result.parts).toHaveLength(2) }), ), @@ -525,7 +533,7 @@ describe("MessageV2.get", () => { text: "response", }) - const result = MessageV2.get({ sessionID, messageID: aid }) + const result = yield* MessageV2.get({ sessionID, messageID: aid }) expect(result.info.role).toBe("assistant") expect(result.parts).toHaveLength(1) expect((result.parts[0] as MessageV2.TextPart).text).toBe("response") @@ -538,7 +546,7 @@ describe("MessageV2.get", () => { Effect.gen(function* () { const id = yield* addUser(sessionID) - const result = MessageV2.get({ sessionID, messageID: id }) + const result = yield* MessageV2.get({ sessionID, messageID: id }) expect(result.info.id).toBe(id) expect(result.parts).toEqual([]) }), @@ -546,6 +554,50 @@ describe("MessageV2.get", () => { ) }) +describe("Session.messages", () => { + it.instance("returns all messages in chronological order across pages", () => + withSession(({ session, sessionID }) => + Effect.gen(function* () { + const ids = yield* fill(sessionID, 55) + const result = yield* session.messages({ sessionID }) + expect(result.map((item) => item.info.id)).toEqual(ids) + }), + ), + ) + + it.instance("fails with NotFoundError for non-existent session", () => + Effect.gen(function* () { + const session = yield* SessionNs.Service + const fake = "non-existent-session" as SessionID + const error = yield* Effect.flip(session.messages({ sessionID: fake })) + expect(error).toBeInstanceOf(NotFoundError) + expect(error.message).toBe(`Session not found: ${fake}`) + }), + ) +}) + +describe("Session.findMessage", () => { + it.instance("searches newest-first", () => + withSession(({ session, sessionID }) => + Effect.gen(function* () { + const ids = yield* fill(sessionID, 3) + const result = yield* session.findMessage(sessionID, () => true) + expect(Option.isSome(result) ? result.value.info.id : undefined).toBe(ids.at(-1)) + }), + ), + ) + + it.instance("fails with NotFoundError for non-existent session", () => + Effect.gen(function* () { + const session = yield* SessionNs.Service + const fake = "non-existent-session" as SessionID + const error = yield* Effect.flip(session.findMessage(fake, () => true)) + expect(error).toBeInstanceOf(NotFoundError) + expect(error.message).toBe(`Session not found: ${fake}`) + }), + ) +}) + describe("MessageV2.filterCompacted", () => { it.instance("returns all messages when no compaction", () => withSession(({ sessionID }) => @@ -650,7 +702,7 @@ describe("MessageV2.filterCompacted", () => { ), ) - it.instance("ignores original tail when compaction stores tail_start_id", () => + it.instance("retains original tail when compaction stores tail_start_id", () => withSession(({ session, sessionID }) => Effect.gen(function* () { const u1 = yield* addUser(sessionID, "first") @@ -696,12 +748,12 @@ describe("MessageV2.filterCompacted", () => { const result = MessageV2.filterCompacted(MessageV2.stream(sessionID)) - expect(result.map((item) => item.info.id)).toEqual([c1, s1, u3, a3]) + expect(result.map((item) => item.info.id)).toEqual([c1, s1, u2, a2, u3, a3]) }), ), ) - it.instance("fork keeps legacy tail_start_id without replaying the tail", () => + it.instance("fork remaps compaction tail_start_id for filterCompacted", () => Effect.gen(function* () { const session = yield* SessionNs.Service const created = yield* session.create({}) @@ -748,7 +800,7 @@ describe("MessageV2.filterCompacted", () => { }) const parentFiltered = MessageV2.filterCompacted(MessageV2.stream(created.id)) - expect(parentFiltered.map((item) => item.info.id)).toEqual([c1, s1, u3, a3]) + expect(parentFiltered.map((item) => item.info.id)).toEqual([c1, s1, u2, a2, u3, a3]) const forked = yield* session.fork({ sessionID: created.id }) const childFiltered = MessageV2.filterCompacted(MessageV2.stream(forked.id)) @@ -758,14 +810,14 @@ describe("MessageV2.filterCompacted", () => { expect(tailPart?.type).toBe("compaction") if (!tailPart || tailPart.type !== "compaction") throw new Error("Expected forked compaction part") expect(tailPart.tail_start_id).toBeDefined() - expect(childFiltered.some((m) => m.info.id === tailPart.tail_start_id)).toBe(false) + expect(childFiltered.some((m) => m.info.id === tailPart.tail_start_id)).toBe(true) yield* session.remove(forked.id) yield* session.remove(created.id) }), ) - it.instance("does not replay an assistant tail when compaction starts inside a turn", () => + it.instance("retains an assistant tail when compaction starts inside a turn", () => withSession(({ session, sessionID }) => Effect.gen(function* () { const u1 = yield* addUser(sessionID, "first") @@ -819,7 +871,7 @@ describe("MessageV2.filterCompacted", () => { const result = MessageV2.filterCompacted(MessageV2.stream(sessionID)) - expect(result.map((item) => item.info.id)).toEqual([c1, s1, u3, a4]) + expect(result.map((item) => item.info.id)).toEqual([c1, s1, a3, u3, a4]) }), ), ) @@ -891,7 +943,7 @@ describe("MessageV2.filterCompacted", () => { const result = MessageV2.filterCompacted(MessageV2.stream(sessionID)) - expect(result.map((item) => item.info.id)).toEqual([c2, s2, u4, a4]) + expect(result.map((item) => item.info.id)).toEqual([c2, s2, u3, a3, u4, a4]) }), ), ) @@ -946,9 +998,9 @@ describe("MessageV2 consistency", () => { Effect.gen(function* () { yield* fill(sessionID, 3) - const paged = MessageV2.page({ sessionID, limit: 10 }) + const paged = yield* MessageV2.page({ sessionID, limit: 10 }) for (const item of paged.items) { - const got = MessageV2.get({ sessionID, messageID: item.info.id as MessageID }) + const got = yield* MessageV2.get({ sessionID, messageID: item.info.id as MessageID }) expect(got.info).toEqual(item.info) expect(got.parts).toEqual(item.parts) } @@ -961,7 +1013,7 @@ describe("MessageV2 consistency", () => { Effect.gen(function* () { const [id] = yield* fill(sessionID, 1) - const got = MessageV2.get({ sessionID, messageID: id }) + const got = yield* MessageV2.get({ sessionID, messageID: id }) const standalone = MessageV2.parts(id) expect(got.parts).toEqual(standalone) }), @@ -978,7 +1030,7 @@ describe("MessageV2 consistency", () => { const paged = [] as MessageV2.WithParts[] let cursor: string | undefined while (true) { - const result = MessageV2.page({ sessionID, limit: 3, before: cursor }) + const result = yield* MessageV2.page({ sessionID, limit: 3, before: cursor }) for (let i = result.items.length - 1; i >= 0; i--) { paged.push(result.items[i]) } diff --git a/packages/opencode/test/session/processor-effect.test.ts b/packages/opencode/test/session/processor-effect.test.ts index 56ff102430..61c566eaec 100644 --- a/packages/opencode/test/session/processor-effect.test.ts +++ b/packages/opencode/test/session/processor-effect.test.ts @@ -25,6 +25,7 @@ import { provideTmpdirServer } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { raw, reply, TestLLMServer } from "../lib/llm-server" import { SyncEvent } from "@/sync" +import { RuntimeFlags } from "@/effect/runtime-flags" void Log.init({ print: false }) @@ -104,6 +105,17 @@ function defer() { return { promise, resolve } } +const waitFor = (check: Effect.Effect, message: string) => + Effect.gen(function* () { + const stop = Date.now() + 500 + while (Date.now() < stop) { + const value = yield* check + if (value !== undefined) return value + yield* Effect.sleep("10 millis") + } + return yield* Effect.fail(new Error(message)) + }) + const user = Effect.fn("TestSession.user")(function* (sessionID: SessionID, text: string) { const session = yield* Session.Service const msg = yield* session.updateMessage({ @@ -171,7 +183,12 @@ const deps = Layer.mergeAll( ).pipe(Layer.provideMerge(infra)) const env = Layer.mergeAll( TestLLMServer.layer, - SessionProcessor.layer.pipe(Layer.provide(summary), Layer.provide(Image.defaultLayer), Layer.provideMerge(deps)), + SessionProcessor.layer.pipe( + Layer.provide(summary), + Layer.provide(Image.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), + Layer.provideMerge(deps), + ), ) const it = testEffect(env) @@ -295,15 +312,10 @@ it.live("session.processor effect tests preserve text start time", () => }) .pipe(Effect.forkChild) - yield* Effect.promise(async () => { - const stop = Date.now() + 500 - while (Date.now() < stop) { - const text = MessageV2.parts(msg.id).find((part): part is MessageV2.TextPart => part.type === "text") - if (text?.time?.start) return - await Bun.sleep(10) - } - throw new Error("timed out waiting for text part") - }) + yield* waitFor( + Effect.sync(() => MessageV2.parts(msg.id).find((part): part is MessageV2.TextPart => part.type === "text")), + "timed out waiting for text part", + ) yield* Effect.sleep("20 millis") gate.resolve() @@ -685,14 +697,10 @@ it.live("session.processor effect tests mark pending tools as aborted on cleanup .pipe(Effect.forkChild) yield* llm.wait(1) - yield* Effect.promise(async () => { - const end = Date.now() + 500 - while (Date.now() < end) { - const parts = await MessageV2.parts(msg.id) - if (parts.some((part) => part.type === "tool")) return - await Bun.sleep(10) - } - }) + yield* waitFor( + Effect.sync(() => MessageV2.parts(msg.id).find((part): part is MessageV2.ToolPart => part.type === "tool")), + "timed out waiting for tool part", + ) yield* Fiber.interrupt(run) const exit = yield* Fiber.await(run) @@ -767,7 +775,7 @@ it.live("session.processor effect tests record aborted errors and idle state", ( const exit = yield* Fiber.await(run) yield* Effect.promise(() => seen.promise) - const stored = MessageV2.get({ sessionID: chat.id, messageID: msg.id }) + const stored = yield* MessageV2.get({ sessionID: chat.id, messageID: msg.id }) const state = yield* sts.get(chat.id) off() @@ -829,7 +837,7 @@ it.live("session.processor effect tests mark interruptions aborted without manua yield* Fiber.interrupt(run) const exit = yield* Fiber.await(run) - const stored = MessageV2.get({ sessionID: chat.id, messageID: msg.id }) + const stored = yield* MessageV2.get({ sessionID: chat.id, messageID: msg.id }) const state = yield* sts.get(chat.id) expect(Exit.isFailure(exit)).toBe(true) diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts index 3821954945..c3d113d52f 100644 --- a/packages/opencode/test/session/prompt.test.ts +++ b/packages/opencode/test/session/prompt.test.ts @@ -1,8 +1,7 @@ import { NodeFileSystem } from "@effect/platform-node" import { FetchHttpClient } from "effect/unstable/http" import { expect } from "bun:test" -import { Cause, Effect, Exit, Fiber, Layer } from "effect" -import fs from "fs/promises" +import { Cause, Deferred, Duration, Effect, Exit, Fiber, Layer } from "effect" import path from "path" import { fileURLToPath, pathToFileURL } from "url" import { NamedError } from "@opencode-ai/core/util/error" @@ -48,10 +47,11 @@ import * as Database from "../../src/storage/db" import { Ripgrep } from "../../src/file/ripgrep" import { Format } from "../../src/format" import { Reference } from "../../src/reference/reference" -import { provideTmpdirInstance, provideTmpdirServer } from "../fixture/fixture" +import { TestInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { reply, TestLLMServer } from "../lib/llm-server" import { SyncEvent } from "@/sync" +import { RuntimeFlags } from "@/effect/runtime-flags" void Log.init({ print: false }) @@ -69,14 +69,6 @@ const ref = { modelID: ModelID.make("test-model"), } -function defer() { - let resolve!: (value: T | PromiseLike) => void - const promise = new Promise((done) => { - resolve = done - }) - return { promise, resolve } -} - function withSh(fx: () => Effect.Effect) { return Effect.acquireUseRelease( Effect.sync(() => { @@ -188,6 +180,7 @@ function makeHttp() { Layer.provide(Reference.defaultLayer), Layer.provide(Ripgrep.defaultLayer), Layer.provide(Format.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), Layer.provideMerge(todo), Layer.provideMerge(question), Layer.provideMerge(deps), @@ -196,9 +189,14 @@ function makeHttp() { const proc = SessionProcessor.layer.pipe( Layer.provide(summary), Layer.provide(Image.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), + Layer.provideMerge(deps), + ) + const compact = SessionCompaction.layer.pipe( + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), + Layer.provideMerge(proc), Layer.provideMerge(deps), ) - const compact = SessionCompaction.layer.pipe(Layer.provideMerge(proc), Layer.provideMerge(deps)) return Layer.mergeAll( TestLLMServer.layer, SessionPrompt.layer.pipe( @@ -213,13 +211,14 @@ function makeHttp() { Layer.provideMerge(trunc), Layer.provide(Instruction.defaultLayer), Layer.provide(SystemPrompt.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), Layer.provideMerge(deps), ), ).pipe(Layer.provide(summary)) } const it = testEffect(makeHttp()) -const unix = process.platform !== "win32" ? it.live : it.live.skip +const unix = process.platform !== "win32" ? it.instance : it.instance.skip // Config that registers a custom "test" provider with a "test-model" model // so provider model lookup succeeds inside the loop. @@ -268,6 +267,84 @@ function providerCfg(url: string) { } } +const writeText = Effect.fn("test.writeText")(function* (file: string, text: string) { + const fs = yield* AppFileSystem.Service + yield* fs.writeWithDirs(file, text) +}) + +const ensureDir = Effect.fn("test.ensureDir")(function* (dir: string) { + const fs = yield* AppFileSystem.Service + yield* fs.ensureDir(dir) +}) + +const writeConfig = Effect.fn("test.writeConfig")(function* (dir: string, config: Partial) { + yield* writeText( + path.join(dir, "opencode.json"), + JSON.stringify({ $schema: "https://opencode.ai/config.json", ...config }), + ) +}) + +const useServerConfig = Effect.fn("test.useServerConfig")(function* (config: (url: string) => Partial) { + const { directory: dir } = yield* TestInstance + const llm = yield* TestLLMServer + yield* writeConfig(dir, config(llm.url)) + return { dir, llm } +}) + +const awaitWithTimeout = ( + self: Effect.Effect, + message: string, + duration: Duration.Input = "2 seconds", +) => + self.pipe( + Effect.timeoutOrElse({ + duration, + orElse: () => Effect.fail(new Error(message)), + }), + ) + +const pollWithTimeout = ( + self: Effect.Effect, + message: string, + duration: Duration.Input = "5 seconds", +) => + Effect.gen(function* () { + while (true) { + const result = yield* self + if (result !== undefined) return result + yield* Effect.sleep("20 millis") + } + }).pipe( + Effect.timeoutOrElse({ + duration, + orElse: () => Effect.fail(new Error(message)), + }), + ) + +const hasBash = Effect.sync(() => Bun.which("bash") !== null) + +const deferredAsPromise = (deferred: Deferred.Deferred): PromiseLike => ({ + then: (onfulfilled, onrejected) => { + Effect.runFork( + Deferred.await(deferred).pipe( + Effect.match({ + onFailure: (error) => { + onrejected?.(error) + }, + onSuccess: (value) => { + onfulfilled?.(value) + }, + }), + ), + ) + return deferredAsPromise(deferred) as PromiseLike + }, +}) + +const succeedVoid = (deferred: Deferred.Deferred) => { + Effect.runSync(Deferred.succeed(deferred, void 0).pipe(Effect.ignore)) +} + const user = Effect.fn("test.user")(function* (sessionID: SessionID, text: string) { const session = yield* Session.Service const msg = yield* session.updateMessage({ @@ -344,9 +421,11 @@ const boot = Effect.fn("test.boot")(function* (input?: { title?: string }) { // Loop semantics -it.live("loop exits immediately when last assistant has stop finish", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { +it.instance( + "loop exits immediately when last assistant has stop finish", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const chat = yield* sessions.create({ title: "Pinned" }) @@ -357,13 +436,14 @@ it.live("loop exits immediately when last assistant has stop finish", () => if (result.info.role === "assistant") expect(result.info.finish).toBe("stop") expect(yield* llm.calls).toBe(0) }), - { git: true, config: providerCfg }, - ), + { git: true }, ) -it.live("loop calls LLM and returns assistant message", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { +it.instance( + "loop calls LLM and returns assistant message", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const chat = yield* sessions.create({ @@ -384,13 +464,14 @@ it.live("loop calls LLM and returns assistant message", () => expect(parts.some((p) => p.type === "text" && p.text === "world")).toBe(true) expect(yield* llm.hits).toHaveLength(1) }), - { git: true, config: providerCfg }, - ), + { git: true }, ) -it.live("prompt emits v2 prompted and synthetic events", () => - provideTmpdirServer( - Effect.fnUntraced(function* () { +it.instance( + "prompt emits v2 prompted and synthetic events", + () => + Effect.gen(function* () { + yield* useServerConfig(providerCfg) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const chat = yield* sessions.create({ title: "Pinned" }) @@ -425,13 +506,14 @@ it.live("prompt emits v2 prompted and synthetic events", () => ]), ) }), - { git: true, config: providerCfg }, - ), + { git: true }, ) -it.live("static loop returns assistant text through local provider", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { +it.instance( + "static loop returns assistant text through local provider", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const session = yield* sessions.create({ @@ -454,13 +536,14 @@ it.live("static loop returns assistant text through local provider", () => expect(yield* llm.hits).toHaveLength(1) expect(yield* llm.pending).toBe(0) }), - { git: true, config: providerCfg }, - ), + { git: true }, ) -it.live("static loop consumes queued replies across turns", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { +it.instance( + "static loop consumes queued replies across turns", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const session = yield* sessions.create({ @@ -497,13 +580,14 @@ it.live("static loop consumes queued replies across turns", () => expect(yield* llm.hits).toHaveLength(2) expect(yield* llm.pending).toBe(0) }), - { git: true, config: providerCfg }, - ), + { git: true }, ) -it.live("loop continues when finish is tool-calls", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { +it.instance( + "loop continues when finish is tool-calls", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const session = yield* sessions.create({ @@ -527,55 +611,56 @@ it.live("loop continues when finish is tool-calls", () => expect(result.info.finish).toBe("stop") } }), - { git: true, config: providerCfg }, - ), + { git: true }, ) -it.live("glob tool keeps instance context during prompt runs", () => - provideTmpdirServer( - ({ dir, llm }) => - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({ - title: "Glob context", - permission: [{ permission: "*", pattern: "*", action: "allow" }], - }) - const file = path.join(dir, "probe.txt") - yield* Effect.promise(() => Bun.write(file, "probe")) +it.instance( + "glob tool keeps instance context during prompt runs", + () => + Effect.gen(function* () { + const { dir, llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({ + title: "Glob context", + permission: [{ permission: "*", pattern: "*", action: "allow" }], + }) + const file = path.join(dir, "probe.txt") + yield* writeText(file, "probe") - yield* prompt.prompt({ - sessionID: session.id, - agent: "build", - noReply: true, - parts: [{ type: "text", text: "find text files" }], - }) - yield* llm.tool("glob", { pattern: "**/*.txt" }) - yield* llm.text("done") + yield* prompt.prompt({ + sessionID: session.id, + agent: "build", + noReply: true, + parts: [{ type: "text", text: "find text files" }], + }) + yield* llm.tool("glob", { pattern: "**/*.txt" }) + yield* llm.text("done") - const result = yield* prompt.loop({ sessionID: session.id }) - expect(result.info.role).toBe("assistant") + const result = yield* prompt.loop({ sessionID: session.id }) + expect(result.info.role).toBe("assistant") - const msgs = yield* MessageV2.filterCompactedEffect(session.id) - const tool = msgs - .flatMap((msg) => msg.parts) - .find( - (part): part is CompletedToolPart => - part.type === "tool" && part.tool === "glob" && part.state.status === "completed", - ) - if (!tool) return + const msgs = yield* MessageV2.filterCompactedEffect(session.id) + const tool = msgs + .flatMap((msg) => msg.parts) + .find( + (part): part is CompletedToolPart => + part.type === "tool" && part.tool === "glob" && part.state.status === "completed", + ) + if (!tool) return - expect(tool.state.output).toContain(file) - expect(tool.state.output).not.toContain("No context found for instance") - expect(result.parts.some((part) => part.type === "text" && part.text === "done")).toBe(true) - }), - { git: true, config: providerCfg }, - ), + expect(tool.state.output).toContain(file) + expect(tool.state.output).not.toContain("No context found for instance") + expect(result.parts.some((part) => part.type === "text" && part.text === "done")).toBe(true) + }), + { git: true }, ) -it.live("loop continues when finish is stop but assistant has tool parts", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { +it.instance( + "loop continues when finish is stop but assistant has tool parts", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const session = yield* sessions.create({ @@ -599,13 +684,21 @@ it.live("loop continues when finish is stop but assistant has tool parts", () => expect(result.info.finish).toBe("stop") } }), - { git: true, config: providerCfg }, - ), + { git: true }, ) -it.live("failed subtask preserves metadata on error tool state", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { +it.instance( + "failed subtask preserves metadata on error tool state", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig((url) => ({ + ...providerCfg(url), + agent: { + general: { + model: "test/missing-model", + }, + }, + })) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const chat = yield* sessions.create({ title: "Pinned" }) @@ -638,479 +731,897 @@ it.live("failed subtask preserves metadata on error tool state", () => modelID: ModelID.make("missing-model"), }) }), - { - git: true, - config: (url) => ({ - ...providerCfg(url), - agent: { - general: { - model: "test/missing-model", - }, - }, - }), - }, - ), + { git: true }, ) -it.live( +it.instance( "running subtask preserves metadata after tool-call transition", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Pinned" }) - yield* llm.hang - const msg = yield* user(chat.id, "hello") - yield* addSubtask(chat.id, msg.id) + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Pinned" }) + yield* llm.hang + const msg = yield* user(chat.id, "hello") + yield* addSubtask(chat.id, msg.id) - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - const tool = yield* Effect.promise(async () => { - const end = Date.now() + 5_000 - while (Date.now() < end) { - const msgs = await Effect.runPromise(MessageV2.filterCompactedEffect(chat.id)) - const taskMsg = msgs.find((item) => item.info.role === "assistant" && item.info.agent === "general") - const tool = taskMsg?.parts.find((part): part is MessageV2.ToolPart => part.type === "tool") - if (tool?.state.status === "running" && tool.state.metadata?.sessionId) return tool - await new Promise((done) => setTimeout(done, 20)) - } - throw new Error("timed out waiting for running subtask metadata") - }) + const tool = yield* pollWithTimeout( + Effect.gen(function* () { + const msgs = yield* MessageV2.filterCompactedEffect(chat.id) + const taskMsg = msgs.find((item) => item.info.role === "assistant" && item.info.agent === "general") + const tool = taskMsg?.parts.find((part): part is MessageV2.ToolPart => part.type === "tool") + if (tool?.state.status === "running" && tool.state.metadata?.sessionId) return tool + }), + "timed out waiting for running subtask metadata", + ) - if (tool.state.status !== "running") return - expect(typeof tool.state.metadata?.sessionId).toBe("string") - expect(tool.state.title).toBeDefined() - expect(tool.state.metadata?.model).toBeDefined() + if (tool.state.status !== "running") return + expect(typeof tool.state.metadata?.sessionId).toBe("string") + expect(tool.state.title).toBeDefined() + expect(tool.state.metadata?.model).toBeDefined() - yield* prompt.cancel(chat.id) - yield* Fiber.await(fiber) - }), - { git: true, config: providerCfg }, - ), + yield* prompt.cancel(chat.id) + yield* Fiber.await(fiber) + }), + { git: true }, 5_000, ) -it.live( +it.instance( "running task tool preserves metadata after tool-call transition", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ - title: "Pinned", - permission: [{ permission: "*", pattern: "*", action: "allow" }], - }) - yield* llm.tool("task", { - description: "inspect bug", - prompt: "look into the cache key path", - subagent_type: "general", - }) - yield* llm.hang - yield* user(chat.id, "hello") + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ + title: "Pinned", + permission: [{ permission: "*", pattern: "*", action: "allow" }], + }) + yield* llm.tool("task", { + description: "inspect bug", + prompt: "look into the cache key path", + subagent_type: "general", + }) + yield* llm.hang + yield* user(chat.id, "hello") - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - const tool = yield* Effect.promise(async () => { - const end = Date.now() + 5_000 - while (Date.now() < end) { - const msgs = await Effect.runPromise(MessageV2.filterCompactedEffect(chat.id)) - const assistant = msgs.findLast((item) => item.info.role === "assistant" && item.info.agent === "build") - const tool = assistant?.parts.find( - (part): part is MessageV2.ToolPart => part.type === "tool" && part.tool === "task", - ) - if (tool?.state.status === "running" && tool.state.metadata?.sessionId) return tool - await new Promise((done) => setTimeout(done, 20)) - } - throw new Error("timed out waiting for running task metadata") - }) + const tool = yield* pollWithTimeout( + Effect.gen(function* () { + const msgs = yield* MessageV2.filterCompactedEffect(chat.id) + const assistant = msgs.findLast((item) => item.info.role === "assistant" && item.info.agent === "build") + const tool = assistant?.parts.find( + (part): part is MessageV2.ToolPart => part.type === "tool" && part.tool === "task", + ) + if (tool?.state.status === "running" && tool.state.metadata?.sessionId) return tool + }), + "timed out waiting for running task metadata", + ) - if (tool.state.status !== "running") return - expect(typeof tool.state.metadata?.sessionId).toBe("string") - expect(tool.state.title).toBe("inspect bug") - expect(tool.state.metadata?.model).toBeDefined() + if (tool.state.status !== "running") return + expect(typeof tool.state.metadata?.sessionId).toBe("string") + expect(tool.state.title).toBe("inspect bug") + expect(tool.state.metadata?.model).toBeDefined() - yield* prompt.cancel(chat.id) - yield* Fiber.await(fiber) - }), - { git: true, config: providerCfg }, - ), + yield* prompt.cancel(chat.id) + yield* Fiber.await(fiber) + }), + { git: true }, 10_000, ) -it.live( +it.instance( "loop sets status to busy then idle", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const status = yield* SessionStatus.Service + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const status = yield* SessionStatus.Service - yield* llm.hang + yield* llm.hang - const chat = yield* sessions.create({}) - yield* user(chat.id, "hi") + const chat = yield* sessions.create({}) + yield* user(chat.id, "hi") - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* llm.wait(1) - expect((yield* status.get(chat.id)).type).toBe("busy") - yield* prompt.cancel(chat.id) - yield* Fiber.await(fiber) - expect((yield* status.get(chat.id)).type).toBe("idle") - }), - { git: true, config: providerCfg }, - ), + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* llm.wait(1) + expect((yield* status.get(chat.id)).type).toBe("busy") + yield* prompt.cancel(chat.id) + yield* Fiber.await(fiber) + expect((yield* status.get(chat.id)).type).toBe("idle") + }), + { git: true }, 3_000, ) // Cancel semantics -it.live( +it.instance( "cancel interrupts loop and resolves with an assistant message", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Pinned" }) - yield* seed(chat.id) + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Pinned" }) + yield* seed(chat.id) - yield* llm.hang + yield* llm.hang - yield* user(chat.id, "more") + yield* user(chat.id, "more") - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* llm.wait(1) - yield* prompt.cancel(chat.id) - const exit = yield* Fiber.await(fiber) - expect(Exit.isSuccess(exit)).toBe(true) - if (Exit.isSuccess(exit)) { - expect(exit.value.info.role).toBe("assistant") - } - }), - { git: true, config: providerCfg }, - ), + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* llm.wait(1) + yield* prompt.cancel(chat.id) + const exit = yield* Fiber.await(fiber) + expect(Exit.isSuccess(exit)).toBe(true) + if (Exit.isSuccess(exit)) { + expect(exit.value.info.role).toBe("assistant") + } + }), + { git: true }, 3_000, ) -it.live( +it.instance( "cancel records MessageAbortedError on interrupted process", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Pinned" }) - yield* llm.hang - yield* user(chat.id, "hello") + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Pinned" }) + yield* llm.hang + yield* user(chat.id, "hello") - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* llm.wait(1) - yield* prompt.cancel(chat.id) - const exit = yield* Fiber.await(fiber) - expect(Exit.isSuccess(exit)).toBe(true) - if (Exit.isSuccess(exit)) { - const info = exit.value.info - if (info.role === "assistant") { - expect(info.error?.name).toBe("MessageAbortedError") - } + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* llm.wait(1) + yield* prompt.cancel(chat.id) + const exit = yield* Fiber.await(fiber) + expect(Exit.isSuccess(exit)).toBe(true) + if (Exit.isSuccess(exit)) { + const info = exit.value.info + if (info.role === "assistant") { + expect(info.error?.name).toBe("MessageAbortedError") } - }), - { git: true, config: providerCfg }, - ), + } + }), + { git: true }, 3_000, ) -it.live( +it.instance( "cancel finalizes subtask tool state", () => - provideTmpdirInstance( - () => - Effect.gen(function* () { - const ready = defer() - const aborted = defer() - const registry = yield* ToolRegistry.Service - const { task } = yield* registry.named() - const original = task.execute - task.execute = (_args, ctx) => - Effect.callback((_resume) => { - ready.resolve() - ctx.abort.addEventListener("abort", () => aborted.resolve(), { once: true }) - return Effect.sync(() => aborted.resolve()) - }) - yield* Effect.addFinalizer(() => Effect.sync(() => void (task.execute = original))) + Effect.gen(function* () { + const ready = yield* Deferred.make() + const aborted = yield* Deferred.make() + const registry = yield* ToolRegistry.Service + const { task } = yield* registry.named() + const original = task.execute + task.execute = (_args, ctx) => + Effect.callback((_resume) => { + ctx.abort.addEventListener("abort", () => succeedVoid(aborted), { once: true }) + if (ctx.abort.aborted) succeedVoid(aborted) + succeedVoid(ready) + return Effect.sync(() => succeedVoid(aborted)) + }) + yield* Effect.addFinalizer(() => Effect.sync(() => void (task.execute = original))) - const { prompt, chat } = yield* boot() - const msg = yield* user(chat.id, "hello") - yield* addSubtask(chat.id, msg.id) + const { prompt, chat } = yield* boot() + const msg = yield* user(chat.id, "hello") + yield* addSubtask(chat.id, msg.id) - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* Effect.promise(() => ready.promise) - yield* prompt.cancel(chat.id) - yield* Effect.promise(() => aborted.promise) + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* awaitWithTimeout(Deferred.await(ready), "timed out waiting for task tool to start", "10 seconds") + yield* prompt.cancel(chat.id) - const exit = yield* Fiber.await(fiber) - expect(Exit.isSuccess(exit)).toBe(true) + const exit = yield* Fiber.await(fiber) + expect(Exit.isSuccess(exit)).toBe(true) + yield* awaitWithTimeout(Deferred.await(aborted), "timed out waiting for task tool abort", "10 seconds") - const msgs = yield* MessageV2.filterCompactedEffect(chat.id) - const taskMsg = msgs.find((item) => item.info.role === "assistant" && item.info.agent === "general") - expect(taskMsg?.info.role).toBe("assistant") - if (!taskMsg || taskMsg.info.role !== "assistant") return + const msgs = yield* MessageV2.filterCompactedEffect(chat.id) + const taskMsg = msgs.find((item) => item.info.role === "assistant" && item.info.agent === "general") + expect(taskMsg?.info.role).toBe("assistant") + if (!taskMsg || taskMsg.info.role !== "assistant") return - const tool = toolPart(taskMsg.parts) - expect(tool?.type).toBe("tool") - if (!tool) return + const tool = toolPart(taskMsg.parts) + expect(tool?.type).toBe("tool") + if (!tool) return - expect(tool.state.status).not.toBe("running") - expect(taskMsg.info.time.completed).toBeDefined() - expect(taskMsg.info.finish).toBeDefined() - }), - { git: true, config: cfg }, - ), + expect(tool.state.status).not.toBe("running") + expect(taskMsg.info.time.completed).toBeDefined() + expect(taskMsg.info.finish).toBeDefined() + }), + { git: true, config: cfg }, 30_000, ) -it.live( +it.instance( "cancel propagates from slash command subtask to child session", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const status = yield* SessionStatus.Service - const chat = yield* sessions.create({ title: "Pinned" }) - yield* llm.hang - const msg = yield* user(chat.id, "hello") - yield* addSubtask(chat.id, msg.id) + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const status = yield* SessionStatus.Service + const chat = yield* sessions.create({ title: "Pinned" }) + yield* llm.hang + const msg = yield* user(chat.id, "hello") + yield* addSubtask(chat.id, msg.id) - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* llm.wait(1) + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* llm.wait(1) - const msgs = yield* MessageV2.filterCompactedEffect(chat.id) - const taskMsg = msgs.find((item) => item.info.role === "assistant" && item.info.agent === "general") - const tool = taskMsg ? toolPart(taskMsg.parts) : undefined - const sessionID = tool?.state.status === "running" ? tool.state.metadata?.sessionId : undefined - expect(typeof sessionID).toBe("string") - if (typeof sessionID !== "string") throw new Error("missing child session id") - const childID = SessionID.make(sessionID) - expect((yield* status.get(childID)).type).toBe("busy") + const msgs = yield* MessageV2.filterCompactedEffect(chat.id) + const taskMsg = msgs.find((item) => item.info.role === "assistant" && item.info.agent === "general") + const tool = taskMsg ? toolPart(taskMsg.parts) : undefined + const sessionID = tool?.state.status === "running" ? tool.state.metadata?.sessionId : undefined + expect(typeof sessionID).toBe("string") + if (typeof sessionID !== "string") throw new Error("missing child session id") + const childID = SessionID.make(sessionID) + expect((yield* status.get(childID)).type).toBe("busy") - yield* prompt.cancel(chat.id) - const exit = yield* Fiber.await(fiber) - expect(Exit.isSuccess(exit)).toBe(true) + yield* prompt.cancel(chat.id) + const exit = yield* Fiber.await(fiber) + expect(Exit.isSuccess(exit)).toBe(true) - expect((yield* status.get(chat.id)).type).toBe("idle") - expect((yield* status.get(childID)).type).toBe("idle") - }), - { git: true, config: providerCfg }, - ), + expect((yield* status.get(chat.id)).type).toBe("idle") + expect((yield* status.get(childID)).type).toBe("idle") + }), + { git: true }, 10_000, ) -it.live( +it.instance( "cancel with queued callers resolves all cleanly", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Pinned" }) - yield* llm.hang - yield* user(chat.id, "hello") + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Pinned" }) + yield* llm.hang + yield* user(chat.id, "hello") - const a = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* llm.wait(1) - const b = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* Effect.sleep(50) + const a = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* llm.wait(1) + const b = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* Effect.sleep(50) - yield* prompt.cancel(chat.id) - const [exitA, exitB] = yield* Effect.all([Fiber.await(a), Fiber.await(b)]) - expect(Exit.isSuccess(exitA)).toBe(true) - expect(Exit.isSuccess(exitB)).toBe(true) - if (Exit.isSuccess(exitA) && Exit.isSuccess(exitB)) { - expect(exitA.value.info.id).toBe(exitB.value.info.id) - } - }), - { git: true, config: providerCfg }, - ), + yield* prompt.cancel(chat.id) + const [exitA, exitB] = yield* Effect.all([Fiber.await(a), Fiber.await(b)]) + expect(Exit.isSuccess(exitA)).toBe(true) + expect(Exit.isSuccess(exitB)).toBe(true) + if (Exit.isSuccess(exitA) && Exit.isSuccess(exitB)) { + expect(exitA.value.info.id).toBe(exitB.value.info.id) + } + }), + { git: true }, 3_000, ) // Queue semantics -it.live("concurrent loop callers get same result", () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const { prompt, run, chat } = yield* boot() - yield* seed(chat.id, { finish: "stop" }) +it.instance( + "concurrent loop callers get same result", + () => + Effect.gen(function* () { + const { prompt, run, chat } = yield* boot() + yield* seed(chat.id, { finish: "stop" }) - const [a, b] = yield* Effect.all([prompt.loop({ sessionID: chat.id }), prompt.loop({ sessionID: chat.id })], { - concurrency: "unbounded", - }) + const [a, b] = yield* Effect.all([prompt.loop({ sessionID: chat.id }), prompt.loop({ sessionID: chat.id })], { + concurrency: "unbounded", + }) - expect(a.info.id).toBe(b.info.id) - expect(a.info.role).toBe("assistant") - yield* run.assertNotBusy(chat.id) - }), - { git: true }, - ), + expect(a.info.id).toBe(b.info.id) + expect(a.info.role).toBe("assistant") + yield* run.assertNotBusy(chat.id) + }), + { git: true }, ) -it.live( +it.instance( "concurrent loop callers all receive same error result", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Pinned" }) + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Pinned" }) - yield* llm.fail("boom") - yield* user(chat.id, "hello") + yield* llm.fail("boom") + yield* user(chat.id, "hello") - const [a, b] = yield* Effect.all([prompt.loop({ sessionID: chat.id }), prompt.loop({ sessionID: chat.id })], { - concurrency: "unbounded", - }) - expect(a.info.id).toBe(b.info.id) - expect(a.info.role).toBe("assistant") - }), - { git: true, config: providerCfg }, - ), + const [a, b] = yield* Effect.all([prompt.loop({ sessionID: chat.id }), prompt.loop({ sessionID: chat.id })], { + concurrency: "unbounded", + }) + expect(a.info.id).toBe(b.info.id) + expect(a.info.role).toBe("assistant") + }), + { git: true }, 3_000, ) -it.live( +it.instance( "prompt submitted during an active run is included in the next LLM input", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const gate = defer() - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Pinned" }) + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const gate = yield* Deferred.make() + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Pinned" }) - yield* llm.hold("first", gate.promise) - yield* llm.text("second") + yield* llm.hold("first", deferredAsPromise(gate)) + yield* llm.text("second") - const a = yield* prompt - .prompt({ - sessionID: chat.id, - agent: "build", - model: ref, - parts: [{ type: "text", text: "first" }], - }) - .pipe(Effect.forkChild) - - yield* llm.wait(1) - - const id = MessageID.ascending() - const b = yield* prompt - .prompt({ - sessionID: chat.id, - messageID: id, - agent: "build", - model: ref, - parts: [{ type: "text", text: "second" }], - }) - .pipe(Effect.forkChild) - - yield* Effect.promise(async () => { - const end = Date.now() + 5000 - while (Date.now() < end) { - const msgs = await Effect.runPromise(sessions.messages({ sessionID: chat.id })) - if (msgs.some((msg) => msg.info.role === "user" && msg.info.id === id)) return - await new Promise((done) => setTimeout(done, 20)) - } - throw new Error("timed out waiting for second prompt to save") + const a = yield* prompt + .prompt({ + sessionID: chat.id, + agent: "build", + model: ref, + parts: [{ type: "text", text: "first" }], }) + .pipe(Effect.forkChild) - gate.resolve() + yield* llm.wait(1) - const [ea, eb] = yield* Effect.all([Fiber.await(a), Fiber.await(b)]) - expect(Exit.isSuccess(ea)).toBe(true) - expect(Exit.isSuccess(eb)).toBe(true) - expect(yield* llm.calls).toBe(2) + const id = MessageID.ascending() + const b = yield* prompt + .prompt({ + sessionID: chat.id, + messageID: id, + agent: "build", + model: ref, + parts: [{ type: "text", text: "second" }], + }) + .pipe(Effect.forkChild) - const msgs = yield* sessions.messages({ sessionID: chat.id }) - const assistants = msgs.filter((msg) => msg.info.role === "assistant") - expect(assistants).toHaveLength(2) - const last = assistants.at(-1) - if (!last || last.info.role !== "assistant") throw new Error("expected second assistant") - expect(last.info.parentID).toBe(id) - expect(last.parts.some((part) => part.type === "text" && part.text === "second")).toBe(true) + yield* pollWithTimeout( + sessions + .messages({ sessionID: chat.id }) + .pipe( + Effect.map((msgs) => + msgs.some((msg) => msg.info.role === "user" && msg.info.id === id) ? true : undefined, + ), + ), + "timed out waiting for second prompt to save", + ) - const inputs = yield* llm.inputs - expect(inputs).toHaveLength(2) - expect(JSON.stringify(inputs.at(-1)?.messages)).toContain("second") - }), - { git: true, config: providerCfg }, - ), + yield* Deferred.succeed(gate, void 0) + + const [ea, eb] = yield* Effect.all([Fiber.await(a), Fiber.await(b)]) + expect(Exit.isSuccess(ea)).toBe(true) + expect(Exit.isSuccess(eb)).toBe(true) + expect(yield* llm.calls).toBe(2) + + const msgs = yield* sessions.messages({ sessionID: chat.id }) + const assistants = msgs.filter((msg) => msg.info.role === "assistant") + expect(assistants).toHaveLength(2) + const last = assistants.at(-1) + if (!last || last.info.role !== "assistant") throw new Error("expected second assistant") + expect(last.info.parentID).toBe(id) + expect(last.parts.some((part) => part.type === "text" && part.text === "second")).toBe(true) + + const inputs = yield* llm.inputs + expect(inputs).toHaveLength(2) + expect(JSON.stringify(inputs.at(-1)?.messages)).toContain("second") + }), + { git: true }, 3_000, ) -it.live( +it.instance( "assertNotBusy throws BusyError when loop running", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const run = yield* SessionRunState.Service - const sessions = yield* Session.Service - yield* llm.hang + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const run = yield* SessionRunState.Service + const sessions = yield* Session.Service + yield* llm.hang - const chat = yield* sessions.create({}) - yield* user(chat.id, "hi") + const chat = yield* sessions.create({}) + yield* user(chat.id, "hi") - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* llm.wait(1) + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* llm.wait(1) - const exit = yield* run.assertNotBusy(chat.id).pipe(Effect.exit) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) { - expect(Cause.squash(exit.cause)).toBeInstanceOf(Session.BusyError) - } + const exit = yield* run.assertNotBusy(chat.id).pipe(Effect.exit) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + expect(Cause.squash(exit.cause)).toBeInstanceOf(Session.BusyError) + } - yield* prompt.cancel(chat.id) - yield* Fiber.await(fiber) - }), - { git: true, config: providerCfg }, - ), + yield* prompt.cancel(chat.id) + yield* Fiber.await(fiber) + }), + { git: true }, 3_000, ) -it.live("assertNotBusy succeeds when idle", () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const run = yield* SessionRunState.Service - const sessions = yield* Session.Service +it.instance( + "assertNotBusy succeeds when idle", + () => + Effect.gen(function* () { + const run = yield* SessionRunState.Service + const sessions = yield* Session.Service - const chat = yield* sessions.create({}) - const exit = yield* run.assertNotBusy(chat.id).pipe(Effect.exit) - expect(Exit.isSuccess(exit)).toBe(true) - }), - { git: true }, - ), + const chat = yield* sessions.create({}) + const exit = yield* run.assertNotBusy(chat.id).pipe(Effect.exit) + expect(Exit.isSuccess(exit)).toBe(true) + }), + { git: true }, ) // Shell semantics -it.live( +it.instance( "shell rejects with BusyError when loop running", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Pinned" }) - yield* llm.hang - yield* user(chat.id, "hi") + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Pinned" }) + yield* llm.hang + yield* user(chat.id, "hi") - const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* llm.wait(1) + const fiber = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* llm.wait(1) + + const exit = yield* prompt.shell({ sessionID: chat.id, agent: "build", command: "echo hi" }).pipe(Effect.exit) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + expect(Cause.squash(exit.cause)).toBeInstanceOf(Session.BusyError) + } + + yield* prompt.cancel(chat.id) + yield* Fiber.await(fiber) + }), + { git: true }, + 3_000, +) + +unix( + "shell captures stdout and stderr in completed tool output", + () => + Effect.gen(function* () { + const { prompt, run, chat } = yield* boot() + const result = yield* prompt.shell({ + sessionID: chat.id, + agent: "build", + command: "printf out && printf err >&2", + }) + + expect(result.info.role).toBe("assistant") + const tool = completedTool(result.parts) + if (!tool) return + + expect(tool.state.output).toContain("out") + expect(tool.state.output).toContain("err") + expect(tool.state.metadata.output).toContain("out") + expect(tool.state.metadata.output).toContain("err") + yield* run.assertNotBusy(chat.id) + }), + { git: true, config: cfg }, +) + +unix( + "shell completes a fast command on the preferred shell", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const { prompt, run, chat } = yield* boot() + const result = yield* prompt.shell({ + sessionID: chat.id, + agent: "build", + command: "pwd", + }) + + expect(result.info.role).toBe("assistant") + const tool = completedTool(result.parts) + if (!tool) return + + expect(tool.state.input.command).toBe("pwd") + expect(tool.state.output).toContain(dir) + expect(tool.state.metadata.output).toContain(dir) + yield* run.assertNotBusy(chat.id) + }), + { git: true, config: cfg }, +) + +unix( + "shell uses configured shell over env shell", + () => + withSh(() => + Effect.gen(function* () { + if (!(yield* hasBash)) return + + const { prompt, chat } = yield* boot() + const result = yield* prompt.shell({ + sessionID: chat.id, + agent: "build", + command: "[[ 1 -eq 1 ]] && printf configured", + }) + + const tool = completedTool(result.parts) + if (!tool) return + expect(tool.state.output).toContain("configured") + }), + ), + { git: true, config: { ...cfg, shell: "bash" } }, + 30_000, +) + +unix( + "shell commands can change directory after startup", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const { prompt, run, chat } = yield* boot() + const parent = path.dirname(dir) + const result = yield* prompt.shell({ + sessionID: chat.id, + agent: "build", + command: "cd .. && pwd", + }) + + expect(result.info.role).toBe("assistant") + const tool = completedTool(result.parts) + if (!tool) return + + expect(tool.state.output).toContain(parent) + expect(tool.state.metadata.output).toContain(parent) + yield* run.assertNotBusy(chat.id) + }), + { git: true, config: cfg }, +) + +unix( + "shell lists files from the project directory", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const { prompt, run, chat } = yield* boot() + yield* writeText(path.join(dir, "README.md"), "# e2e\n") + + const result = yield* prompt.shell({ + sessionID: chat.id, + agent: "build", + command: "command ls", + }) + + expect(result.info.role).toBe("assistant") + const tool = completedTool(result.parts) + if (!tool) return + + expect(tool.state.input.command).toBe("command ls") + expect(tool.state.output).toContain("README.md") + expect(tool.state.metadata.output).toContain("README.md") + yield* run.assertNotBusy(chat.id) + }), + { git: true, config: cfg }, +) + +unix( + "shell captures stderr from a failing command", + () => + Effect.gen(function* () { + const { prompt, run, chat } = yield* boot() + const result = yield* prompt.shell({ + sessionID: chat.id, + agent: "build", + command: "command -v __nonexistent_cmd_e2e__ || echo 'not found' >&2; exit 1", + }) + + expect(result.info.role).toBe("assistant") + const tool = completedTool(result.parts) + if (!tool) return + + expect(tool.state.output).toContain("not found") + expect(tool.state.metadata.output).toContain("not found") + yield* run.assertNotBusy(chat.id) + }), + { git: true, config: cfg }, +) + +unix( + "shell updates running metadata before process exit", + () => + withSh(() => + Effect.gen(function* () { + const { prompt, chat } = yield* boot() + + const fiber = yield* prompt + .shell({ sessionID: chat.id, agent: "build", command: "printf first && sleep 0.2 && printf second" }) + .pipe(Effect.forkChild) + + yield* pollWithTimeout( + Effect.gen(function* () { + const msgs = yield* MessageV2.filterCompactedEffect(chat.id) + const taskMsg = msgs.find((item) => item.info.role === "assistant") + const tool = taskMsg ? toolPart(taskMsg.parts) : undefined + if (tool?.state.status === "running" && tool.state.metadata?.output.includes("first")) return true + }), + "timed out waiting for running shell metadata", + ) + + const exit = yield* Fiber.await(fiber) + expect(Exit.isSuccess(exit)).toBe(true) + }), + ), + { git: true, config: cfg }, + 30_000, +) + +it.instance( + "loop waits while shell runs and starts after shell exits", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ + title: "Pinned", + permission: [{ permission: "*", pattern: "*", action: "allow" }], + }) + yield* llm.text("after-shell") + + const sh = yield* prompt + .shell({ sessionID: chat.id, agent: "build", command: "sleep 0.2" }) + .pipe(Effect.forkChild) + yield* Effect.sleep(50) + + const loop = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* Effect.sleep(50) + + expect(yield* llm.calls).toBe(0) + + yield* Fiber.await(sh) + const exit = yield* Fiber.await(loop) + + expect(Exit.isSuccess(exit)).toBe(true) + if (Exit.isSuccess(exit)) { + expect(exit.value.info.role).toBe("assistant") + expect(exit.value.parts.some((part) => part.type === "text" && part.text === "after-shell")).toBe(true) + } + expect(yield* llm.calls).toBe(1) + }), + { git: true }, + 3_000, +) + +it.instance( + "shell completion resumes queued loop callers", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ + title: "Pinned", + permission: [{ permission: "*", pattern: "*", action: "allow" }], + }) + yield* llm.text("done") + + const sh = yield* prompt + .shell({ sessionID: chat.id, agent: "build", command: "sleep 0.2" }) + .pipe(Effect.forkChild) + yield* Effect.sleep(50) + + const a = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + const b = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* Effect.sleep(50) + + expect(yield* llm.calls).toBe(0) + + yield* Fiber.await(sh) + const [ea, eb] = yield* Effect.all([Fiber.await(a), Fiber.await(b)]) + + expect(Exit.isSuccess(ea)).toBe(true) + expect(Exit.isSuccess(eb)).toBe(true) + if (Exit.isSuccess(ea) && Exit.isSuccess(eb)) { + expect(ea.value.info.id).toBe(eb.value.info.id) + expect(ea.value.info.role).toBe("assistant") + } + expect(yield* llm.calls).toBe(1) + }), + { git: true }, + 3_000, +) + +unix( + "command ! expansion uses configured shell over env shell", + () => + withSh(() => + Effect.gen(function* () { + if (!(yield* hasBash)) return + const { llm } = yield* useServerConfig((url) => ({ + ...providerCfg(url), + shell: "bash", + command: { + probe: { + template: "Probe: !`[[ 1 -eq 1 ]] && printf configured`", + }, + }, + })) + + const { prompt, chat } = yield* boot() + yield* llm.text("done") + + const result = yield* prompt.command({ + sessionID: chat.id, + command: "probe", + arguments: "", + }) + + expect(result.info.role).toBe("assistant") + const inputs = yield* llm.inputs + expect(JSON.stringify(inputs.at(-1)?.messages)).toContain("configured") + }), + ), + { git: true }, + 30_000, +) + +unix( + "cancel interrupts shell and resolves cleanly", + () => + withSh(() => + Effect.gen(function* () { + const { prompt, run, chat } = yield* boot() + + const sh = yield* prompt + .shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }) + .pipe(Effect.forkChild) + yield* Effect.sleep(50) + + yield* prompt.cancel(chat.id) + + const status = yield* SessionStatus.Service + expect((yield* status.get(chat.id)).type).toBe("idle") + const busy = yield* run.assertNotBusy(chat.id).pipe(Effect.exit) + expect(Exit.isSuccess(busy)).toBe(true) + + const exit = yield* Fiber.await(sh) + expect(Exit.isSuccess(exit)).toBe(true) + if (Exit.isSuccess(exit)) { + expect(exit.value.info.role).toBe("assistant") + const tool = completedTool(exit.value.parts) + if (tool) { + expect(tool.state.output).toContain("User aborted the command") + } + } + }), + ), + { git: true, config: cfg }, + 30_000, +) + +unix( + "cancel persists aborted shell result when shell ignores TERM", + () => + withSh(() => + Effect.gen(function* () { + const { prompt, chat } = yield* boot() + + const sh = yield* prompt + .shell({ sessionID: chat.id, agent: "build", command: "trap '' TERM; sleep 30" }) + .pipe(Effect.forkChild) + yield* Effect.sleep(50) + + yield* prompt.cancel(chat.id) + + const exit = yield* Fiber.await(sh) + expect(Exit.isSuccess(exit)).toBe(true) + if (Exit.isSuccess(exit)) { + expect(exit.value.info.role).toBe("assistant") + const tool = completedTool(exit.value.parts) + if (tool) { + expect(tool.state.output).toContain("User aborted the command") + } + } + }), + ), + { git: true, config: cfg }, + 30_000, +) + +unix( + "cancel finalizes interrupted bash tool output through normal truncation", + () => + Effect.gen(function* () { + const { dir, llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ + title: "Interrupted bash truncation", + permission: [{ permission: "*", pattern: "*", action: "allow" }], + }) + + yield* prompt.prompt({ + sessionID: chat.id, + agent: "build", + noReply: true, + parts: [{ type: "text", text: "run bash" }], + }) + + yield* llm.tool("bash", { + command: + 'i=0; while [ "$i" -lt 4000 ]; do printf "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx %05d\\n" "$i"; i=$((i + 1)); done; sleep 30', + description: "Print many lines", + timeout: 30_000, + workdir: path.resolve(dir), + }) + + const run = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* llm.wait(1) + yield* Effect.sleep(150) + yield* prompt.cancel(chat.id) + + const exit = yield* Fiber.await(run) + expect(Exit.isSuccess(exit)).toBe(true) + if (Exit.isFailure(exit)) return + + const tool = completedTool(exit.value.parts) + if (!tool) return + + expect(tool.state.metadata.truncated).toBe(true) + expect(typeof tool.state.metadata.outputPath).toBe("string") + expect(tool.state.output).toMatch(/\.\.\.output truncated\.\.\./) + expect(tool.state.output).toMatch(/Full output saved to:\s+\S+/) + expect(tool.state.output).not.toContain("Tool execution aborted") + }), + { git: true }, + 30_000, +) + +unix( + "cancel interrupts loop queued behind shell", + () => + Effect.gen(function* () { + const { prompt, chat } = yield* boot() + + const sh = yield* prompt.shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }).pipe(Effect.forkChild) + yield* Effect.sleep(50) + + const loop = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) + yield* Effect.sleep(50) + + yield* prompt.cancel(chat.id) + + const exit = yield* Fiber.await(loop) + expect(Exit.isSuccess(exit)).toBe(true) + if (Exit.isSuccess(exit)) { + const tool = completedTool(exit.value.parts) + expect(tool?.state.output).toContain("User aborted the command") + } + + yield* Fiber.await(sh) + }), + { git: true, config: cfg }, + 30_000, +) + +unix( + "shell rejects when another shell is already running", + () => + withSh(() => + Effect.gen(function* () { + const { prompt, chat } = yield* boot() + + const a = yield* prompt + .shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }) + .pipe(Effect.forkChild) + yield* Effect.sleep(50) const exit = yield* prompt.shell({ sessionID: chat.id, agent: "build", command: "echo hi" }).pipe(Effect.exit) expect(Exit.isFailure(exit)).toBe(true) @@ -1119,884 +1630,390 @@ it.live( } yield* prompt.cancel(chat.id) - yield* Fiber.await(fiber) + yield* Fiber.await(a) }), - { git: true, config: providerCfg }, - ), - 3_000, -) - -unix("shell captures stdout and stderr in completed tool output", () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const { prompt, run, chat } = yield* boot() - const result = yield* prompt.shell({ - sessionID: chat.id, - agent: "build", - command: "printf out && printf err >&2", - }) - - expect(result.info.role).toBe("assistant") - const tool = completedTool(result.parts) - if (!tool) return - - expect(tool.state.output).toContain("out") - expect(tool.state.output).toContain("err") - expect(tool.state.metadata.output).toContain("out") - expect(tool.state.metadata.output).toContain("err") - yield* run.assertNotBusy(chat.id) - }), - { git: true, config: cfg }, - ), -) - -unix("shell completes a fast command on the preferred shell", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const { prompt, run, chat } = yield* boot() - const result = yield* prompt.shell({ - sessionID: chat.id, - agent: "build", - command: "pwd", - }) - - expect(result.info.role).toBe("assistant") - const tool = completedTool(result.parts) - if (!tool) return - - expect(tool.state.input.command).toBe("pwd") - expect(tool.state.output).toContain(dir) - expect(tool.state.metadata.output).toContain(dir) - yield* run.assertNotBusy(chat.id) - }), - { git: true, config: cfg }, - ), -) - -unix( - "shell uses configured shell over env shell", - () => - withSh(() => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - if (!Bun.which("bash")) return - - const { prompt, chat } = yield* boot() - const result = yield* prompt.shell({ - sessionID: chat.id, - agent: "build", - command: "[[ 1 -eq 1 ]] && printf configured", - }) - - const tool = completedTool(result.parts) - if (!tool) return - expect(tool.state.output).toContain("configured") - }), - { git: true, config: { ...cfg, shell: "bash" } }, - ), - ), - 30_000, -) - -unix("shell commands can change directory after startup", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const { prompt, run, chat } = yield* boot() - const parent = path.dirname(dir) - const result = yield* prompt.shell({ - sessionID: chat.id, - agent: "build", - command: "cd .. && pwd", - }) - - expect(result.info.role).toBe("assistant") - const tool = completedTool(result.parts) - if (!tool) return - - expect(tool.state.output).toContain(parent) - expect(tool.state.metadata.output).toContain(parent) - yield* run.assertNotBusy(chat.id) - }), - { git: true, config: cfg }, - ), -) - -unix("shell lists files from the project directory", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const { prompt, run, chat } = yield* boot() - yield* Effect.promise(() => Bun.write(path.join(dir, "README.md"), "# e2e\n")) - - const result = yield* prompt.shell({ - sessionID: chat.id, - agent: "build", - command: "command ls", - }) - - expect(result.info.role).toBe("assistant") - const tool = completedTool(result.parts) - if (!tool) return - - expect(tool.state.input.command).toBe("command ls") - expect(tool.state.output).toContain("README.md") - expect(tool.state.metadata.output).toContain("README.md") - yield* run.assertNotBusy(chat.id) - }), - { git: true, config: cfg }, - ), -) - -unix("shell captures stderr from a failing command", () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const { prompt, run, chat } = yield* boot() - const result = yield* prompt.shell({ - sessionID: chat.id, - agent: "build", - command: "command -v __nonexistent_cmd_e2e__ || echo 'not found' >&2; exit 1", - }) - - expect(result.info.role).toBe("assistant") - const tool = completedTool(result.parts) - if (!tool) return - - expect(tool.state.output).toContain("not found") - expect(tool.state.metadata.output).toContain("not found") - yield* run.assertNotBusy(chat.id) - }), - { git: true, config: cfg }, - ), -) - -unix( - "shell updates running metadata before process exit", - () => - withSh(() => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const { prompt, chat } = yield* boot() - - const fiber = yield* prompt - .shell({ sessionID: chat.id, agent: "build", command: "printf first && sleep 0.2 && printf second" }) - .pipe(Effect.forkChild) - - yield* Effect.promise(async () => { - const start = Date.now() - while (Date.now() - start < 5000) { - const msgs = await MessageV2.filterCompacted(MessageV2.stream(chat.id)) - const taskMsg = msgs.find((item) => item.info.role === "assistant") - const tool = taskMsg ? toolPart(taskMsg.parts) : undefined - if (tool?.state.status === "running" && tool.state.metadata?.output.includes("first")) return - await new Promise((done) => setTimeout(done, 20)) - } - throw new Error("timed out waiting for running shell metadata") - }) - - const exit = yield* Fiber.await(fiber) - expect(Exit.isSuccess(exit)).toBe(true) - }), - { git: true, config: cfg }, - ), - ), - 30_000, -) - -it.live( - "loop waits while shell runs and starts after shell exits", - () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ - title: "Pinned", - permission: [{ permission: "*", pattern: "*", action: "allow" }], - }) - yield* llm.text("after-shell") - - const sh = yield* prompt - .shell({ sessionID: chat.id, agent: "build", command: "sleep 0.2" }) - .pipe(Effect.forkChild) - yield* Effect.sleep(50) - - const loop = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* Effect.sleep(50) - - expect(yield* llm.calls).toBe(0) - - yield* Fiber.await(sh) - const exit = yield* Fiber.await(loop) - - expect(Exit.isSuccess(exit)).toBe(true) - if (Exit.isSuccess(exit)) { - expect(exit.value.info.role).toBe("assistant") - expect(exit.value.parts.some((part) => part.type === "text" && part.text === "after-shell")).toBe(true) - } - expect(yield* llm.calls).toBe(1) - }), - { git: true, config: providerCfg }, - ), - 3_000, -) - -it.live( - "shell completion resumes queued loop callers", - () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ - title: "Pinned", - permission: [{ permission: "*", pattern: "*", action: "allow" }], - }) - yield* llm.text("done") - - const sh = yield* prompt - .shell({ sessionID: chat.id, agent: "build", command: "sleep 0.2" }) - .pipe(Effect.forkChild) - yield* Effect.sleep(50) - - const a = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - const b = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* Effect.sleep(50) - - expect(yield* llm.calls).toBe(0) - - yield* Fiber.await(sh) - const [ea, eb] = yield* Effect.all([Fiber.await(a), Fiber.await(b)]) - - expect(Exit.isSuccess(ea)).toBe(true) - expect(Exit.isSuccess(eb)).toBe(true) - if (Exit.isSuccess(ea) && Exit.isSuccess(eb)) { - expect(ea.value.info.id).toBe(eb.value.info.id) - expect(ea.value.info.role).toBe("assistant") - } - expect(yield* llm.calls).toBe(1) - }), - { git: true, config: providerCfg }, - ), - 3_000, -) - -unix( - "command ! expansion uses configured shell over env shell", - () => - withSh(() => - provideTmpdirServer( - ({ llm }) => - Effect.gen(function* () { - if (!Bun.which("bash")) return - - const { prompt, chat } = yield* boot() - yield* llm.text("done") - - const result = yield* prompt.command({ - sessionID: chat.id, - command: "probe", - arguments: "", - }) - - expect(result.info.role).toBe("assistant") - const inputs = yield* llm.inputs - expect(JSON.stringify(inputs.at(-1)?.messages)).toContain("configured") - }), - { - git: true, - config: (url) => ({ - ...providerCfg(url), - shell: "bash", - command: { - probe: { - template: "Probe: !`[[ 1 -eq 1 ]] && printf configured`", - }, - }, - }), - }, - ), - ), - 30_000, -) - -unix( - "cancel interrupts shell and resolves cleanly", - () => - withSh(() => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const { prompt, run, chat } = yield* boot() - - const sh = yield* prompt - .shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }) - .pipe(Effect.forkChild) - yield* Effect.sleep(50) - - yield* prompt.cancel(chat.id) - - const status = yield* SessionStatus.Service - expect((yield* status.get(chat.id)).type).toBe("idle") - const busy = yield* run.assertNotBusy(chat.id).pipe(Effect.exit) - expect(Exit.isSuccess(busy)).toBe(true) - - const exit = yield* Fiber.await(sh) - expect(Exit.isSuccess(exit)).toBe(true) - if (Exit.isSuccess(exit)) { - expect(exit.value.info.role).toBe("assistant") - const tool = completedTool(exit.value.parts) - if (tool) { - expect(tool.state.output).toContain("User aborted the command") - } - } - }), - { git: true, config: cfg }, - ), - ), - 30_000, -) - -unix( - "cancel persists aborted shell result when shell ignores TERM", - () => - withSh(() => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const { prompt, chat } = yield* boot() - - const sh = yield* prompt - .shell({ sessionID: chat.id, agent: "build", command: "trap '' TERM; sleep 30" }) - .pipe(Effect.forkChild) - yield* Effect.sleep(50) - - yield* prompt.cancel(chat.id) - - const exit = yield* Fiber.await(sh) - expect(Exit.isSuccess(exit)).toBe(true) - if (Exit.isSuccess(exit)) { - expect(exit.value.info.role).toBe("assistant") - const tool = completedTool(exit.value.parts) - if (tool) { - expect(tool.state.output).toContain("User aborted the command") - } - } - }), - { git: true, config: cfg }, - ), - ), - 30_000, -) - -unix( - "cancel finalizes interrupted bash tool output through normal truncation", - () => - provideTmpdirServer( - ({ dir, llm }) => - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ - title: "Interrupted bash truncation", - permission: [{ permission: "*", pattern: "*", action: "allow" }], - }) - - yield* prompt.prompt({ - sessionID: chat.id, - agent: "build", - noReply: true, - parts: [{ type: "text", text: "run bash" }], - }) - - yield* llm.tool("bash", { - command: - 'i=0; while [ "$i" -lt 4000 ]; do printf "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx %05d\\n" "$i"; i=$((i + 1)); done; sleep 30', - description: "Print many lines", - timeout: 30_000, - workdir: path.resolve(dir), - }) - - const run = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* llm.wait(1) - yield* Effect.sleep(150) - yield* prompt.cancel(chat.id) - - const exit = yield* Fiber.await(run) - expect(Exit.isSuccess(exit)).toBe(true) - if (Exit.isFailure(exit)) return - - const tool = completedTool(exit.value.parts) - if (!tool) return - - expect(tool.state.metadata.truncated).toBe(true) - expect(typeof tool.state.metadata.outputPath).toBe("string") - expect(tool.state.output).toMatch(/\.\.\.output truncated\.\.\./) - expect(tool.state.output).toMatch(/Full output saved to:\s+\S+/) - expect(tool.state.output).not.toContain("Tool execution aborted") - }), - { git: true, config: providerCfg }, - ), - 30_000, -) - -unix( - "cancel interrupts loop queued behind shell", - () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const { prompt, chat } = yield* boot() - - const sh = yield* prompt - .shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }) - .pipe(Effect.forkChild) - yield* Effect.sleep(50) - - const loop = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) - yield* Effect.sleep(50) - - yield* prompt.cancel(chat.id) - - const exit = yield* Fiber.await(loop) - expect(Exit.isSuccess(exit)).toBe(true) - if (Exit.isSuccess(exit)) { - const tool = completedTool(exit.value.parts) - expect(tool?.state.output).toContain("User aborted the command") - } - - yield* Fiber.await(sh) - }), - { git: true, config: cfg }, - ), - 30_000, -) - -unix( - "shell rejects when another shell is already running", - () => - withSh(() => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const { prompt, chat } = yield* boot() - - const a = yield* prompt - .shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }) - .pipe(Effect.forkChild) - yield* Effect.sleep(50) - - const exit = yield* prompt - .shell({ sessionID: chat.id, agent: "build", command: "echo hi" }) - .pipe(Effect.exit) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) { - expect(Cause.squash(exit.cause)).toBeInstanceOf(Session.BusyError) - } - - yield* prompt.cancel(chat.id) - yield* Fiber.await(a) - }), - { git: true, config: cfg }, - ), ), + { git: true, config: cfg }, 30_000, ) // Abort signal propagation tests for inline tool execution -/** Override a tool's execute to hang until aborted. Returns ready/aborted defers and a finalizer. */ function hangUntilAborted(tool: { execute: (...args: any[]) => any }) { - const ready = defer() - const aborted = defer() - const original = tool.execute - tool.execute = (_args: any, ctx: any) => { - ready.resolve() - ctx.abort.addEventListener("abort", () => aborted.resolve(), { once: true }) - return Effect.callback(() => {}) - } - const restore = Effect.addFinalizer(() => Effect.sync(() => void (tool.execute = original))) - return { ready, aborted, restore } + return Effect.gen(function* () { + const ready = yield* Deferred.make() + const aborted = yield* Deferred.make() + const original = tool.execute + tool.execute = (_args: any, ctx: any) => { + ctx.abort.addEventListener("abort", () => succeedVoid(aborted), { once: true }) + if (ctx.abort.aborted) succeedVoid(aborted) + succeedVoid(ready) + return Effect.callback(() => Effect.sync(() => succeedVoid(aborted))) + } + const restore = Effect.addFinalizer(() => Effect.sync(() => void (tool.execute = original))) + return { ready, aborted, restore } + }) } -it.live( +it.instance( "interrupt propagates abort signal to read tool via file part (text/plain)", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const registry = yield* ToolRegistry.Service - const { read } = yield* registry.named() - const { ready, aborted, restore } = hangUntilAborted(read) - yield* restore + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const registry = yield* ToolRegistry.Service + const { read } = yield* registry.named() + const { ready, restore } = yield* hangUntilAborted(read) + yield* restore - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Abort Test" }) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Abort Test" }) - const testFile = path.join(dir, "test.txt") - yield* Effect.promise(() => Bun.write(testFile, "hello world")) + const testFile = path.join(dir, "test.txt") + yield* writeText(testFile, "hello world") - const fiber = yield* prompt - .prompt({ - sessionID: chat.id, - agent: "build", - parts: [ - { type: "text", text: "read this" }, - { type: "file", url: `file://${testFile}`, filename: "test.txt", mime: "text/plain" }, - ], - }) - .pipe(Effect.forkChild) + const fiber = yield* prompt + .prompt({ + sessionID: chat.id, + agent: "build", + parts: [ + { type: "text", text: "read this" }, + { type: "file", url: `file://${testFile}`, filename: "test.txt", mime: "text/plain" }, + ], + }) + .pipe(Effect.forkChild) - yield* Effect.promise(() => ready.promise) - yield* Fiber.interrupt(fiber) - - yield* Effect.promise(() => - Promise.race([ - aborted.promise, - new Promise((_, reject) => - setTimeout(() => reject(new Error("abort signal not propagated within 2s")), 2_000), - ), - ]), - ) - }), - { git: true, config: cfg }, - ), + yield* awaitWithTimeout(Deferred.await(ready), "timed out waiting for read tool to start", "10 seconds") + yield* prompt.cancel(chat.id) + yield* Fiber.interrupt(fiber) + const exit = yield* Fiber.await(fiber) + expect(Exit.isFailure(exit)).toBe(true) + }), + { git: true, config: cfg }, 30_000, ) -it.live( +it.instance( "interrupt propagates abort signal to read tool via file part (directory)", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const registry = yield* ToolRegistry.Service - const { read } = yield* registry.named() - const { ready, aborted, restore } = hangUntilAborted(read) - yield* restore + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const registry = yield* ToolRegistry.Service + const { read } = yield* registry.named() + const { ready, restore } = yield* hangUntilAborted(read) + yield* restore - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const chat = yield* sessions.create({ title: "Abort Test" }) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const chat = yield* sessions.create({ title: "Abort Test" }) - const fiber = yield* prompt - .prompt({ - sessionID: chat.id, - agent: "build", - parts: [ - { type: "text", text: "read this" }, - { type: "file", url: `file://${dir}`, filename: "dir", mime: "application/x-directory" }, - ], - }) - .pipe(Effect.forkChild) + const fiber = yield* prompt + .prompt({ + sessionID: chat.id, + agent: "build", + parts: [ + { type: "text", text: "read this" }, + { type: "file", url: `file://${dir}`, filename: "dir", mime: "application/x-directory" }, + ], + }) + .pipe(Effect.forkChild) - yield* Effect.promise(() => ready.promise) - yield* Fiber.interrupt(fiber) - - yield* Effect.promise(() => - Promise.race([ - aborted.promise, - new Promise((_, reject) => - setTimeout(() => reject(new Error("abort signal not propagated within 2s")), 2_000), - ), - ]), - ) - }), - { git: true, config: cfg }, - ), + yield* awaitWithTimeout(Deferred.await(ready), "timed out waiting for read tool to start", "10 seconds") + yield* prompt.cancel(chat.id) + yield* Fiber.interrupt(fiber) + const exit = yield* Fiber.await(fiber) + expect(Exit.isFailure(exit)).toBe(true) + }), + { git: true, config: cfg }, 30_000, ) // Missing file handling -it.live("does not fail the prompt when a file part is missing", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) +it.instance( + "does not fail the prompt when a file part is missing", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) - const missing = path.join(dir, "does-not-exist.ts") - const msg = yield* prompt.prompt({ - sessionID: session.id, - agent: "build", - noReply: true, - parts: [ - { type: "text", text: "please review @does-not-exist.ts" }, - { - type: "file", - mime: "text/plain", - url: `file://${missing}`, - filename: "does-not-exist.ts", - }, - ], - }) + const missing = path.join(dir, "does-not-exist.ts") + const msg = yield* prompt.prompt({ + sessionID: session.id, + agent: "build", + noReply: true, + parts: [ + { type: "text", text: "please review @does-not-exist.ts" }, + { + type: "file", + mime: "text/plain", + url: `file://${missing}`, + filename: "does-not-exist.ts", + }, + ], + }) - if (msg.info.role !== "user") throw new Error("expected user message") - const hasFailure = msg.parts.some( - (part) => part.type === "text" && part.synthetic && part.text.includes("Read tool failed to read"), - ) - expect(hasFailure).toBe(true) + if (msg.info.role !== "user") throw new Error("expected user message") + const hasFailure = msg.parts.some( + (part) => part.type === "text" && part.synthetic && part.text.includes("Read tool failed to read"), + ) + expect(hasFailure).toBe(true) - yield* sessions.remove(session.id) - }), - { git: true, config: cfg }, - ), + yield* sessions.remove(session.id) + }), + { git: true, config: cfg }, ) -it.live("keeps stored part order stable when file resolution is async", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) +it.instance( + "keeps stored part order stable when file resolution is async", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) - const missing = path.join(dir, "still-missing.ts") - const msg = yield* prompt.prompt({ - sessionID: session.id, - agent: "build", - noReply: true, - parts: [ - { - type: "file", - mime: "text/plain", - url: `file://${missing}`, - filename: "still-missing.ts", - }, - { type: "text", text: "after-file" }, - ], - }) + const missing = path.join(dir, "still-missing.ts") + const msg = yield* prompt.prompt({ + sessionID: session.id, + agent: "build", + noReply: true, + parts: [ + { + type: "file", + mime: "text/plain", + url: `file://${missing}`, + filename: "still-missing.ts", + }, + { type: "text", text: "after-file" }, + ], + }) - if (msg.info.role !== "user") throw new Error("expected user message") + if (msg.info.role !== "user") throw new Error("expected user message") - const stored = MessageV2.get({ - sessionID: session.id, - messageID: msg.info.id, - }) - const text = stored.parts.filter((part) => part.type === "text").map((part) => part.text) + const stored = yield* MessageV2.get({ + sessionID: session.id, + messageID: msg.info.id, + }) + const text = stored.parts.filter((part) => part.type === "text").map((part) => part.text) - expect(text[0]?.startsWith("Called the Read tool with the following input:")).toBe(true) - expect(text[1]?.includes("Read tool failed to read")).toBe(true) - expect(text[2]).toBe("after-file") + expect(text[0]?.startsWith("Called the Read tool with the following input:")).toBe(true) + expect(text[1]?.includes("Read tool failed to read")).toBe(true) + expect(text[2]).toBe("after-file") - yield* sessions.remove(session.id) - }), - { git: true, config: cfg }, - ), + yield* sessions.remove(session.id) + }), + { git: true, config: cfg }, ) -it.live("resolves configured reference mentions before workspace paths and agents", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const docs = path.join(dir, "external-docs") - yield* Effect.promise(() => fs.mkdir(path.join(docs, "guide"), { recursive: true })) - yield* Effect.promise(() => fs.mkdir(path.join(dir, "docs"), { recursive: true })) - yield* Effect.promise(() => Bun.write(path.join(docs, "README.md"), "reference readme")) - yield* Effect.promise(() => Bun.write(path.join(docs, "guide", "intro.md"), "reference intro")) - yield* Effect.promise(() => Bun.write(path.join(dir, "docs", "README.md"), "workspace readme")) +it.instance( + "resolves configured reference mentions before workspace paths and agents", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const docs = path.join(dir, "external-docs") + yield* ensureDir(path.join(docs, "guide")) + yield* ensureDir(path.join(dir, "docs")) + yield* writeText(path.join(docs, "README.md"), "reference readme") + yield* writeText(path.join(docs, "guide", "intro.md"), "reference intro") + yield* writeText(path.join(dir, "docs", "README.md"), "workspace readme") - const prompt = yield* SessionPrompt.Service - const parts = yield* prompt.resolvePromptParts( - "Use @docs and @docs/README.md and @docs/guide and @docs/missing.md and @docs/README.md and @build", - ) - const references = parts.filter( - (part): part is MessageV2.TextPartInput => - part.type === "text" && part.synthetic === true && part.text.startsWith("Referenced configured reference "), - ) - const files = parts.filter((part): part is MessageV2.FilePartInput => part.type === "file") - const agents = parts.filter((part): part is MessageV2.AgentPartInput => part.type === "agent") - const bare = references.find((part) => part.text.includes("@docs.")) - const missing = references.find((part) => part.text.includes("@docs/missing.md")) - const guide = files.find((part) => part.filename === "docs/guide") + const prompt = yield* SessionPrompt.Service + const parts = yield* prompt.resolvePromptParts( + "Use @docs and @docs/README.md and @docs/guide and @docs/missing.md and @docs/README.md and @build", + ) + const references = parts.filter( + (part): part is MessageV2.TextPartInput => + part.type === "text" && part.synthetic === true && part.text.startsWith("Referenced configured reference "), + ) + const files = parts.filter((part): part is MessageV2.FilePartInput => part.type === "file") + const agents = parts.filter((part): part is MessageV2.AgentPartInput => part.type === "agent") + const bare = references.find((part) => part.text.includes("@docs.")) + const missing = references.find((part) => part.text.includes("@docs/missing.md")) + const guide = files.find((part) => part.filename === "docs/guide") - expect(references.length).toBe(2) - expect(bare?.metadata?.reference).toMatchObject({ - name: "docs", - kind: "local", - path: docs, - }) - expect(missing?.text).toContain("Path does not exist inside configured reference @docs") - expect(missing?.metadata?.reference).toMatchObject({ - target: "missing.md", - targetPath: path.join(docs, "missing.md"), - }) + expect(references.length).toBe(2) + expect(bare?.metadata?.reference).toMatchObject({ + name: "docs", + kind: "local", + path: docs, + }) + expect(missing?.text).toContain("Path does not exist inside configured reference @docs") + expect(missing?.metadata?.reference).toMatchObject({ + target: "missing.md", + targetPath: path.join(docs, "missing.md"), + }) - expect(files.length).toBe(2) - expect(files.map((file) => fileURLToPath(file.url)).sort()).toEqual( - [path.join(docs, "README.md"), path.join(docs, "guide")].sort(), - ) - expect(guide?.mime).toBe("application/x-directory") - expect(agents.map((agent) => agent.name)).toEqual(["build"]) - }), - { - git: true, - config: { - ...cfg, - reference: { - docs: "./external-docs", - }, + expect(files.length).toBe(2) + expect(files.map((file) => fileURLToPath(file.url)).sort()).toEqual( + [path.join(docs, "README.md"), path.join(docs, "guide")].sort(), + ) + expect(guide?.mime).toBe("application/x-directory") + expect(agents.map((agent) => agent.name)).toEqual(["build"]) + }), + { + git: true, + config: { + ...cfg, + reference: { + docs: "./external-docs", }, }, - ), + }, ) -it.live("injects metadata for bare configured reference mentions", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const docs = path.join(dir, "external-docs") - yield* Effect.promise(() => fs.mkdir(docs, { recursive: true })) +it.instance( + "injects metadata for bare configured reference mentions", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const docs = path.join(dir, "external-docs") + yield* ensureDir(docs) - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) - const message = yield* prompt.prompt({ - sessionID: session.id, - noReply: true, - parts: yield* prompt.resolvePromptParts("Use @docs for context"), - }) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) + const message = yield* prompt.prompt({ + sessionID: session.id, + noReply: true, + parts: yield* prompt.resolvePromptParts("Use @docs for context"), + }) - const stored = MessageV2.get({ sessionID: session.id, messageID: message.info.id }) - const synthetic = stored.parts.filter( - (part): part is MessageV2.TextPart => part.type === "text" && part.synthetic === true, - ) - const reference = synthetic.find((part) => part.text.startsWith("Referenced configured reference @docs.")) + const stored = yield* MessageV2.get({ sessionID: session.id, messageID: message.info.id }) + const synthetic = stored.parts.filter( + (part): part is MessageV2.TextPart => part.type === "text" && part.synthetic === true, + ) + const reference = synthetic.find((part) => part.text.startsWith("Referenced configured reference @docs.")) - expect(reference?.metadata?.reference).toMatchObject({ name: "docs", kind: "local", path: docs }) - expect(synthetic.some((part) => part.text.includes(`Reference root: ${docs}`))).toBe(true) - expect(synthetic.some((part) => part.text.includes("subagent scout"))).toBe(true) + expect(reference?.metadata?.reference).toMatchObject({ name: "docs", kind: "local", path: docs }) + expect(synthetic.some((part) => part.text.includes(`Reference root: ${docs}`))).toBe(true) + expect(synthetic.some((part) => part.text.includes("subagent scout"))).toBe(true) - yield* sessions.remove(session.id) - }), - { - git: true, - config: { - ...cfg, - reference: { - docs: "./external-docs", - }, + yield* sessions.remove(session.id) + }), + { + git: true, + config: { + ...cfg, + reference: { + docs: "./external-docs", }, }, - ), + }, ) -it.live("injects metadata for configured reference file attachments", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - const docs = path.join(dir, "external-docs") - const readme = path.join(docs, "README.md") - yield* Effect.promise(() => fs.mkdir(docs, { recursive: true })) - yield* Effect.promise(() => Bun.write(readme, "reference readme")) +it.instance( + "injects metadata for configured reference file attachments", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + const docs = path.join(dir, "external-docs") + const readme = path.join(docs, "README.md") + yield* ensureDir(docs) + yield* writeText(readme, "reference readme") - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) - const message = yield* prompt.prompt({ - sessionID: session.id, - agent: "build", - noReply: true, - parts: [ - { type: "text", text: "Read @docs/README.md" }, - { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) + const message = yield* prompt.prompt({ + sessionID: session.id, + agent: "build", + noReply: true, + parts: [ + { type: "text", text: "Read @docs/README.md" }, + { + type: "file", + mime: "text/plain", + filename: "docs/README.md", + url: pathToFileURL(readme).href, + source: { type: "file", - mime: "text/plain", - filename: "docs/README.md", - url: pathToFileURL(readme).href, - source: { - type: "file", - path: "docs/README.md", - text: { value: "@docs/README.md", start: 5, end: 20 }, - }, + path: "docs/README.md", + text: { value: "@docs/README.md", start: 5, end: 20 }, }, - ], - }) + }, + ], + }) - const stored = MessageV2.get({ sessionID: session.id, messageID: message.info.id }) - const synthetic = stored.parts.filter( - (part): part is MessageV2.TextPart => part.type === "text" && part.synthetic === true, - ) - const reference = synthetic.find((part) => - part.text.startsWith("Referenced configured reference @docs/README.md."), - ) + const stored = yield* MessageV2.get({ sessionID: session.id, messageID: message.info.id }) + const synthetic = stored.parts.filter( + (part): part is MessageV2.TextPart => part.type === "text" && part.synthetic === true, + ) + const reference = synthetic.find((part) => + part.text.startsWith("Referenced configured reference @docs/README.md."), + ) - expect(reference?.metadata?.reference).toMatchObject({ - name: "docs", - kind: "local", - path: docs, - target: "README.md", - targetPath: readme, - source: { value: "@docs/README.md", start: 5, end: 20 }, - }) - expect(synthetic.findIndex((part) => part === reference)).toBeLessThan( - synthetic.findIndex((part) => part.text.startsWith("Called the Read tool with the following input:")), - ) + expect(reference?.metadata?.reference).toMatchObject({ + name: "docs", + kind: "local", + path: docs, + target: "README.md", + targetPath: readme, + source: { value: "@docs/README.md", start: 5, end: 20 }, + }) + expect(synthetic.findIndex((part) => part === reference)).toBeLessThan( + synthetic.findIndex((part) => part.text.startsWith("Called the Read tool with the following input:")), + ) - yield* sessions.remove(session.id) - }), - { - git: true, - config: { - ...cfg, - reference: { - docs: "./external-docs", - }, + yield* sessions.remove(session.id) + }), + { + git: true, + config: { + ...cfg, + reference: { + docs: "./external-docs", }, }, - ), + }, ) // Special characters in filenames -it.live("handles filenames with # character", () => - provideTmpdirInstance( - (dir) => - Effect.gen(function* () { - yield* Effect.promise(() => Bun.write(path.join(dir, "file#name.txt"), "special content\n")) +it.instance( + "handles filenames with # character", + () => + Effect.gen(function* () { + const { directory: dir } = yield* TestInstance + yield* writeText(path.join(dir, "file#name.txt"), "special content\n") - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) - const parts = yield* prompt.resolvePromptParts("Read @file#name.txt") - const fileParts = parts.filter((part) => part.type === "file") + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) + const parts = yield* prompt.resolvePromptParts("Read @file#name.txt") + const fileParts = parts.filter((part) => part.type === "file") - expect(fileParts.length).toBe(1) - expect(fileParts[0].filename).toBe("file#name.txt") - expect(fileParts[0].url).toContain("%23") + expect(fileParts.length).toBe(1) + expect(fileParts[0].filename).toBe("file#name.txt") + expect(fileParts[0].url).toContain("%23") - const decodedPath = fileURLToPath(fileParts[0].url) - expect(decodedPath).toBe(path.join(dir, "file#name.txt")) + const decodedPath = fileURLToPath(fileParts[0].url) + expect(decodedPath).toBe(path.join(dir, "file#name.txt")) - const message = yield* prompt.prompt({ - sessionID: session.id, - parts, - noReply: true, - }) - const stored = MessageV2.get({ sessionID: session.id, messageID: message.info.id }) - const textParts = stored.parts.filter((part) => part.type === "text") - const hasContent = textParts.some((part) => part.text.includes("special content")) - expect(hasContent).toBe(true) + const message = yield* prompt.prompt({ + sessionID: session.id, + parts, + noReply: true, + }) + const stored = yield* MessageV2.get({ sessionID: session.id, messageID: message.info.id }) + const textParts = stored.parts.filter((part) => part.type === "text") + const hasContent = textParts.some((part) => part.text.includes("special content")) + expect(hasContent).toBe(true) - yield* sessions.remove(session.id) - }), - { git: true, config: cfg }, - ), + yield* sessions.remove(session.id) + }), + { git: true, config: cfg }, ) // Regression: empty assistant turn loop -it.live("does not loop empty assistant turns for a simple reply", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { +it.instance( + "does not loop empty assistant turns for a simple reply", + () => + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) const prompt = yield* SessionPrompt.Service const sessions = yield* Session.Service const session = yield* sessions.create({ title: "Prompt regression" }) @@ -2016,222 +2033,210 @@ it.live("does not loop empty assistant turns for a simple reply", () => expect(msgs.filter((msg) => msg.info.role === "assistant")).toHaveLength(1) expect(yield* llm.calls).toBe(1) }), - { git: true, config: providerCfg }, - ), + { git: true }, ) -it.live( +it.instance( "records aborted errors when prompt is cancelled mid-stream", () => - provideTmpdirServer( - Effect.fnUntraced(function* ({ llm }) { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({ title: "Prompt cancel regression" }) + Effect.gen(function* () { + const { llm } = yield* useServerConfig(providerCfg) + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({ title: "Prompt cancel regression" }) - yield* llm.hang + yield* llm.hang - const fiber = yield* prompt - .prompt({ - sessionID: session.id, - agent: "build", - parts: [{ type: "text", text: "Cancel me" }], - }) - .pipe(Effect.forkChild) + const fiber = yield* prompt + .prompt({ + sessionID: session.id, + agent: "build", + parts: [{ type: "text", text: "Cancel me" }], + }) + .pipe(Effect.forkChild) - yield* llm.wait(1) - yield* prompt.cancel(session.id) + yield* llm.wait(1) + yield* prompt.cancel(session.id) - const exit = yield* Fiber.await(fiber) - expect(Exit.isSuccess(exit)).toBe(true) - if (Exit.isSuccess(exit)) { - expect(exit.value.info.role).toBe("assistant") - if (exit.value.info.role === "assistant") { - expect(exit.value.info.error?.name).toBe("MessageAbortedError") - } + const exit = yield* Fiber.await(fiber) + expect(Exit.isSuccess(exit)).toBe(true) + if (Exit.isSuccess(exit)) { + expect(exit.value.info.role).toBe("assistant") + if (exit.value.info.role === "assistant") { + expect(exit.value.info.error?.name).toBe("MessageAbortedError") } + } - const msgs = yield* sessions.messages({ sessionID: session.id }) - const last = msgs.findLast((msg) => msg.info.role === "assistant") - expect(last?.info.role).toBe("assistant") - if (last?.info.role === "assistant") { - expect(last.info.error?.name).toBe("MessageAbortedError") - } - }), - { git: true, config: providerCfg }, - ), + const msgs = yield* sessions.messages({ sessionID: session.id }) + const last = msgs.findLast((msg) => msg.info.role === "assistant") + expect(last?.info.role).toBe("assistant") + if (last?.info.role === "assistant") { + expect(last.info.error?.name).toBe("MessageAbortedError") + } + }), + { git: true }, 3_000, ) // Agent variant -it.live("applies agent variant only when using agent model", () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) +it.instance( + "applies agent variant only when using agent model", + () => + Effect.gen(function* () { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) - const other = yield* prompt.prompt({ - sessionID: session.id, - agent: "build", - model: { providerID: ProviderID.make("opencode"), modelID: ModelID.make("kimi-k2.5-free") }, - noReply: true, - parts: [{ type: "text", text: "hello" }], - }) - if (other.info.role !== "user") throw new Error("expected user message") - expect(other.info.model.variant).toBeUndefined() + const other = yield* prompt.prompt({ + sessionID: session.id, + agent: "build", + model: { providerID: ProviderID.make("opencode"), modelID: ModelID.make("kimi-k2.5-free") }, + noReply: true, + parts: [{ type: "text", text: "hello" }], + }) + if (other.info.role !== "user") throw new Error("expected user message") + expect(other.info.model.variant).toBeUndefined() - const match = yield* prompt.prompt({ - sessionID: session.id, - agent: "build", - noReply: true, - parts: [{ type: "text", text: "hello again" }], - }) - if (match.info.role !== "user") throw new Error("expected user message") - expect(match.info.model).toEqual({ - providerID: ProviderID.make("test"), - modelID: ModelID.make("test-model"), - variant: "xhigh", - }) - expect(match.info.model.variant).toBe("xhigh") + const match = yield* prompt.prompt({ + sessionID: session.id, + agent: "build", + noReply: true, + parts: [{ type: "text", text: "hello again" }], + }) + if (match.info.role !== "user") throw new Error("expected user message") + expect(match.info.model).toEqual({ + providerID: ProviderID.make("test"), + modelID: ModelID.make("test-model"), + variant: "xhigh", + }) + expect(match.info.model.variant).toBe("xhigh") - const override = yield* prompt.prompt({ - sessionID: session.id, - agent: "build", - noReply: true, - variant: "high", - parts: [{ type: "text", text: "hello third" }], - }) - if (override.info.role !== "user") throw new Error("expected user message") - expect(override.info.model.variant).toBe("high") + const override = yield* prompt.prompt({ + sessionID: session.id, + agent: "build", + noReply: true, + variant: "high", + parts: [{ type: "text", text: "hello third" }], + }) + if (override.info.role !== "user") throw new Error("expected user message") + expect(override.info.model.variant).toBe("high") - yield* sessions.remove(session.id) - }), - { - git: true, - config: { - ...cfg, - provider: { - ...cfg.provider, - test: { - ...cfg.provider.test, - models: { - "test-model": { - ...cfg.provider.test.models["test-model"], - variants: { xhigh: {}, high: {} }, - }, + yield* sessions.remove(session.id) + }), + { + git: true, + config: { + ...cfg, + provider: { + ...cfg.provider, + test: { + ...cfg.provider.test, + models: { + "test-model": { + ...cfg.provider.test.models["test-model"], + variants: { xhigh: {}, high: {} }, }, }, }, - agent: { - build: { - model: "test/test-model", - variant: "xhigh", - }, + }, + agent: { + build: { + model: "test/test-model", + variant: "xhigh", }, }, }, - ), + }, ) // Agent / command resolution errors -it.live( +it.instance( "unknown agent throws typed error", () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) - const exit = yield* prompt - .prompt({ - sessionID: session.id, - agent: "nonexistent-agent-xyz", - noReply: true, - parts: [{ type: "text", text: "hello" }], - }) - .pipe(Effect.exit) + Effect.gen(function* () { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) + const exit = yield* prompt + .prompt({ + sessionID: session.id, + agent: "nonexistent-agent-xyz", + noReply: true, + parts: [{ type: "text", text: "hello" }], + }) + .pipe(Effect.exit) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) { - const err = Cause.squash(exit.cause) - expect(err).not.toBeInstanceOf(TypeError) - expect(NamedError.Unknown.isInstance(err)).toBe(true) - if (NamedError.Unknown.isInstance(err)) { - expect(err.data.message).toContain('Agent not found: "nonexistent-agent-xyz"') - } - } - }), - { git: true }, - ), + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const err = Cause.squash(exit.cause) + expect(err).not.toBeInstanceOf(TypeError) + expect(NamedError.Unknown.isInstance(err)).toBe(true) + if (NamedError.Unknown.isInstance(err)) { + expect(err.data.message).toContain('Agent not found: "nonexistent-agent-xyz"') + } + } + }), + { git: true }, 30_000, ) -it.live( +it.instance( "unknown agent error includes available agent names", () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) - const exit = yield* prompt - .prompt({ - sessionID: session.id, - agent: "nonexistent-agent-xyz", - noReply: true, - parts: [{ type: "text", text: "hello" }], - }) - .pipe(Effect.exit) + Effect.gen(function* () { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) + const exit = yield* prompt + .prompt({ + sessionID: session.id, + agent: "nonexistent-agent-xyz", + noReply: true, + parts: [{ type: "text", text: "hello" }], + }) + .pipe(Effect.exit) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) { - const err = Cause.squash(exit.cause) - expect(NamedError.Unknown.isInstance(err)).toBe(true) - if (NamedError.Unknown.isInstance(err)) { - expect(err.data.message).toContain("build") - } - } - }), - { git: true }, - ), + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const err = Cause.squash(exit.cause) + expect(NamedError.Unknown.isInstance(err)).toBe(true) + if (NamedError.Unknown.isInstance(err)) { + expect(err.data.message).toContain("build") + } + } + }), + { git: true }, 30_000, ) -it.live( +it.instance( "unknown command throws typed error with available names", () => - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({}) - const exit = yield* prompt - .command({ - sessionID: session.id, - command: "nonexistent-command-xyz", - arguments: "", - }) - .pipe(Effect.exit) + Effect.gen(function* () { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({}) + const exit = yield* prompt + .command({ + sessionID: session.id, + command: "nonexistent-command-xyz", + arguments: "", + }) + .pipe(Effect.exit) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isFailure(exit)) { - const err = Cause.squash(exit.cause) - expect(err).not.toBeInstanceOf(TypeError) - expect(NamedError.Unknown.isInstance(err)).toBe(true) - if (NamedError.Unknown.isInstance(err)) { - expect(err.data.message).toContain('Command not found: "nonexistent-command-xyz"') - expect(err.data.message).toContain("init") - } - } - }), - { git: true }, - ), + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) { + const err = Cause.squash(exit.cause) + expect(err).not.toBeInstanceOf(TypeError) + expect(NamedError.Unknown.isInstance(err)).toBe(true) + if (NamedError.Unknown.isInstance(err)) { + expect(err.data.message).toContain('Command not found: "nonexistent-command-xyz"') + expect(err.data.message).toContain("init") + } + } + }), + { git: true }, 30_000, ) diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts index bb69e459bc..63920d2181 100644 --- a/packages/opencode/test/session/session.test.ts +++ b/packages/opencode/test/session/session.test.ts @@ -1,186 +1,185 @@ -import { describe, expect, test } from "bun:test" -import path from "path" +import { describe, expect } from "bun:test" +import { Deferred, Effect, Exit, Layer } from "effect" import { Session as SessionNs } from "@/session/session" -import { Bus } from "../../src/bus" +import { GlobalBus, type GlobalEvent } from "../../src/bus/global" import * as Log from "@opencode-ai/core/util/log" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { MessageV2 } from "../../src/session/message-v2" import { MessageID, PartID, type SessionID } from "../../src/session/schema" -import { AppRuntime } from "../../src/effect/app-runtime" -import { tmpdir } from "../fixture/fixture" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { provideInstance, tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" +import { Bus } from "@/bus" +import { Storage } from "@/storage/storage" +import { SyncEvent } from "@/sync" +import { RuntimeFlags } from "@/effect/runtime-flags" -const projectRoot = path.join(__dirname, "../..") void Log.init({ print: false }) -function create(input?: SessionNs.CreateInput) { - return AppRuntime.runPromise(SessionNs.Service.use((svc) => svc.create(input))) -} +const it = testEffect( + Layer.mergeAll( + SessionNs.layer.pipe( + Layer.provide(Bus.layer), + Layer.provide(Storage.defaultLayer), + Layer.provide(SyncEvent.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalWorkspaces: false })), + ), + CrossSpawnSpawner.defaultLayer, + ), +) -function get(id: SessionID) { - return AppRuntime.runPromise(SessionNs.Service.use((svc) => svc.get(id))) -} +const awaitDeferred = (deferred: Deferred.Deferred, message: string) => + Effect.race( + Deferred.await(deferred), + Effect.sleep("2 seconds").pipe(Effect.flatMap(() => Effect.fail(new Error(message)))), + ) -function remove(id: SessionID) { - return AppRuntime.runPromise(SessionNs.Service.use((svc) => svc.remove(id))) -} +const remove = (id: SessionID) => SessionNs.Service.use((svc) => svc.remove(id)) -function updateMessage(msg: T) { - return AppRuntime.runPromise(SessionNs.Service.use((svc) => svc.updateMessage(msg))) -} - -function updatePart(part: T) { - return AppRuntime.runPromise(SessionNs.Service.use((svc) => svc.updatePart(part))) +const subscribeGlobal = (type: string, callback: (event: NonNullable) => void) => { + const listener = (event: GlobalEvent) => { + if (event.payload?.type === type) callback(event.payload) + } + GlobalBus.on("event", listener) + return () => GlobalBus.off("event", listener) } describe("session.created event", () => { - test("should emit session.created event when session is created", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - let eventReceived = false - let receivedInfo: SessionNs.Info | undefined + it.instance("should emit session.created event when session is created", () => + Effect.gen(function* () { + const session = yield* SessionNs.Service + const received = yield* Deferred.make() - const unsub = Bus.subscribe(SessionNs.Event.Created, (event) => { - eventReceived = true - receivedInfo = event.properties.info as SessionNs.Info - }) + const unsub = subscribeGlobal(SessionNs.Event.Created.type, (event) => { + Deferred.doneUnsafe(received, Effect.succeed(event.properties.info as SessionNs.Info)) + }) + yield* Effect.addFinalizer(() => Effect.sync(unsub)) - const info = await create({}) - await new Promise((resolve) => setTimeout(resolve, 100)) - unsub() + const info = yield* session.create({}) + const receivedInfo = yield* awaitDeferred(received, "timed out waiting for session.created") - expect(eventReceived).toBe(true) - expect(receivedInfo).toBeDefined() - expect(receivedInfo?.id).toBe(info.id) - expect(receivedInfo?.projectID).toBe(info.projectID) - expect(receivedInfo?.directory).toBe(info.directory) - expect(receivedInfo?.path).toBe(info.path) - expect(receivedInfo?.title).toBe(info.title) + expect(receivedInfo.id).toBe(info.id) + expect(receivedInfo.projectID).toBe(info.projectID) + expect(receivedInfo.directory).toBe(info.directory) + expect(receivedInfo.path).toBe(info.path) + expect(receivedInfo.title).toBe(info.title) - await remove(info.id) - }, - }) - }) + yield* session.remove(info.id) + }), + ) - test("session.created event should be emitted before session.updated", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const events: string[] = [] + it.instance("session.created event should be emitted before session.updated", () => + Effect.gen(function* () { + const session = yield* SessionNs.Service + const events: string[] = [] + const received = yield* Deferred.make() + const push = (event: string) => { + events.push(event) + if (events.includes("created") && events.includes("updated")) { + Deferred.doneUnsafe(received, Effect.succeed(events)) + } + } - const unsubCreated = Bus.subscribe(SessionNs.Event.Created, () => { - events.push("created") - }) + const unsubCreated = subscribeGlobal(SessionNs.Event.Created.type, () => { + push("created") + }) + yield* Effect.addFinalizer(() => Effect.sync(unsubCreated)) - const unsubUpdated = Bus.subscribe(SessionNs.Event.Updated, () => { - events.push("updated") - }) + const unsubUpdated = subscribeGlobal(SessionNs.Event.Updated.type, () => { + push("updated") + }) + yield* Effect.addFinalizer(() => Effect.sync(unsubUpdated)) - const info = await create({}) - await new Promise((resolve) => setTimeout(resolve, 100)) - unsubCreated() - unsubUpdated() + const info = yield* session.create({}) + const receivedEvents = yield* awaitDeferred(received, "timed out waiting for session created/updated events") - expect(events).toContain("created") - expect(events).toContain("updated") - expect(events.indexOf("created")).toBeLessThan(events.indexOf("updated")) + expect(receivedEvents).toContain("created") + expect(receivedEvents).toContain("updated") + expect(receivedEvents.indexOf("created")).toBeLessThan(receivedEvents.indexOf("updated")) - await remove(info.id) - }, - }) - }) + yield* session.remove(info.id) + }), + ) }) describe("step-finish token propagation via Bus event", () => { - test( + it.instance( "non-zero tokens propagate through PartUpdated event", - async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const info = await create({}) + () => + Effect.gen(function* () { + const session = yield* SessionNs.Service + const info = yield* session.create({}) - const messageID = MessageID.ascending() - await updateMessage({ - id: messageID, - sessionID: info.id, - role: "user", - time: { created: Date.now() }, - agent: "user", - model: { providerID: "test", modelID: "test" }, - tools: {}, - mode: "", - } as unknown as MessageV2.Info) + const messageID = MessageID.ascending() + yield* session.updateMessage({ + id: messageID, + sessionID: info.id, + role: "user", + time: { created: Date.now() }, + agent: "user", + model: { providerID: "test", modelID: "test" }, + tools: {}, + mode: "", + } as unknown as MessageV2.Info) - // Bus subscribers receive readonly Schema.Type payloads; `MessageV2.Part` - // is the mutable domain type. Cast bridges the two — safe because the - // test only reads the value afterwards. - let received: MessageV2.Part | undefined - const unsub = Bus.subscribe(MessageV2.Event.PartUpdated, (event) => { - received = event.properties.part as MessageV2.Part - }) + // Bus subscribers receive readonly Schema.Type payloads; `MessageV2.Part` + // is the mutable domain type. Cast bridges the two — safe because the + // test only reads the value afterwards. + const received = yield* Deferred.make() + const unsub = subscribeGlobal(MessageV2.Event.PartUpdated.type, (event) => { + Deferred.doneUnsafe(received, Effect.succeed(event.properties.part as MessageV2.Part)) + }) + yield* Effect.addFinalizer(() => Effect.sync(unsub)) - const tokens = { - total: 1500, - input: 500, - output: 800, - reasoning: 200, - cache: { read: 100, write: 50 }, - } + const tokens = { + total: 1500, + input: 500, + output: 800, + reasoning: 200, + cache: { read: 100, write: 50 }, + } - const partInput = { - id: PartID.ascending(), - messageID, - sessionID: info.id, - type: "step-finish" as const, - reason: "stop", - cost: 0.005, - tokens, - } + const partInput = { + id: PartID.ascending(), + messageID, + sessionID: info.id, + type: "step-finish" as const, + reason: "stop", + cost: 0.005, + tokens, + } - await updatePart(partInput) - await new Promise((resolve) => setTimeout(resolve, 100)) + yield* session.updatePart(partInput) + const receivedPart = yield* awaitDeferred(received, "timed out waiting for message.part.updated") - expect(received).toBeDefined() - expect(received!.type).toBe("step-finish") - const finish = received as MessageV2.StepFinishPart - expect(finish.tokens.input).toBe(500) - expect(finish.tokens.output).toBe(800) - expect(finish.tokens.reasoning).toBe(200) - expect(finish.tokens.total).toBe(1500) - expect(finish.tokens.cache.read).toBe(100) - expect(finish.tokens.cache.write).toBe(50) - expect(finish.cost).toBe(0.005) - expect(received).not.toBe(partInput) + expect(receivedPart.type).toBe("step-finish") + const finish = receivedPart as MessageV2.StepFinishPart + expect(finish.tokens.input).toBe(500) + expect(finish.tokens.output).toBe(800) + expect(finish.tokens.reasoning).toBe(200) + expect(finish.tokens.total).toBe(1500) + expect(finish.tokens.cache.read).toBe(100) + expect(finish.tokens.cache.write).toBe(50) + expect(finish.cost).toBe(0.005) + expect(receivedPart).not.toBe(partInput) - unsub() - await remove(info.id) - }, - }) - }, + yield* session.remove(info.id) + }), { timeout: 30000 }, ) }) describe("Session", () => { - test("remove works without an instance", async () => { - await using tmp = await tmpdir({ git: true }) + it.live("remove works without an instance", () => + Effect.gen(function* () { + const session = yield* SessionNs.Service + const dir = yield* tmpdirScoped({ git: true }) + const info = yield* provideInstance(dir)(session.create({ title: "remove-without-instance" })) - const info = await WithInstance.provide({ - directory: tmp.path, - fn: () => create({ title: "remove-without-instance" }), - }) + const removeExit = yield* remove(info.id).pipe(Effect.exit) + expect(Exit.isSuccess(removeExit)).toBe(true) - await expect(async () => { - await remove(info.id) - }).not.toThrow() - - let missing = false - await get(info.id).catch(() => { - missing = true - }) - - expect(missing).toBe(true) - }) + const getExit = yield* session.get(info.id).pipe(Effect.exit) + expect(Exit.isFailure(getExit)).toBe(true) + }), + ) }) diff --git a/packages/opencode/test/session/snapshot-tool-race.test.ts b/packages/opencode/test/session/snapshot-tool-race.test.ts index 8640612e98..28565699bc 100644 --- a/packages/opencode/test/session/snapshot-tool-race.test.ts +++ b/packages/opencode/test/session/snapshot-tool-race.test.ts @@ -59,6 +59,7 @@ import { Ripgrep } from "../../src/file/ripgrep" import { Format } from "../../src/format" import { Reference } from "../../src/reference/reference" import { SyncEvent } from "@/sync" +import { RuntimeFlags } from "@/effect/runtime-flags" void Log.init({ print: false }) @@ -137,6 +138,7 @@ function makeHttp() { Layer.provide(Reference.defaultLayer), Layer.provide(Ripgrep.defaultLayer), Layer.provide(Format.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), Layer.provideMerge(todo), Layer.provideMerge(question), Layer.provideMerge(deps), @@ -145,9 +147,14 @@ function makeHttp() { const proc = SessionProcessor.layer.pipe( Layer.provide(SessionSummary.defaultLayer), Layer.provide(Image.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), + Layer.provideMerge(deps), + ) + const compact = SessionCompaction.layer.pipe( + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), + Layer.provideMerge(proc), Layer.provideMerge(deps), ) - const compact = SessionCompaction.layer.pipe(Layer.provideMerge(proc), Layer.provideMerge(deps)) return Layer.mergeAll( TestLLMServer.layer, SessionSummary.defaultLayer, @@ -163,6 +170,7 @@ function makeHttp() { Layer.provideMerge(trunc), Layer.provide(Instruction.defaultLayer), Layer.provide(SystemPrompt.defaultLayer), + Layer.provide(RuntimeFlags.layer({ experimentalEventSystem: true })), Layer.provideMerge(deps), ), ) diff --git a/packages/opencode/test/session/structured-output-integration.test.ts b/packages/opencode/test/session/structured-output-integration.test.ts index da2ffb7937..125c63c0f9 100644 --- a/packages/opencode/test/session/structured-output-integration.test.ts +++ b/packages/opencode/test/session/structured-output-integration.test.ts @@ -1,250 +1,219 @@ import { describe, expect, test } from "bun:test" -import path from "path" import { Effect, Layer } from "effect" import { Session } from "@/session/session" import { SessionPrompt } from "../../src/session/prompt" import * as Log from "@opencode-ai/core/util/log" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { MessageV2 } from "../../src/session/message-v2" +import { testEffect } from "../lib/effect" -const projectRoot = path.join(__dirname, "../..") void Log.init({ print: false }) // Skip tests if no API key is available const hasApiKey = !!process.env.ANTHROPIC_API_KEY - -// Helper to run test within Instance context -async function withInstance(fn: () => Promise): Promise { - return WithInstance.provide({ - directory: projectRoot, - fn, - }) -} - -function run(fx: Effect.Effect) { - return Effect.runPromise( - fx.pipe(Effect.scoped, Effect.provide(Layer.mergeAll(SessionPrompt.defaultLayer, Session.defaultLayer))), - ) -} +const it = testEffect(Layer.mergeAll(SessionPrompt.defaultLayer, Session.defaultLayer)) +const live = hasApiKey ? it.instance : it.instance.skip describe("StructuredOutput Integration", () => { - test.skipIf(!hasApiKey)( + live( "produces structured output with simple schema", - async () => { - await withInstance(() => - run( - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({ title: "Structured Output Test" }) + () => + Effect.gen(function* () { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({ title: "Structured Output Test" }) - const result = yield* prompt.prompt({ - sessionID: session.id, - parts: [ - { - type: "text", - text: "What is 2 + 2? Provide a simple answer.", - }, - ], - format: { - type: "json_schema", - schema: { - type: "object", - properties: { - answer: { type: "number", description: "The numerical answer" }, - explanation: { type: "string", description: "Brief explanation" }, - }, - required: ["answer"], - }, - retryCount: 0, + const result = yield* prompt.prompt({ + sessionID: session.id, + parts: [ + { + type: "text", + text: "What is 2 + 2? Provide a simple answer.", + }, + ], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + answer: { type: "number", description: "The numerical answer" }, + explanation: { type: "string", description: "Brief explanation" }, }, - }) + required: ["answer"], + }, + retryCount: 0, + }, + }) - // Verify structured output was captured (only on assistant messages) - expect(result.info.role).toBe("assistant") - if (result.info.role === "assistant") { - expect(result.info.structured).toBeDefined() - expect(typeof result.info.structured).toBe("object") + // Verify structured output was captured (only on assistant messages) + expect(result.info.role).toBe("assistant") + if (result.info.role === "assistant") { + expect(result.info.structured).toBeDefined() + expect(typeof result.info.structured).toBe("object") - const output = result.info.structured as any - expect(output.answer).toBe(4) + const output = result.info.structured as any + expect(output.answer).toBe(4) - // Verify no error was set - expect(result.info.error).toBeUndefined() - } + // Verify no error was set + expect(result.info.error).toBeUndefined() + } - // Clean up - // Note: Not removing session to avoid race with background SessionSummary.summarize - }), - ), - ) - }, + // Clean up + // Note: Not removing session to avoid race with background SessionSummary.summarize + }), + { git: true }, 60000, ) - test.skipIf(!hasApiKey)( + live( "produces structured output with nested objects", - async () => { - await withInstance(() => - run( - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({ title: "Nested Schema Test" }) + () => + Effect.gen(function* () { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({ title: "Nested Schema Test" }) - const result = yield* prompt.prompt({ - sessionID: session.id, - parts: [ - { - type: "text", - text: "Tell me about Anthropic company in a structured format.", - }, - ], - format: { - type: "json_schema", - schema: { + const result = yield* prompt.prompt({ + sessionID: session.id, + parts: [ + { + type: "text", + text: "Tell me about Anthropic company in a structured format.", + }, + ], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + company: { type: "object", properties: { - company: { - type: "object", - properties: { - name: { type: "string" }, - founded: { type: "number" }, - }, - required: ["name", "founded"], - }, - products: { - type: "array", - items: { type: "string" }, - }, + name: { type: "string" }, + founded: { type: "number" }, }, - required: ["company"], + required: ["name", "founded"], + }, + products: { + type: "array", + items: { type: "string" }, }, - retryCount: 0, }, - }) + required: ["company"], + }, + retryCount: 0, + }, + }) - // Verify structured output was captured (only on assistant messages) - expect(result.info.role).toBe("assistant") - if (result.info.role === "assistant") { - expect(result.info.structured).toBeDefined() - const output = result.info.structured as any + // Verify structured output was captured (only on assistant messages) + expect(result.info.role).toBe("assistant") + if (result.info.role === "assistant") { + expect(result.info.structured).toBeDefined() + const output = result.info.structured as any - expect(output.company).toBeDefined() - expect(output.company.name).toBe("Anthropic") - expect(typeof output.company.founded).toBe("number") + expect(output.company).toBeDefined() + expect(output.company.name).toBe("Anthropic") + expect(typeof output.company.founded).toBe("number") - if (output.products) { - expect(Array.isArray(output.products)).toBe(true) - } + if (output.products) { + expect(Array.isArray(output.products)).toBe(true) + } - // Verify no error was set - expect(result.info.error).toBeUndefined() - } + // Verify no error was set + expect(result.info.error).toBeUndefined() + } - // Clean up - // Note: Not removing session to avoid race with background SessionSummary.summarize - }), - ), - ) - }, + // Clean up + // Note: Not removing session to avoid race with background SessionSummary.summarize + }), + { git: true }, 60000, ) - test.skipIf(!hasApiKey)( + live( "works with text outputFormat (default)", - async () => { - await withInstance(() => - run( - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({ title: "Text Output Test" }) + () => + Effect.gen(function* () { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({ title: "Text Output Test" }) - const result = yield* prompt.prompt({ - sessionID: session.id, - parts: [ - { - type: "text", - text: "Say hello.", - }, - ], - format: { - type: "text", - }, - }) + const result = yield* prompt.prompt({ + sessionID: session.id, + parts: [ + { + type: "text", + text: "Say hello.", + }, + ], + format: { + type: "text", + }, + }) - // Verify no structured output (text mode) and no error - expect(result.info.role).toBe("assistant") - if (result.info.role === "assistant") { - expect(result.info.structured).toBeUndefined() - expect(result.info.error).toBeUndefined() - } + // Verify no structured output (text mode) and no error + expect(result.info.role).toBe("assistant") + if (result.info.role === "assistant") { + expect(result.info.structured).toBeUndefined() + expect(result.info.error).toBeUndefined() + } - // Verify we got a response with parts - expect(result.parts.length).toBeGreaterThan(0) + // Verify we got a response with parts + expect(result.parts.length).toBeGreaterThan(0) - // Clean up - // Note: Not removing session to avoid race with background SessionSummary.summarize - }), - ), - ) - }, + // Clean up + // Note: Not removing session to avoid race with background SessionSummary.summarize + }), + { git: true }, 60000, ) - test.skipIf(!hasApiKey)( + live( "stores outputFormat on user message", - async () => { - await withInstance(() => - run( - Effect.gen(function* () { - const prompt = yield* SessionPrompt.Service - const sessions = yield* Session.Service - const session = yield* sessions.create({ title: "OutputFormat Storage Test" }) + () => + Effect.gen(function* () { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const session = yield* sessions.create({ title: "OutputFormat Storage Test" }) - yield* prompt.prompt({ - sessionID: session.id, - parts: [ - { - type: "text", - text: "What is 1 + 1?", - }, - ], - format: { - type: "json_schema", - schema: { - type: "object", - properties: { - result: { type: "number" }, - }, - required: ["result"], - }, - retryCount: 3, + yield* prompt.prompt({ + sessionID: session.id, + parts: [ + { + type: "text", + text: "What is 1 + 1?", + }, + ], + format: { + type: "json_schema", + schema: { + type: "object", + properties: { + result: { type: "number" }, }, - }) + required: ["result"], + }, + retryCount: 3, + }, + }) - // Get all messages from session - const messages = yield* sessions.messages({ sessionID: session.id }) - const userMessage = messages.find((m) => m.info.role === "user") + // Get all messages from session + const messages = yield* sessions.messages({ sessionID: session.id }) + const userMessage = messages.find((m) => m.info.role === "user") - // Verify outputFormat was stored on user message - expect(userMessage).toBeDefined() - if (userMessage?.info.role === "user") { - expect(userMessage.info.format).toBeDefined() - expect(userMessage.info.format?.type).toBe("json_schema") - if (userMessage.info.format?.type === "json_schema") { - expect(userMessage.info.format.retryCount).toBe(3) - } - } + // Verify outputFormat was stored on user message + expect(userMessage).toBeDefined() + if (userMessage?.info.role === "user") { + expect(userMessage.info.format).toBeDefined() + expect(userMessage.info.format?.type).toBe("json_schema") + if (userMessage.info.format?.type === "json_schema") { + expect(userMessage.info.format.retryCount).toBe(3) + } + } - // Clean up - // Note: Not removing session to avoid race with background SessionSummary.summarize - }), - ), - ) - }, + // Clean up + // Note: Not removing session to avoid race with background SessionSummary.summarize + }), + { git: true }, 60000, ) diff --git a/packages/opencode/test/skill/discovery.test.ts b/packages/opencode/test/skill/discovery.test.ts index f4a17f25ce..074992c56c 100644 --- a/packages/opencode/test/skill/discovery.test.ts +++ b/packages/opencode/test/skill/discovery.test.ts @@ -1,10 +1,12 @@ -import { describe, test, expect, beforeAll, afterAll } from "bun:test" -import { Effect } from "effect" +import { describe, expect, beforeAll, afterAll } from "bun:test" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { Effect, Layer } from "effect" import { Discovery } from "../../src/skill/discovery" import { Global } from "@opencode-ai/core/global" import { Filesystem } from "@/util/filesystem" import { rm } from "fs/promises" import path from "path" +import { testEffect } from "../lib/effect" let CLOUDFLARE_SKILLS_URL: string let server: ReturnType @@ -12,6 +14,7 @@ let downloadCount = 0 const fixturePath = path.join(import.meta.dir, "../fixture/skills") const cacheDir = path.join(Global.Path.cache, "skills") +const it = testEffect(Layer.mergeAll(Discovery.defaultLayer, AppFileSystem.defaultLayer)) beforeAll(async () => { await rm(cacheDir, { recursive: true, force: true }) @@ -47,70 +50,90 @@ afterAll(async () => { }) describe("Discovery.pull", () => { - const pull = (url: string) => - Effect.runPromise(Discovery.Service.use((s) => s.pull(url)).pipe(Effect.provide(Discovery.defaultLayer))) + it.live("downloads skills from cloudflare url", () => + Effect.gen(function* () { + const fsys = yield* AppFileSystem.Service + const discovery = yield* Discovery.Service + const dirs = yield* discovery.pull(CLOUDFLARE_SKILLS_URL) + expect(dirs.length).toBeGreaterThan(0) + for (const dir of dirs) { + expect(dir).toStartWith(cacheDir) + const md = path.join(dir, "SKILL.md") + expect(yield* fsys.existsSafe(md)).toBe(true) + } + }), + ) - test("downloads skills from cloudflare url", async () => { - const dirs = await pull(CLOUDFLARE_SKILLS_URL) - expect(dirs.length).toBeGreaterThan(0) - for (const dir of dirs) { - expect(dir).toStartWith(cacheDir) - const md = path.join(dir, "SKILL.md") - expect(await Filesystem.exists(md)).toBe(true) - } - }) + it.live("url without trailing slash works", () => + Effect.gen(function* () { + const fsys = yield* AppFileSystem.Service + const discovery = yield* Discovery.Service + const dirs = yield* discovery.pull(CLOUDFLARE_SKILLS_URL.replace(/\/$/, "")) + expect(dirs.length).toBeGreaterThan(0) + for (const dir of dirs) { + const md = path.join(dir, "SKILL.md") + expect(yield* fsys.existsSafe(md)).toBe(true) + } + }), + ) - test("url without trailing slash works", async () => { - const dirs = await pull(CLOUDFLARE_SKILLS_URL.replace(/\/$/, "")) - expect(dirs.length).toBeGreaterThan(0) - for (const dir of dirs) { - const md = path.join(dir, "SKILL.md") - expect(await Filesystem.exists(md)).toBe(true) - } - }) + it.live("returns empty array for invalid url", () => + Effect.gen(function* () { + const discovery = yield* Discovery.Service + const dirs = yield* discovery.pull(`http://localhost:${server.port}/invalid-url/`) + expect(dirs).toEqual([]) + }), + ) - test("returns empty array for invalid url", async () => { - const dirs = await pull(`http://localhost:${server.port}/invalid-url/`) - expect(dirs).toEqual([]) - }) + it.live("returns empty array for non-json response", () => + Effect.gen(function* () { + // any url not explicitly handled in server returns 404 text "Not Found" + const discovery = yield* Discovery.Service + const dirs = yield* discovery.pull(`http://localhost:${server.port}/some-other-path/`) + expect(dirs).toEqual([]) + }), + ) - test("returns empty array for non-json response", async () => { - // any url not explicitly handled in server returns 404 text "Not Found" - const dirs = await pull(`http://localhost:${server.port}/some-other-path/`) - expect(dirs).toEqual([]) - }) + it.live("downloads reference files alongside SKILL.md", () => + Effect.gen(function* () { + const fsys = yield* AppFileSystem.Service + const discovery = yield* Discovery.Service + const dirs = yield* discovery.pull(CLOUDFLARE_SKILLS_URL) + // find a skill dir that should have reference files (e.g. agents-sdk) + const agentsSdk = dirs.find((d) => d.endsWith(path.sep + "agents-sdk")) + expect(agentsSdk).toBeDefined() + if (agentsSdk) { + const refs = path.join(agentsSdk, "references") + expect(yield* fsys.existsSafe(path.join(agentsSdk, "SKILL.md"))).toBe(true) + // agents-sdk has reference files per the index + const refDir = yield* Effect.promise(() => + Array.fromAsync(new Bun.Glob("**/*.md").scan({ cwd: refs, onlyFiles: true })), + ) + expect(refDir.length).toBeGreaterThan(0) + } + }), + ) - test("downloads reference files alongside SKILL.md", async () => { - const dirs = await pull(CLOUDFLARE_SKILLS_URL) - // find a skill dir that should have reference files (e.g. agents-sdk) - const agentsSdk = dirs.find((d) => d.endsWith(path.sep + "agents-sdk")) - expect(agentsSdk).toBeDefined() - if (agentsSdk) { - const refs = path.join(agentsSdk, "references") - expect(await Filesystem.exists(path.join(agentsSdk, "SKILL.md"))).toBe(true) - // agents-sdk has reference files per the index - const refDir = await Array.fromAsync(new Bun.Glob("**/*.md").scan({ cwd: refs, onlyFiles: true })) - expect(refDir.length).toBeGreaterThan(0) - } - }) + it.live("caches downloaded files on second pull", () => + Effect.gen(function* () { + // clear dir and downloadCount + yield* Effect.promise(() => rm(cacheDir, { recursive: true, force: true })) + downloadCount = 0 + const discovery = yield* Discovery.Service - test("caches downloaded files on second pull", async () => { - // clear dir and downloadCount - await rm(cacheDir, { recursive: true, force: true }) - downloadCount = 0 + // first pull to populate cache + const first = yield* discovery.pull(CLOUDFLARE_SKILLS_URL) + expect(first.length).toBeGreaterThan(0) + const firstCount = downloadCount + expect(firstCount).toBeGreaterThan(0) - // first pull to populate cache - const first = await pull(CLOUDFLARE_SKILLS_URL) - expect(first.length).toBeGreaterThan(0) - const firstCount = downloadCount - expect(firstCount).toBeGreaterThan(0) + // second pull should return same results from cache + const second = yield* discovery.pull(CLOUDFLARE_SKILLS_URL) + expect(second.length).toBe(first.length) + expect(second.sort()).toEqual(first.sort()) - // second pull should return same results from cache - const second = await pull(CLOUDFLARE_SKILLS_URL) - expect(second.length).toBe(first.length) - expect(second.sort()).toEqual(first.sort()) - - // second pull should NOT increment download count - expect(downloadCount).toBe(firstCount) - }) + // second pull should NOT increment download count + expect(downloadCount).toBe(firstCount) + }), + ) }) diff --git a/packages/opencode/test/snapshot/snapshot.test.ts b/packages/opencode/test/snapshot/snapshot.test.ts index fa167281b9..de60d58b2d 100644 --- a/packages/opencode/test/snapshot/snapshot.test.ts +++ b/packages/opencode/test/snapshot/snapshot.test.ts @@ -1,15 +1,15 @@ import { afterEach, expect } from "bun:test" import { $ } from "bun" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { AppFileSystem } from "@opencode-ai/core/filesystem" import fs from "fs/promises" import path from "path" -import { Effect, Fiber } from "effect" +import { Effect, Fiber, Layer } from "effect" import { Snapshot } from "../../src/snapshot" -import { Filesystem } from "@/util/filesystem" import { disposeAllInstances, provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture" import { testEffect } from "../lib/effect" -const it = testEffect(Snapshot.defaultLayer) +const it = testEffect(Layer.mergeAll(Snapshot.defaultLayer, AppFileSystem.defaultLayer)) // Git always outputs /-separated paths internally. Snapshot.patch() joins them // with path.join (which produces \ on Windows) then normalizes back to /. @@ -27,17 +27,13 @@ const exec = (cwd: string, command: string[]) => if (code !== 0) throw new Error(`${command.join(" ")} failed: ${await new Response(proc.stderr).text()}`) }) -const write = (file: string, content: string | Uint8Array) => Effect.promise(() => Filesystem.write(file, content)) -const readText = (file: string) => Effect.promise(() => fs.readFile(file, "utf-8")) -const exists = (file: string) => - Effect.promise(() => - fs - .access(file) - .then(() => true) - .catch(() => false), - ) -const mkdirp = (dir: string) => Effect.promise(() => fs.mkdir(dir, { recursive: true })) -const rm = (file: string) => Effect.promise(() => fs.rm(file, { recursive: true, force: true })) +const write = (file: string, content: string | Uint8Array) => + AppFileSystem.Service.use((fs) => fs.writeWithDirs(file, content)) +const readText = (file: string) => AppFileSystem.Service.use((fs) => fs.readFileString(file)) +const exists = (file: string) => AppFileSystem.Service.use((fs) => fs.existsSafe(file)) +const mkdirp = (dir: string) => AppFileSystem.Service.use((fs) => fs.ensureDir(dir)) +const rm = (file: string) => + AppFileSystem.Service.use((fs) => fs.remove(file, { recursive: true, force: true }).pipe(Effect.ignore)) const initialize = Effect.fn("SnapshotTest.initialize")(function* (dir: string) { const unique = Math.random().toString(36).slice(2) diff --git a/packages/opencode/test/storage/storage.test.ts b/packages/opencode/test/storage/storage.test.ts index f0aff4ba78..d0fe5dd34c 100644 --- a/packages/opencode/test/storage/storage.test.ts +++ b/packages/opencode/test/storage/storage.test.ts @@ -74,20 +74,23 @@ describe("Storage", () => { it.live("maps missing reads to NotFoundError", () => Effect.gen(function* () { const { root, svc } = yield* scope() - const exit = yield* svc.read([...root, "missing", "value"]).pipe(Effect.exit) - expect(Exit.isFailure(exit)).toBe(true) + const error = yield* Effect.flip(svc.read([...root, "missing", "value"])) + expect(error).toBeInstanceOf(Storage.NotFoundError) + expect(error._tag).toBe("NotFoundError") + expect(error.message).toContain(path.join(...root, "missing", "value") + ".json") }), ) it.live("update on missing key throws NotFoundError", () => Effect.gen(function* () { const { root, svc } = yield* scope() - const exit = yield* svc - .update<{ value: number }>([...root, "missing", "key"], (draft) => { + const error = yield* Effect.flip( + svc.update<{ value: number }>([...root, "missing", "key"], (draft) => { draft.value += 1 - }) - .pipe(Effect.exit) - expect(Exit.isFailure(exit)).toBe(true) + }), + ) + expect(error).toBeInstanceOf(Storage.NotFoundError) + expect(error._tag).toBe("NotFoundError") }), ) diff --git a/packages/opencode/test/sync/index.test.ts b/packages/opencode/test/sync/index.test.ts index 10f593a571..c4e5b86062 100644 --- a/packages/opencode/test/sync/index.test.ts +++ b/packages/opencode/test/sync/index.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, beforeEach, afterEach, afterAll } from "bun:test" +import { describe, expect, beforeEach, afterAll } from "bun:test" import { provideTmpdirInstance } from "../fixture/fixture" import { Effect, Layer, Schema } from "effect" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" @@ -7,21 +7,19 @@ import { SyncEvent } from "../../src/sync" import { Database, eq } from "@/storage/db" import { EventSequenceTable, EventTable } from "../../src/sync/event.sql" import { MessageID } from "../../src/session/schema" -import { Flag } from "@opencode-ai/core/flag/flag" import { initProjectors } from "../../src/server/projectors" import { testEffect } from "../lib/effect" +import { RuntimeFlags } from "@/effect/runtime-flags" -const original = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES -const it = testEffect(Layer.mergeAll(SyncEvent.defaultLayer, CrossSpawnSpawner.defaultLayer)) +const it = testEffect( + Layer.mergeAll( + SyncEvent.layer.pipe(Layer.provide(RuntimeFlags.layer({ experimentalWorkspaces: true }))), + CrossSpawnSpawner.defaultLayer, + ), +) beforeEach(() => { Database.close() - - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true -}) - -afterEach(() => { - Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = original }) describe("SyncEvent", () => { diff --git a/packages/opencode/test/tool/apply_patch.test.ts b/packages/opencode/test/tool/apply_patch.test.ts index 3fc034e4e5..be5754f3b4 100644 --- a/packages/opencode/test/tool/apply_patch.test.ts +++ b/packages/opencode/test/tool/apply_patch.test.ts @@ -1,20 +1,19 @@ -import { describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import path from "path" import * as fs from "fs/promises" -import { Effect, ManagedRuntime, Layer } from "effect" +import { Cause, Effect, Exit, Layer } from "effect" import { ApplyPatchTool } from "../../src/tool/apply_patch" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { LSP } from "@/lsp/lsp" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { Format } from "../../src/format" import { Agent } from "../../src/agent/agent" import { Bus } from "../../src/bus" import { Truncate } from "@/tool/truncate" -import { tmpdir } from "../fixture/fixture" +import { TestInstance } from "../fixture/fixture" import { SessionID, MessageID } from "../../src/session/schema" +import { testEffect } from "../lib/effect" -const runtime = ManagedRuntime.make( +const it = testEffect( Layer.mergeAll( LSP.defaultLayer, AppFileSystem.defaultLayer, @@ -58,11 +57,11 @@ type ToolCtx = typeof baseCtx & { ask: (input: AskInput) => Effect.Effect } -const execute = async (params: { patchText: string }, ctx: ToolCtx) => { - const info = await runtime.runPromise(ApplyPatchTool) - const tool = await runtime.runPromise(info.init()) - return Effect.runPromise(tool.execute(params, ctx)) -} +const execute = Effect.fn("ApplyPatchToolTest.execute")(function* (params: { patchText: string }, ctx: ToolCtx) { + const info = yield* ApplyPatchTool + const tool = yield* info.init() + return yield* tool.execute(params, ctx) +}) const makeCtx = () => { const calls: AskInput[] = [] @@ -77,39 +76,56 @@ const makeCtx = () => { return { ctx, calls } } +const readText = (filepath: string) => Effect.promise(() => fs.readFile(filepath, "utf-8")) +const writeText = (filepath: string, content: string) => Effect.promise(() => fs.writeFile(filepath, content, "utf-8")) +const makeDir = (dir: string) => Effect.promise(() => fs.mkdir(dir, { recursive: true })) + +const expectFailure = (effect: Effect.Effect, message?: string) => + Effect.gen(function* () { + const exit = yield* Effect.exit(effect) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit) && message) expect(Cause.pretty(exit.cause)).toContain(message) + }) + +const expectReadFailure = (filepath: string) => expectFailure(readText(filepath)) + describe("tool.apply_patch freeform", () => { - test("requires patchText", async () => { - const { ctx } = makeCtx() - await expect(execute({ patchText: "" }, ctx)).rejects.toThrow("patchText is required") - }) + it.live("requires patchText", () => + Effect.gen(function* () { + const { ctx } = makeCtx() + yield* expectFailure(execute({ patchText: "" }, ctx), "patchText is required") + }), + ) - test("rejects invalid patch format", async () => { - const { ctx } = makeCtx() - await expect(execute({ patchText: "invalid patch" }, ctx)).rejects.toThrow("apply_patch verification failed") - }) + it.live("rejects invalid patch format", () => + Effect.gen(function* () { + const { ctx } = makeCtx() + yield* expectFailure(execute({ patchText: "invalid patch" }, ctx), "apply_patch verification failed") + }), + ) - test("rejects empty patch", async () => { - const { ctx } = makeCtx() - const emptyPatch = "*** Begin Patch\n*** End Patch" - await expect(execute({ patchText: emptyPatch }, ctx)).rejects.toThrow("patch rejected: empty patch") - }) + it.live("rejects empty patch", () => + Effect.gen(function* () { + const { ctx } = makeCtx() + yield* expectFailure(execute({ patchText: "*** Begin Patch\n*** End Patch" }, ctx), "patch rejected: empty patch") + }), + ) - test("applies add/update/delete in one patch", async () => { - await using fixture = await tmpdir({ git: true }) - const { ctx, calls } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const modifyPath = path.join(fixture.path, "modify.txt") - const deletePath = path.join(fixture.path, "delete.txt") - await fs.writeFile(modifyPath, "line1\nline2\n", "utf-8") - await fs.writeFile(deletePath, "obsolete\n", "utf-8") + it.instance( + "applies add/update/delete in one patch", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx, calls } = makeCtx() + const modifyPath = path.join(test.directory, "modify.txt") + const deletePath = path.join(test.directory, "delete.txt") + yield* writeText(modifyPath, "line1\nline2\n") + yield* writeText(deletePath, "obsolete\n") const patchText = "*** Begin Patch\n*** Add File: nested/new.txt\n+created\n*** Delete File: delete.txt\n*** Update File: modify.txt\n@@\n-line2\n+changed\n*** End Patch" - const result = await execute({ patchText }, ctx) + const result = yield* execute({ patchText }, ctx) expect(result.title).toContain("Success. Updated the following files") expect(result.output).toContain("Success. Updated the following files") @@ -129,38 +145,34 @@ describe("tool.apply_patch freeform", () => { expect(permissionCall.metadata.files.map((f) => f.type).sort()).toEqual(["add", "delete", "update"]) const addFile = permissionCall.metadata.files.find((f) => f.type === "add") - expect(addFile).toBeDefined() - expect(addFile!.relativePath).toBe("nested/new.txt") - expect(addFile!.patch).toContain("+created") + expect(addFile?.relativePath).toBe("nested/new.txt") + expect(addFile?.patch).toContain("+created") const updateFile = permissionCall.metadata.files.find((f) => f.type === "update") - expect(updateFile).toBeDefined() - expect(updateFile!.patch).toContain("-line2") - expect(updateFile!.patch).toContain("+changed") + expect(updateFile?.patch).toContain("-line2") + expect(updateFile?.patch).toContain("+changed") - const added = await fs.readFile(path.join(fixture.path, "nested", "new.txt"), "utf-8") - expect(added).toBe("created\n") - expect(await fs.readFile(modifyPath, "utf-8")).toBe("line1\nchanged\n") - await expect(fs.readFile(deletePath, "utf-8")).rejects.toThrow() - }, - }) - }) + expect(yield* readText(path.join(test.directory, "nested", "new.txt"))).toBe("created\n") + expect(yield* readText(modifyPath)).toBe("line1\nchanged\n") + yield* expectReadFailure(deletePath) + }), + { git: true }, + ) - test("permission metadata includes move file info", async () => { - await using fixture = await tmpdir({ git: true }) - const { ctx, calls } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const original = path.join(fixture.path, "old", "name.txt") - await fs.mkdir(path.dirname(original), { recursive: true }) - await fs.writeFile(original, "old content\n", "utf-8") + it.instance( + "permission metadata includes move file info", + () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx, calls } = makeCtx() + const original = path.join(test.directory, "old", "name.txt") + yield* makeDir(path.dirname(original)) + yield* writeText(original, "old content\n") const patchText = "*** Begin Patch\n*** Update File: old/name.txt\n*** Move to: renamed/dir/name.txt\n@@\n-old content\n+new content\n*** End Patch" - await execute({ patchText }, ctx) + yield* execute({ patchText }, ctx) expect(calls.length).toBe(1) const permissionCall = calls[0] @@ -169,447 +181,353 @@ describe("tool.apply_patch freeform", () => { const moveFile = permissionCall.metadata.files[0] expect(moveFile.type).toBe("move") expect(moveFile.relativePath).toBe("renamed/dir/name.txt") - expect(moveFile.movePath).toBe(path.join(fixture.path, "renamed/dir/name.txt")) + expect(moveFile.movePath).toBe(path.join(test.directory, "renamed/dir/name.txt")) expect(moveFile.patch).toContain("-old content") expect(moveFile.patch).toContain("+new content") - }, - }) - }) - - test("applies multiple hunks to one file", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "multi.txt") - await fs.writeFile(target, "line1\nline2\nline3\nline4\n", "utf-8") - - const patchText = - "*** Begin Patch\n*** Update File: multi.txt\n@@\n-line2\n+changed2\n@@\n-line4\n+changed4\n*** End Patch" - - await execute({ patchText }, ctx) - - expect(await fs.readFile(target, "utf-8")).toBe("line1\nchanged2\nline3\nchanged4\n") - }, - }) - }) - - test("does not invent a first-line diff for BOM files", async () => { - await using fixture = await tmpdir() - const { ctx, calls } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const bom = String.fromCharCode(0xfeff) - const target = path.join(fixture.path, "example.cs") - await fs.writeFile(target, `${bom}using System;\n\nclass Test {}\n`, "utf-8") - - const patchText = - "*** Begin Patch\n*** Update File: example.cs\n@@\n class Test {}\n+class Next {}\n*** End Patch" - - await execute({ patchText }, ctx) - - expect(calls.length).toBe(1) - const shown = calls[0].metadata.files[0]?.patch ?? "" - expect(shown).not.toContain(bom) - expect(shown).not.toContain("-using System;") - expect(shown).not.toContain("+using System;") - - const content = await fs.readFile(target, "utf-8") - expect(content.charCodeAt(0)).toBe(0xfeff) - expect(content.slice(1)).toBe("using System;\n\nclass Test {}\nclass Next {}\n") - }, - }) - }) - - test("inserts lines with insert-only hunk", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "insert_only.txt") - await fs.writeFile(target, "alpha\nomega\n", "utf-8") - - const patchText = "*** Begin Patch\n*** Update File: insert_only.txt\n@@\n alpha\n+beta\n omega\n*** End Patch" - - await execute({ patchText }, ctx) - - expect(await fs.readFile(target, "utf-8")).toBe("alpha\nbeta\nomega\n") - }, - }) - }) - - test("appends trailing newline on update", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "no_newline.txt") - await fs.writeFile(target, "no newline at end", "utf-8") - - const patchText = - "*** Begin Patch\n*** Update File: no_newline.txt\n@@\n-no newline at end\n+first line\n+second line\n*** End Patch" - - await execute({ patchText }, ctx) - - const contents = await fs.readFile(target, "utf-8") - expect(contents.endsWith("\n")).toBe(true) - expect(contents).toBe("first line\nsecond line\n") - }, - }) - }) - - test("moves file to a new directory", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const original = path.join(fixture.path, "old", "name.txt") - await fs.mkdir(path.dirname(original), { recursive: true }) - await fs.writeFile(original, "old content\n", "utf-8") - - const patchText = - "*** Begin Patch\n*** Update File: old/name.txt\n*** Move to: renamed/dir/name.txt\n@@\n-old content\n+new content\n*** End Patch" - - await execute({ patchText }, ctx) - - const moved = path.join(fixture.path, "renamed", "dir", "name.txt") - await expect(fs.readFile(original, "utf-8")).rejects.toThrow() - expect(await fs.readFile(moved, "utf-8")).toBe("new content\n") - }, - }) - }) - - test("moves file overwriting existing destination", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const original = path.join(fixture.path, "old", "name.txt") - const destination = path.join(fixture.path, "renamed", "dir", "name.txt") - await fs.mkdir(path.dirname(original), { recursive: true }) - await fs.mkdir(path.dirname(destination), { recursive: true }) - await fs.writeFile(original, "from\n", "utf-8") - await fs.writeFile(destination, "existing\n", "utf-8") - - const patchText = - "*** Begin Patch\n*** Update File: old/name.txt\n*** Move to: renamed/dir/name.txt\n@@\n-from\n+new\n*** End Patch" - - await execute({ patchText }, ctx) - - await expect(fs.readFile(original, "utf-8")).rejects.toThrow() - expect(await fs.readFile(destination, "utf-8")).toBe("new\n") - }, - }) - }) - - test("adds file overwriting existing file", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "duplicate.txt") - await fs.writeFile(target, "old content\n", "utf-8") - - const patchText = "*** Begin Patch\n*** Add File: duplicate.txt\n+new content\n*** End Patch" - - await execute({ patchText }, ctx) - expect(await fs.readFile(target, "utf-8")).toBe("new content\n") - }, - }) - }) - - test("rejects update when target file is missing", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const patchText = "*** Begin Patch\n*** Update File: missing.txt\n@@\n-nope\n+better\n*** End Patch" - - await expect(execute({ patchText }, ctx)).rejects.toThrow( - "apply_patch verification failed: Failed to read file to update", - ) - }, - }) - }) - - test("rejects delete when file is missing", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const patchText = "*** Begin Patch\n*** Delete File: missing.txt\n*** End Patch" - - await expect(execute({ patchText }, ctx)).rejects.toThrow() - }, - }) - }) - - test("rejects delete when target is a directory", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const dirPath = path.join(fixture.path, "dir") - await fs.mkdir(dirPath) - - const patchText = "*** Begin Patch\n*** Delete File: dir\n*** End Patch" - - await expect(execute({ patchText }, ctx)).rejects.toThrow() - }, - }) - }) - - test("rejects invalid hunk header", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const patchText = "*** Begin Patch\n*** Frobnicate File: foo\n*** End Patch" - - await expect(execute({ patchText }, ctx)).rejects.toThrow("apply_patch verification failed") - }, - }) - }) - - test("rejects update with missing context", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "modify.txt") - await fs.writeFile(target, "line1\nline2\n", "utf-8") - - const patchText = "*** Begin Patch\n*** Update File: modify.txt\n@@\n-missing\n+changed\n*** End Patch" - - await expect(execute({ patchText }, ctx)).rejects.toThrow("apply_patch verification failed") - expect(await fs.readFile(target, "utf-8")).toBe("line1\nline2\n") - }, - }) - }) - - test("verification failure leaves no side effects", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const patchText = - "*** Begin Patch\n*** Add File: created.txt\n+hello\n*** Update File: missing.txt\n@@\n-old\n+new\n*** End Patch" - - await expect(execute({ patchText }, ctx)).rejects.toThrow() - - const createdPath = path.join(fixture.path, "created.txt") - await expect(fs.readFile(createdPath, "utf-8")).rejects.toThrow() - }, - }) - }) - - test("supports end of file anchor", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "tail.txt") - await fs.writeFile(target, "alpha\nlast\n", "utf-8") - - const patchText = "*** Begin Patch\n*** Update File: tail.txt\n@@\n-last\n+end\n*** End of File\n*** End Patch" - - await execute({ patchText }, ctx) - expect(await fs.readFile(target, "utf-8")).toBe("alpha\nend\n") - }, - }) - }) - - test("rejects missing second chunk context", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "two_chunks.txt") - await fs.writeFile(target, "a\nb\nc\nd\n", "utf-8") - - const patchText = "*** Begin Patch\n*** Update File: two_chunks.txt\n@@\n-b\n+B\n\n-d\n+D\n*** End Patch" - - await expect(execute({ patchText }, ctx)).rejects.toThrow() - expect(await fs.readFile(target, "utf-8")).toBe("a\nb\nc\nd\n") - }, - }) - }) - - test("disambiguates change context with @@ header", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "multi_ctx.txt") - await fs.writeFile(target, "fn a\nx=10\ny=2\nfn b\nx=10\ny=20\n", "utf-8") - - const patchText = "*** Begin Patch\n*** Update File: multi_ctx.txt\n@@ fn b\n-x=10\n+x=11\n*** End Patch" - - await execute({ patchText }, ctx) - expect(await fs.readFile(target, "utf-8")).toBe("fn a\nx=10\ny=2\nfn b\nx=11\ny=20\n") - }, - }) - }) - - test("EOF anchor matches from end of file first", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "eof_anchor.txt") - // File has duplicate "marker" lines - one in middle, one at end - await fs.writeFile(target, "start\nmarker\nmiddle\nmarker\nend\n", "utf-8") - - // With EOF anchor, should match the LAST "marker" line, not the first - const patchText = - "*** Begin Patch\n*** Update File: eof_anchor.txt\n@@\n-marker\n-end\n+marker-changed\n+end\n*** End of File\n*** End Patch" - - await execute({ patchText }, ctx) - // First marker unchanged, second marker changed - expect(await fs.readFile(target, "utf-8")).toBe("start\nmarker\nmiddle\nmarker-changed\nend\n") - }, - }) - }) - - test("parses heredoc-wrapped patch", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const patchText = `cat <<'EOF' + }), + { git: true }, + ) + + it.instance("applies multiple hunks to one file", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "multi.txt") + yield* writeText(target, "line1\nline2\nline3\nline4\n") + + const patchText = + "*** Begin Patch\n*** Update File: multi.txt\n@@\n-line2\n+changed2\n@@\n-line4\n+changed4\n*** End Patch" + + yield* execute({ patchText }, ctx) + + expect(yield* readText(target)).toBe("line1\nchanged2\nline3\nchanged4\n") + }), + ) + + it.instance("does not invent a first-line diff for BOM files", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx, calls } = makeCtx() + const bom = String.fromCharCode(0xfeff) + const target = path.join(test.directory, "example.cs") + yield* writeText(target, `${bom}using System;\n\nclass Test {}\n`) + + const patchText = + "*** Begin Patch\n*** Update File: example.cs\n@@\n class Test {}\n+class Next {}\n*** End Patch" + + yield* execute({ patchText }, ctx) + + expect(calls.length).toBe(1) + const shown = calls[0].metadata.files[0]?.patch ?? "" + expect(shown).not.toContain(bom) + expect(shown).not.toContain("-using System;") + expect(shown).not.toContain("+using System;") + + const content = yield* readText(target) + expect(content.charCodeAt(0)).toBe(0xfeff) + expect(content.slice(1)).toBe("using System;\n\nclass Test {}\nclass Next {}\n") + }), + ) + + it.instance("inserts lines with insert-only hunk", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "insert_only.txt") + yield* writeText(target, "alpha\nomega\n") + + const patchText = "*** Begin Patch\n*** Update File: insert_only.txt\n@@\n alpha\n+beta\n omega\n*** End Patch" + + yield* execute({ patchText }, ctx) + + expect(yield* readText(target)).toBe("alpha\nbeta\nomega\n") + }), + ) + + it.instance("appends trailing newline on update", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "no_newline.txt") + yield* writeText(target, "no newline at end") + + const patchText = + "*** Begin Patch\n*** Update File: no_newline.txt\n@@\n-no newline at end\n+first line\n+second line\n*** End Patch" + + yield* execute({ patchText }, ctx) + + const contents = yield* readText(target) + expect(contents.endsWith("\n")).toBe(true) + expect(contents).toBe("first line\nsecond line\n") + }), + ) + + it.instance("moves file to a new directory", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const original = path.join(test.directory, "old", "name.txt") + yield* makeDir(path.dirname(original)) + yield* writeText(original, "old content\n") + + const patchText = + "*** Begin Patch\n*** Update File: old/name.txt\n*** Move to: renamed/dir/name.txt\n@@\n-old content\n+new content\n*** End Patch" + + yield* execute({ patchText }, ctx) + + const moved = path.join(test.directory, "renamed", "dir", "name.txt") + yield* expectReadFailure(original) + expect(yield* readText(moved)).toBe("new content\n") + }), + ) + + it.instance("moves file overwriting existing destination", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const original = path.join(test.directory, "old", "name.txt") + const destination = path.join(test.directory, "renamed", "dir", "name.txt") + yield* makeDir(path.dirname(original)) + yield* makeDir(path.dirname(destination)) + yield* writeText(original, "from\n") + yield* writeText(destination, "existing\n") + + const patchText = + "*** Begin Patch\n*** Update File: old/name.txt\n*** Move to: renamed/dir/name.txt\n@@\n-from\n+new\n*** End Patch" + + yield* execute({ patchText }, ctx) + + yield* expectReadFailure(original) + expect(yield* readText(destination)).toBe("new\n") + }), + ) + + it.instance("adds file overwriting existing file", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "duplicate.txt") + yield* writeText(target, "old content\n") + + const patchText = "*** Begin Patch\n*** Add File: duplicate.txt\n+new content\n*** End Patch" + + yield* execute({ patchText }, ctx) + expect(yield* readText(target)).toBe("new content\n") + }), + ) + + it.instance("rejects update when target file is missing", () => + Effect.gen(function* () { + const { ctx } = makeCtx() + const patchText = "*** Begin Patch\n*** Update File: missing.txt\n@@\n-nope\n+better\n*** End Patch" + + yield* expectFailure( + execute({ patchText }, ctx), + "apply_patch verification failed: Failed to read file to update", + ) + }), + ) + + it.instance("rejects delete when file is missing", () => + Effect.gen(function* () { + const { ctx } = makeCtx() + const patchText = "*** Begin Patch\n*** Delete File: missing.txt\n*** End Patch" + + yield* expectFailure(execute({ patchText }, ctx)) + }), + ) + + it.instance("rejects delete when target is a directory", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const dirPath = path.join(test.directory, "dir") + yield* makeDir(dirPath) + + const patchText = "*** Begin Patch\n*** Delete File: dir\n*** End Patch" + + yield* expectFailure(execute({ patchText }, ctx)) + }), + ) + + it.instance("rejects invalid hunk header", () => + Effect.gen(function* () { + const { ctx } = makeCtx() + const patchText = "*** Begin Patch\n*** Frobnicate File: foo\n*** End Patch" + + yield* expectFailure(execute({ patchText }, ctx), "apply_patch verification failed") + }), + ) + + it.instance("rejects update with missing context", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "modify.txt") + yield* writeText(target, "line1\nline2\n") + + const patchText = "*** Begin Patch\n*** Update File: modify.txt\n@@\n-missing\n+changed\n*** End Patch" + + yield* expectFailure(execute({ patchText }, ctx), "apply_patch verification failed") + expect(yield* readText(target)).toBe("line1\nline2\n") + }), + ) + + it.instance("verification failure leaves no side effects", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const patchText = + "*** Begin Patch\n*** Add File: created.txt\n+hello\n*** Update File: missing.txt\n@@\n-old\n+new\n*** End Patch" + + yield* expectFailure(execute({ patchText }, ctx)) + yield* expectReadFailure(path.join(test.directory, "created.txt")) + }), + ) + + it.instance("supports end of file anchor", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "tail.txt") + yield* writeText(target, "alpha\nlast\n") + + const patchText = "*** Begin Patch\n*** Update File: tail.txt\n@@\n-last\n+end\n*** End of File\n*** End Patch" + + yield* execute({ patchText }, ctx) + expect(yield* readText(target)).toBe("alpha\nend\n") + }), + ) + + it.instance("rejects missing second chunk context", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "two_chunks.txt") + yield* writeText(target, "a\nb\nc\nd\n") + + const patchText = "*** Begin Patch\n*** Update File: two_chunks.txt\n@@\n-b\n+B\n\n-d\n+D\n*** End Patch" + + yield* expectFailure(execute({ patchText }, ctx)) + expect(yield* readText(target)).toBe("a\nb\nc\nd\n") + }), + ) + + it.instance("disambiguates change context with @@ header", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "multi_ctx.txt") + yield* writeText(target, "fn a\nx=10\ny=2\nfn b\nx=10\ny=20\n") + + const patchText = "*** Begin Patch\n*** Update File: multi_ctx.txt\n@@ fn b\n-x=10\n+x=11\n*** End Patch" + + yield* execute({ patchText }, ctx) + expect(yield* readText(target)).toBe("fn a\nx=10\ny=2\nfn b\nx=11\ny=20\n") + }), + ) + + it.instance("EOF anchor matches from end of file first", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "eof_anchor.txt") + // File has duplicate "marker" lines - one in middle, one at end + yield* writeText(target, "start\nmarker\nmiddle\nmarker\nend\n") + + // With EOF anchor, should match the LAST "marker" line, not the first + const patchText = + "*** Begin Patch\n*** Update File: eof_anchor.txt\n@@\n-marker\n-end\n+marker-changed\n+end\n*** End of File\n*** End Patch" + + yield* execute({ patchText }, ctx) + // First marker unchanged, second marker changed + expect(yield* readText(target)).toBe("start\nmarker\nmiddle\nmarker-changed\nend\n") + }), + ) + + it.instance("parses heredoc-wrapped patch", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const patchText = `cat <<'EOF' *** Begin Patch *** Add File: heredoc_test.txt +heredoc content *** End Patch EOF` - await execute({ patchText }, ctx) - const content = await fs.readFile(path.join(fixture.path, "heredoc_test.txt"), "utf-8") - expect(content).toBe("heredoc content\n") - }, - }) - }) + yield* execute({ patchText }, ctx) + expect(yield* readText(path.join(test.directory, "heredoc_test.txt"))).toBe("heredoc content\n") + }), + ) - test("parses heredoc-wrapped patch without cat", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const patchText = `< + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const patchText = `< { - await using fixture = await tmpdir() - const { ctx } = makeCtx() + it.instance("matches with trailing whitespace differences", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "trailing_ws.txt") + // File has trailing spaces on some lines + yield* writeText(target, "line1 \nline2\nline3 \n") - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "trailing_ws.txt") - // File has trailing spaces on some lines - await fs.writeFile(target, "line1 \nline2\nline3 \n", "utf-8") + // Patch doesn't have trailing spaces - should still match via rstrip pass + const patchText = "*** Begin Patch\n*** Update File: trailing_ws.txt\n@@\n-line2\n+changed\n*** End Patch" - // Patch doesn't have trailing spaces - should still match via rstrip pass - const patchText = "*** Begin Patch\n*** Update File: trailing_ws.txt\n@@\n-line2\n+changed\n*** End Patch" + yield* execute({ patchText }, ctx) + expect(yield* readText(target)).toBe("line1 \nchanged\nline3 \n") + }), + ) - await execute({ patchText }, ctx) - expect(await fs.readFile(target, "utf-8")).toBe("line1 \nchanged\nline3 \n") - }, - }) - }) + it.instance("matches with leading whitespace differences", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "leading_ws.txt") + // File has leading spaces + yield* writeText(target, " line1\nline2\n line3\n") - test("matches with leading whitespace differences", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() + // Patch without leading spaces - should match via trim pass + const patchText = "*** Begin Patch\n*** Update File: leading_ws.txt\n@@\n-line2\n+changed\n*** End Patch" - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "leading_ws.txt") - // File has leading spaces - await fs.writeFile(target, " line1\nline2\n line3\n", "utf-8") + yield* execute({ patchText }, ctx) + expect(yield* readText(target)).toBe(" line1\nchanged\n line3\n") + }), + ) - // Patch without leading spaces - should match via trim pass - const patchText = "*** Begin Patch\n*** Update File: leading_ws.txt\n@@\n-line2\n+changed\n*** End Patch" + it.instance("matches with Unicode punctuation differences", () => + Effect.gen(function* () { + const test = yield* TestInstance + const { ctx } = makeCtx() + const target = path.join(test.directory, "unicode.txt") + // File has fancy Unicode quotes (U+201C, U+201D) and em-dash (U+2014) + const leftQuote = "\u201C" + const rightQuote = "\u201D" + const emDash = "\u2014" + yield* writeText(target, `He said ${leftQuote}hello${rightQuote}\nsome${emDash}dash\nend\n`) - await execute({ patchText }, ctx) - expect(await fs.readFile(target, "utf-8")).toBe(" line1\nchanged\n line3\n") - }, - }) - }) + // Patch uses ASCII equivalents - should match via normalized pass + // The replacement uses ASCII quotes from the patch (not preserving Unicode) + const patchText = + '*** Begin Patch\n*** Update File: unicode.txt\n@@\n-He said "hello"\n+He said "hi"\n*** End Patch' - test("matches with Unicode punctuation differences", async () => { - await using fixture = await tmpdir() - const { ctx } = makeCtx() - - await WithInstance.provide({ - directory: fixture.path, - fn: async () => { - const target = path.join(fixture.path, "unicode.txt") - // File has fancy Unicode quotes (U+201C, U+201D) and em-dash (U+2014) - const leftQuote = "\u201C" - const rightQuote = "\u201D" - const emDash = "\u2014" - await fs.writeFile(target, `He said ${leftQuote}hello${rightQuote}\nsome${emDash}dash\nend\n`, "utf-8") - - // Patch uses ASCII equivalents - should match via normalized pass - // The replacement uses ASCII quotes from the patch (not preserving Unicode) - const patchText = - '*** Begin Patch\n*** Update File: unicode.txt\n@@\n-He said "hello"\n+He said "hi"\n*** End Patch' - - await execute({ patchText }, ctx) - // Result has ASCII quotes because that's what the patch specifies - expect(await fs.readFile(target, "utf-8")).toBe(`He said "hi"\nsome${emDash}dash\nend\n`) - }, - }) - }) + yield* execute({ patchText }, ctx) + // Result has ASCII quotes because that's what the patch specifies + expect(yield* readText(target)).toBe(`He said "hi"\nsome${emDash}dash\nend\n`) + }), + ) }) diff --git a/packages/opencode/test/tool/edit.test.ts b/packages/opencode/test/tool/edit.test.ts index 572fcd9aa4..3f644ed53d 100644 --- a/packages/opencode/test/tool/edit.test.ts +++ b/packages/opencode/test/tool/edit.test.ts @@ -1,10 +1,9 @@ -import { afterAll, afterEach, describe, test, expect } from "bun:test" +import { afterEach, describe, expect } from "bun:test" import path from "path" import fs from "fs/promises" -import { Cause, Deferred, Effect, Exit, Layer, ManagedRuntime } from "effect" +import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect" import { EditTool } from "../../src/tool/edit" -import { WithInstance } from "../../src/project/with-instance" -import { disposeAllInstances, TestInstance, tmpdir } from "../fixture/fixture" +import { disposeAllInstances, TestInstance } from "../fixture/fixture" import { LSP } from "@/lsp/lsp" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { Format } from "../../src/format" @@ -42,20 +41,6 @@ const layer = Layer.mergeAll( const it = testEffect(layer) -const runtime = ManagedRuntime.make(layer) - -afterAll(async () => { - await runtime.dispose() -}) - -const resolve = () => - runtime.runPromise( - Effect.gen(function* () { - const info = yield* EditTool - return yield* info.init() - }), - ) - const init = Effect.fn("EditToolTest.init")(function* () { const info = yield* EditTool return yield* info.init() @@ -500,58 +485,49 @@ describe("tool.edit", () => { }) describe("concurrent editing", () => { - test("preserves concurrent edits to different sections of the same file", async () => { - await using tmp = await tmpdir() - const filepath = path.join(tmp.path, "file.txt") - await fs.writeFile(filepath, "top = 0\nmiddle = keep\nbottom = 0\n", "utf-8") + it.instance("preserves concurrent edits to different sections of the same file", () => + Effect.gen(function* () { + const test = yield* TestInstance + const filepath = path.join(test.directory, "file.txt") + yield* put(filepath, "top = 0\nmiddle = keep\nbottom = 0\n") - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const edit = await resolve() - let asks = 0 - const firstAsk = Promise.withResolvers() - const delayedCtx = { - ...ctx, - ask: () => - Effect.gen(function* () { - asks++ - if (asks !== 1) return - firstAsk.resolve() - yield* Effect.promise(() => Bun.sleep(50)) - }), - } + const firstAsk = yield* Deferred.make() + let asks = 0 + const delayedCtx = { + ...ctx, + ask: () => + Effect.gen(function* () { + asks++ + if (asks !== 1) return + yield* Deferred.succeed(firstAsk, undefined) + yield* Effect.sleep("50 millis") + }), + } - const promise1 = Effect.runPromise( - edit.execute( - { - filePath: filepath, - oldString: "top = 0", - newString: "top = 1", - }, - delayedCtx, - ), - ) + const first = yield* run( + { + filePath: filepath, + oldString: "top = 0", + newString: "top = 1", + }, + delayedCtx, + ).pipe(Effect.forkScoped) - await firstAsk.promise + yield* Deferred.await(firstAsk) + yield* Effect.all([ + Fiber.join(first), + run( + { + filePath: filepath, + oldString: "bottom = 0", + newString: "bottom = 2", + }, + delayedCtx, + ), + ]) - const promise2 = Effect.runPromise( - edit.execute( - { - filePath: filepath, - oldString: "bottom = 0", - newString: "bottom = 2", - }, - delayedCtx, - ), - ) - - const results = await Promise.allSettled([promise1, promise2]) - expect(results[0]?.status).toBe("fulfilled") - expect(results[1]?.status).toBe("fulfilled") - expect(await fs.readFile(filepath, "utf-8")).toBe("top = 1\nmiddle = keep\nbottom = 2\n") - }, - }) - }) + expect(yield* load(filepath)).toBe("top = 1\nmiddle = keep\nbottom = 2\n") + }), + ) }) }) diff --git a/packages/opencode/test/tool/external-directory.test.ts b/packages/opencode/test/tool/external-directory.test.ts index 0560ea0300..04ef5c5d01 100644 --- a/packages/opencode/test/tool/external-directory.test.ts +++ b/packages/opencode/test/tool/external-directory.test.ts @@ -1,14 +1,16 @@ -import { describe, expect, test } from "bun:test" +import { describe, expect } from "bun:test" import path from "path" import { Effect } from "effect" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import type { Tool } from "@/tool/tool" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" -import { assertExternalDirectory } from "../../src/tool/external-directory" +import { assertExternalDirectoryEffect } from "../../src/tool/external-directory" import { Filesystem } from "@/util/filesystem" -import { tmpdir } from "../fixture/fixture" +import { provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture" import type { Permission } from "../../src/permission" import { SessionID, MessageID } from "../../src/session/schema" +import { testEffect } from "../lib/effect" + +const it = testEffect(CrossSpawnSpawner.defaultLayer) const baseCtx: Omit = { sessionID: SessionID.make("ses_test"), @@ -36,135 +38,120 @@ function makeCtx() { } describe("tool.assertExternalDirectory", () => { - test("no-ops for empty target", async () => { - const { requests, ctx } = makeCtx() + it.live("no-ops for empty target", () => + Effect.gen(function* () { + const { requests, ctx } = makeCtx() - await WithInstance.provide({ - directory: "/tmp", - fn: async () => { - await assertExternalDirectory(ctx) - }, - }) + yield* assertExternalDirectoryEffect(ctx) - expect(requests.length).toBe(0) - }) + expect(requests.length).toBe(0) + }), + ) - test("no-ops for paths inside Instance.directory", async () => { - const { requests, ctx } = makeCtx() + it.live("no-ops for paths inside Instance.directory", () => + provideInstance("/tmp/project")( + Effect.gen(function* () { + const { requests, ctx } = makeCtx() - await WithInstance.provide({ - directory: "/tmp/project", - fn: async () => { - await assertExternalDirectory(ctx, path.join("/tmp/project", "file.txt")) - }, - }) + yield* assertExternalDirectoryEffect(ctx, path.join("/tmp/project", "file.txt")) - expect(requests.length).toBe(0) - }) + expect(requests.length).toBe(0) + }), + ), + ) - test("asks with a single canonical glob", async () => { - const { requests, ctx } = makeCtx() + it.live("asks with a single canonical glob", () => + Effect.gen(function* () { + const { requests, ctx } = makeCtx() - const directory = "/tmp/project" - const target = "/tmp/outside/file.txt" - const expected = glob(path.join(path.dirname(target), "*")) + const directory = "/tmp/project" + const target = "/tmp/outside/file.txt" + const expected = glob(path.join(path.dirname(target), "*")) - await WithInstance.provide({ - directory, - fn: async () => { - await assertExternalDirectory(ctx, target) - }, - }) + yield* provideInstance(directory)(assertExternalDirectoryEffect(ctx, target)) - const req = requests.find((r) => r.permission === "external_directory") - expect(req).toBeDefined() - expect(req!.patterns).toEqual([expected]) - expect(req!.always).toEqual([expected]) - }) + const req = requests.find((r) => r.permission === "external_directory") + expect(req).toBeDefined() + expect(req!.patterns).toEqual([expected]) + expect(req!.always).toEqual([expected]) + }), + ) - test("uses target directory when kind=directory", async () => { - const { requests, ctx } = makeCtx() + it.live("uses target directory when kind=directory", () => + Effect.gen(function* () { + const { requests, ctx } = makeCtx() - const directory = "/tmp/project" - const target = "/tmp/outside" - const expected = glob(path.join(target, "*")) + const directory = "/tmp/project" + const target = "/tmp/outside" + const expected = glob(path.join(target, "*")) - await WithInstance.provide({ - directory, - fn: async () => { - await assertExternalDirectory(ctx, target, { kind: "directory" }) - }, - }) + yield* provideInstance(directory)(assertExternalDirectoryEffect(ctx, target, { kind: "directory" })) - const req = requests.find((r) => r.permission === "external_directory") - expect(req).toBeDefined() - expect(req!.patterns).toEqual([expected]) - expect(req!.always).toEqual([expected]) - }) + const req = requests.find((r) => r.permission === "external_directory") + expect(req).toBeDefined() + expect(req!.patterns).toEqual([expected]) + expect(req!.always).toEqual([expected]) + }), + ) - test("skips prompting when bypass=true", async () => { - const { requests, ctx } = makeCtx() + it.live("skips prompting when bypass=true", () => + provideInstance("/tmp/project")( + Effect.gen(function* () { + const { requests, ctx } = makeCtx() - await WithInstance.provide({ - directory: "/tmp/project", - fn: async () => { - await assertExternalDirectory(ctx, "/tmp/outside/file.txt", { bypass: true }) - }, - }) + yield* assertExternalDirectoryEffect(ctx, "/tmp/outside/file.txt", { bypass: true }) - expect(requests.length).toBe(0) - }) + expect(requests.length).toBe(0) + }), + ), + ) if (process.platform === "win32") { - test("normalizes Windows path variants to one glob", async () => { - const { requests, ctx } = makeCtx() + it.instance( + "normalizes Windows path variants to one glob", + () => + Effect.gen(function* () { + const { requests, ctx } = makeCtx() - await using outerTmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "outside.txt"), "x") - }, - }) - await using tmp = await tmpdir({ git: true }) + const outerTmp = yield* tmpdirScoped() + yield* Effect.promise(() => Bun.write(path.join(outerTmp, "outside.txt"), "x")) - const target = path.join(outerTmp.path, "outside.txt") - const alt = target - .replace(/^[A-Za-z]:/, "") - .replaceAll("\\", "/") - .toLowerCase() + const target = path.join(outerTmp, "outside.txt") + const alt = target + .replace(/^[A-Za-z]:/, "") + .replaceAll("\\", "/") + .toLowerCase() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await assertExternalDirectory(ctx, alt) - }, - }) + yield* assertExternalDirectoryEffect(ctx, alt) - const req = requests.find((r) => r.permission === "external_directory") - const expected = glob(path.join(outerTmp.path, "*")) - expect(req).toBeDefined() - expect(req!.patterns).toEqual([expected]) - expect(req!.always).toEqual([expected]) - }) + const req = requests.find((r) => r.permission === "external_directory") + const expected = glob(path.join(outerTmp, "*")) + expect(req).toBeDefined() + expect(req!.patterns).toEqual([expected]) + expect(req!.always).toEqual([expected]) + }), + { git: true }, + ) - test("uses drive root glob for root files", async () => { - const { requests, ctx } = makeCtx() + it.instance( + "uses drive root glob for root files", + () => + Effect.gen(function* () { + const { requests, ctx } = makeCtx() - await using tmp = await tmpdir({ git: true }) - const root = path.parse(tmp.path).root - const target = path.join(root, "boot.ini") + const tmp = yield* TestInstance + const root = path.parse(tmp.directory).root + const target = path.join(root, "boot.ini") - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - await assertExternalDirectory(ctx, target) - }, - }) + yield* assertExternalDirectoryEffect(ctx, target) - const req = requests.find((r) => r.permission === "external_directory") - const expected = path.join(root, "*") - expect(req).toBeDefined() - expect(req!.patterns).toEqual([expected]) - expect(req!.always).toEqual([expected]) - }) + const req = requests.find((r) => r.permission === "external_directory") + const expected = path.join(root, "*") + expect(req).toBeDefined() + expect(req!.patterns).toEqual([expected]) + expect(req!.always).toEqual([expected]) + }), + { git: true }, + ) } }) diff --git a/packages/opencode/test/tool/fixtures/models-api.json b/packages/opencode/test/tool/fixtures/models-api.json index 5a3eb7e801..6302a951dd 100644 --- a/packages/opencode/test/tool/fixtures/models-api.json +++ b/packages/opencode/test/tool/fixtures/models-api.json @@ -1,366 +1,328 @@ { - "ollama-cloud": { - "id": "ollama-cloud", - "env": ["OLLAMA_API_KEY"], + "302ai": { + "id": "302ai", + "env": ["302AI_API_KEY"], "npm": "@ai-sdk/openai-compatible", - "api": "https://ollama.com/v1", - "name": "Ollama Cloud", - "doc": "https://docs.ollama.com/cloud", + "api": "https://api.302.ai/v1", + "name": "302.AI", + "doc": "https://doc.302.ai", "models": { - "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 } - }, - "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 } - }, - "qwen3-coder-next": { - "id": "qwen3-coder-next", - "name": "qwen3-coder-next", + "qwen3-235b-a22b": { + "id": "qwen3-235b-a22b", + "name": "Qwen3-235B-A22B", "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 } + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-04-29", + "last_updated": "2025-04-29", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.29, + "output": 2.86 + } }, - "qwen3-vl:235b-instruct": { - "id": "qwen3-vl:235b-instruct", - "name": "qwen3-vl:235b-instruct", - "family": "qwen", + "grok-4.1": { + "id": "grok-4.1", + "name": "grok-4.1", "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 } + "temperature": true, + "knowledge": "2025-06", + "release_date": "2025-11-18", + "last_updated": "2025-11-18", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 10 + } }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "minimax-m2": { - "id": "minimax-m2", - "name": "minimax-m2", - "family": "minimax", + "MiniMax-M2": { + "id": "MiniMax-M2", + "name": "MiniMax-M2", "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 } + "temperature": true, + "release_date": "2025-10-26", + "last_updated": "2025-10-26", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 0.33, + "output": 1.32 + } }, - "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", + "grok-4-1-fast-reasoning": { + "id": "grok-4-1-fast-reasoning", + "name": "grok-4-1-fast-reasoning", "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 } + "temperature": true, + "knowledge": "2025-06", + "release_date": "2025-11-20", + "last_updated": "2025-11-20", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "gemini-3-flash-preview": { - "id": "gemini-3-flash-preview", - "name": "gemini-3-flash-preview", + "gemini-2.5-flash-nothink": { + "id": "gemini-2.5-flash-nothink", + "name": "gemini-2.5-flash-nothink", "family": "gemini-flash", - "attachment": false, - "reasoning": true, + "attachment": true, + "reasoning": false, "tool_call": true, + "temperature": true, "knowledge": "2025-01", - "release_date": "2025-12-17", - "last_updated": "2026-01-19", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "limit": { "context": 1048576, "output": 65536 } + "release_date": "2025-06-24", + "last_updated": "2025-06-24", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } }, - "minimax-m2.7": { - "id": "minimax-m2.7", - "name": "minimax-m2.7", - "family": "minimax", - "attachment": false, + "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, - "release_date": "2026-03-18", - "last_updated": "2026-03-18", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "limit": { "context": 204800, "output": 131072 } + "temperature": true, + "release_date": "2026-03-16", + "last_updated": "2026-03-16", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 2, + "output": 6 + } }, - "gpt-oss:20b": { - "id": "gpt-oss:20b", - "name": "gpt-oss:20b", - "family": "gpt-oss", + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.632, + "output": 2.53 + } + }, + "claude-haiku-4-5": { + "id": "claude-haiku-4-5", + "name": "claude-haiku-4-5", + "family": "claude-haiku", + "attachment": true, "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 } + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5 + } }, - "ministral-3:8b": { - "id": "ministral-3:8b", - "name": "ministral-3:8b", - "family": "ministral", + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, - "release_date": "2024-12-01", - "last_updated": "2026-01-19", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "limit": { "context": 262144, "output": 128000 } + "temperature": true, + "knowledge": "2025-01", + "release_date": "2025-09-26", + "last_updated": "2025-09-26", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } }, - "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 } - }, - "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": 81920 } - }, - "nemotron-3-super": { - "id": "nemotron-3-super", - "name": "nemotron-3-super", - "family": "nemotron", + "qwen3-235b-a22b-instruct-2507": { + "id": "qwen3-235b-a22b-instruct-2507", + "name": "qwen3-235b-a22b-instruct-2507", "attachment": false, - "reasoning": true, + "reasoning": false, "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 } + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-07-30", + "last_updated": "2025-07-30", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 65536 + }, + "cost": { + "input": 0.29, + "output": 1.143 + } }, - "glm-5": { - "id": "glm-5", - "name": "glm-5", + "glm-5v-turbo": { + "id": "glm-5v-turbo", + "name": "GLM-5V-Turbo", "family": "glm", - "attachment": false, + "attachment": true, "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 } + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.72, + "output": 3.2 + } }, - "devstral-2:123b": { - "id": "devstral-2:123b", - "name": "devstral-2:123b", - "family": "devstral", - "attachment": false, + "mistral-large-2512": { + "id": "mistral-large-2512", + "name": "mistral-large-2512", + "attachment": true, "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 } + "temperature": true, + "knowledge": "2024-12", + "release_date": "2025-12-16", + "last_updated": "2025-12-16", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 262144 + }, + "cost": { + "input": 1.1, + "output": 3.3 + } }, "glm-4.7": { "id": "glm-4.7", @@ -369,401 +331,873 @@ "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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" }, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, "knowledge": "2025-04", "release_date": "2025-12-22", "last_updated": "2025-12-22", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 3.5, "output": 14 }, - "limit": { "context": 204800, "output": 131072 } + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.286, + "output": 1.142 + } }, - "MiniMax-M2.1": { - "id": "MiniMax-M2.1", - "name": "MiniMax-M2.1", - "family": "minimax", + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4 + } + }, + "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, + "limit": { + "context": 224000, + "output": 64000 + }, + "cost": { + "input": 0.114, + "output": 0.286 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 5, + "output": 15 + } + }, + "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": "2025-12-23", - "last_updated": "2025-12-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-02-12", + "last_updated": "2026-02-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 2.1, "output": 8.4 }, - "limit": { "context": 204800, "output": 131072 } - } - } - }, - "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 } + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.6 + } }, - "public/deepseek-v3": { - "id": "public/deepseek-v3", - "name": "DeepSeek V3", + "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-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 } - }, - "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"] }, + "release_date": "2024-11-29", + "last_updated": "2024-11-29", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.29, "output": 1.16 }, - "limit": { "context": 204800, "output": 131072 } - } - } - }, - "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": { - "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 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.29, + "output": 0.43 + } }, - "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/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 } - }, - "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-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.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 } - }, - "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-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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "Ring-1T": { - "id": "Ring-1T", - "name": "Ring-1T", - "family": "ring", + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.29, + "output": 0.43 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.0715, + "output": 0.429 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.12, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5 + } + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 12 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 258048, + "output": 65536 + }, + "cost": { + "input": 0.86, + "output": 3.43 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.022, + "output": 0.22 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5 + } + }, + "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": "2024-06", - "release_date": "2025-10", - "last_updated": "2025-10", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-06", + "release_date": "2025-11-20", + "last_updated": "2025-11-20", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 32768, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 120 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.86, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.343, + "output": 1.372 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 30 + } + }, + "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.57, "output": 2.29 }, - "limit": { "context": 128000, "output": 32000 } - } - } - }, - "openai": { - "id": "openai", - "env": ["OPENAI_API_KEY"], - "npm": "@ai-sdk/openai", - "name": "OpenAI", - "doc": "https://platform.openai.com/docs/models", - "models": { - "gpt-5.2-codex": { - "id": "gpt-5.2-codex", - "name": "GPT-5.2 Codex", + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.286, + "output": 1.142 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "gpt-5.2-chat-latest": { + "id": "gpt-5.2-chat-latest", + "name": "gpt-5.2-chat-latest", "family": "gpt-codex", "attachment": true, "reasoning": true, @@ -771,66 +1205,292 @@ "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"] }, + "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, "cache_read": 0.175 }, - "limit": { "context": 400000, "input": 272000, "output": 128000 } + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14 + } }, - "o1-pro": { - "id": "o1-pro", - "name": "o1-pro", - "family": "o-pro", + "doubao-seed-1-6-vision-250815": { + "id": "doubao-seed-1-6-vision-250815", + "name": "doubao-seed-1-6-vision-250815", "attachment": true, - "reasoning": true, + "reasoning": false, "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"] }, + "temperature": true, + "release_date": "2025-09-30", + "last_updated": "2025-09-30", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 150, "output": 600 }, - "limit": { "context": 200000, "output": 100000 } + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0.114, + "output": 1.143 + } }, - "text-embedding-3-large": { - "id": "text-embedding-3-large", - "name": "text-embedding-3-large", - "family": "text-embedding", - "attachment": false, + "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": false, - "knowledge": "2024-01", - "release_date": "2024-01-25", - "last_updated": "2024-01-25", - "modalities": { "input": ["text"], "output": ["text"] }, + "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.13, "output": 0 }, - "limit": { "context": 8191, "output": 3072 } + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 60 + } }, - "gpt-5.1-codex-mini": { - "id": "gpt-5.1-codex-mini", - "name": "GPT-5.1 Codex mini", - "family": "gpt-codex", + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 4.8 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.143, + "output": 2.29 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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"] }, + "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, "input": 272000, "output": 128000 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.265, + "output": 9.119 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.29, + "output": 0.43 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.1143, + "output": 0.286 + } }, "gpt-5.4-pro": { "id": "gpt-5.4-pro", - "name": "GPT-5.4 Pro", + "name": "gpt-5.4-pro", "family": "gpt-pro", "attachment": true, "reasoning": true, @@ -840,48 +1500,582 @@ "knowledge": "2025-08-31", "release_date": "2026-03-05", "last_updated": "2026-03-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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 } + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "cache_read": 0, + "cache_write": 0, + "tiers": [ + { + "input": 60, + "output": 270, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 60, + "output": 270 + } + } }, - "o3-mini": { - "id": "o3-mini", - "name": "o3-mini", - "family": "o-mini", + "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": false, - "knowledge": "2024-05", - "release_date": "2024-12-20", - "last_updated": "2025-01-29", - "modalities": { "input": ["text"], "output": ["text"] }, + "temperature": true, + "release_date": "2026-03-16", + "last_updated": "2026-03-16", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.1, "output": 4.4, "cache_read": 0.55 }, - "limit": { "context": 200000, "output": 100000 } + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.72, + "output": 3.2 + } }, - "gpt-5.4-mini": { - "id": "gpt-5.4-mini", - "name": "GPT-5.4 mini", - "family": "gpt-mini", + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.11, + "output": 1.08 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 64000, + "output": 16384 + }, + "cost": { + "input": 0.29, + "output": 0.86 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.286, + "output": 1.142 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.145, + "output": 0.43 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75 + } + }, + "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-17", - "last_updated": "2026-03-17", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "release_date": "2026-03-05", + "last_updated": "2026-03-05", + "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 } + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "cache_write": 0, + "tiers": [ + { + "input": 5, + "output": 22.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 5, + "output": 22.5 + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 0.132, + "output": 1.254 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.86, + "output": 3.43 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0.17, + "output": 1.14 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.29, + "output": 0.43 + } }, "gpt-5-pro": { "id": "gpt-5-pro", - "name": "GPT-5 Pro", + "name": "gpt-5-pro", "family": "gpt-pro", "attachment": true, "reasoning": true, @@ -889,67 +2083,26 @@ "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"] }, + "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-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": { - "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-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 } + "limit": { + "context": 400000, + "input": 272000, + "output": 272000 + }, + "cost": { + "input": 15, + "output": 120 + } }, "gpt-4o": { "id": "gpt-4o", - "name": "GPT-4o", + "name": "gpt-4o", "family": "gpt", "attachment": true, "reasoning": false, @@ -958,100 +2111,197 @@ "temperature": true, "knowledge": "2023-09", "release_date": "2024-05-13", - "last_updated": "2024-08-06", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "last_updated": "2024-05-13", + "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 } + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10 + } }, - "gpt-5.3-codex": { - "id": "gpt-5.3-codex", - "name": "GPT-5.3 Codex", - "family": "gpt-codex", + "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": 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-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.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 } - }, - "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"], "output": ["text"] }, + "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": 0.15, "output": 0.6, "cache_read": 0.08 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } }, - "gpt-5.1-codex-max": { - "id": "gpt-5.1-codex-max", - "name": "GPT-5.1 Codex Max", - "family": "gpt-codex", + "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-11-13", - "last_updated": "2025-11-13", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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, "cache_read": 0.125 }, - "limit": { "context": 400000, "input": 272000, "output": 128000 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.086, + "output": 0.343 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.572, + "output": 1.714 + } }, "gpt-4.1": { "id": "gpt-4.1", - "name": "GPT-4.1", + "name": "gpt-4.1", "family": "gpt", "attachment": true, "reasoning": false, @@ -1061,44 +2311,15500 @@ "knowledge": "2024-04", "release_date": "2025-04-14", "last_updated": "2025-04-14", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 2, "output": 8, "cache_read": 0.5 }, - "limit": { "context": 1047576, "output": 32768 } + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8 + } }, - "gpt-5.1-chat-latest": { - "id": "gpt-5.1-chat-latest", - "name": "GPT-5.1 Chat", + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.575, + "output": 2.3 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 8192 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16000 + }, + "cost": { + "input": 0.121, + "output": 1.21 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.33, + "output": 0.33 + } + } + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.7, + "output": 2.8, + "reasoning": 8.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1, + "output": 5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 34096, + "output": 4096 + }, + "cost": { + "input": 0.72, + "output": 0.72 + } + }, + "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, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0.27, + "output": 1.07, + "input_audio": 4.44, + "output_audio": 8.89 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.18, + "output": 0.7, + "reasoning": 2.1 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.21, + "output": 0.63 + } + }, + "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, + "limit": { + "context": 53248, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 10, + "input_audio": 10, + "output_audio": 38 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.7, + "output": 2.8, + "reasoning": 8.4 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 1.6, + "output": 6.4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.2, + "reasoning": 4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.248, + "output": 1.485 + } + }, + "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, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0.07, + "output": 0.27, + "input_audio": 4.44, + "output_audio": 8.89 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.35, + "output": 1.05 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 0.625, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.2, + "cache_write": 2.5, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "cache_write": 2.5 + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 1.2, + "output": 6 + } + }, + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.43, + "output": 1.66, + "input_audio": 3.81, + "output_audio": 15.11 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 1.4, + "output": 5.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.7, + "output": 2.8, + "reasoning": 8.4 + } + }, + "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, + "limit": { + "context": 53248, + "output": 4096 + }, + "cost": { + "input": 0.035, + "output": 0.035 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 6 + } + }, + "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, + "limit": { + "context": 16384, + "output": 8192 + }, + "cost": { + "input": 2.46, + "output": 7.37 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.175, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.35, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.7, + "output": 2.8 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 8192, + "output": 512 + }, + "cost": { + "input": 0.5, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.52, + "output": 1.99, + "input_audio": 4.57, + "output_audio": 18.13 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 0.8, + "reasoning": 2.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 1.6, + "reasoning": 4.8 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 1.5, + "output": 7.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.45, + "output": 2.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 16384 + }, + "cost": { + "input": 0.05, + "output": 0.2, + "reasoning": 0.5 + } + }, + "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, + "limit": { + "context": 16384, + "output": 8192 + }, + "cost": { + "input": 0.16, + "output": 0.49 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 1.3, + "output": 7.8, + "cache_read": 0.13, + "cache_write": 1.625 + } + }, + "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, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "input_audio": 6.76 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 2.4, + "reasoning": 2.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 2.8, + "output": 8.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 1.2, + "output": 4.8 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.35, + "output": 1.4, + "reasoning": 4.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 2 + } + } + } + }, + "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, + "limit": { + "context": 32768, + "output": 4096 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 260000, + "output": 16384 + }, + "cost": { + "input": 0.75, + "output": 2.25 + } + }, + "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, + "limit": { + "context": 100000, + "output": 16384 + }, + "cost": { + "input": 0.9, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 32000, + "output": 8196 + }, + "cost": { + "input": 0.9, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 0, + "output": 8192 + }, + "cost": { + "input": 0.003, + "output": 0 + } + }, + "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, + "limit": { + "context": 32000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.35 + } + }, + "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, + "limit": { + "context": 40000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 8191, + "output": 3072 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.35 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 0.1003, + "output": 0.1003 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 4 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + }, + "cost": { + "input": 0.17, + "output": 1.53 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 8192 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + }, + "cost": { + "input": 5, + "output": 5 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + }, + "cost": { + "input": 2.5, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 2097152, + "input": 2097152, + "output": 8192 + }, + "cost": { + "input": 1.258, + "output": 4.998 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 4.998, + "output": 25.007 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + }, + "cost": { + "input": 9.996, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + }, + "cost": { + "input": 0.1989, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 4096 + }, + "cost": { + "input": 3.196, + "output": 3.196 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + }, + "cost": { + "input": 9.996, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 2.499, + "output": 9.996 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.612, + "output": 6.12 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + }, + "cost": { + "input": 0.204, + "output": 0.51 + } + }, + "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, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 1.1, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 0.1394, + "output": 0.1394 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 7.5, + "output": 7.5 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + }, + "cost": { + "input": 0.204, + "output": 2.04 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 8192 + }, + "cost": { + "input": 0.1003, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 220600, + "input": 220600, + "output": 65536 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 8192 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 4096 + }, + "cost": { + "input": 2.499, + "output": 2.499 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.17, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + }, + "cost": { + "input": 0.33, + "output": 1.32 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + }, + "cost": { + "input": 0.07, + "output": 0.07 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 0.2006, + "output": 0.2006 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.493, + "output": 0.493 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 8192 + }, + "cost": { + "input": 0.306, + "output": 1.003 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + }, + "cost": { + "input": 0.1343, + "output": 0.3349 + } + }, + "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, + "limit": { + "context": 80000, + "input": 80000, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 14.994, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + }, + "cost": { + "input": 1.5997, + "output": 6.392 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + }, + "cost": { + "input": 1.989, + "output": 7.99 + } + }, + "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, + "limit": { + "context": 995904, + "input": 995904, + "output": 32768 + }, + "cost": { + "input": 0.3995, + "output": 1.2002 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 32768 + }, + "cost": { + "input": 0.69989, + "output": 0.69989 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 98304 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 30, + "output": 30 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.25, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 1048000, + "input": 1048000, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 65536 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 6 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 9.996, + "output": 9.996 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 4.998, + "output": 6.987 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.4, + "output": 1.7 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 128000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 96000 + }, + "cost": { + "input": 0.42, + "output": 0.42 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 2097152, + "input": 2097152, + "output": 8192 + }, + "cost": { + "input": 1.989, + "output": 7.956 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.1496, + "output": 0.595 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 991800, + "output": 65536 + }, + "cost": { + "input": 0.45, + "output": 2.7 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + }, + "cost": { + "input": 0.17, + "output": 0.66 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.55, + "output": 1.43 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 1 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 1.1, + "output": 2 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 96000 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 128000 + }, + "cost": { + "input": 0.782, + "output": 3.876 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + }, + "cost": { + "input": 0.1989, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 1.292, + "output": 4.998 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32000 + }, + "cost": { + "input": 0.1462, + "output": 0.8738 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 60000, + "input": 60000, + "output": 128000 + }, + "cost": { + "input": 3.4, + "output": 13.6 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 8000, + "input": 8000, + "output": 16384 + }, + "cost": { + "input": 0.66, + "output": 2.6 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32000 + }, + "cost": { + "input": 0.0493, + "output": 0.4845 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + }, + "cost": { + "input": 15, + "output": 75 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.132, + "output": 0.55 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 1.5, + "output": 6 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 8192 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 8000, + "input": 8000, + "output": 4096 + }, + "cost": { + "input": 1.802, + "output": 1.802 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 16384 + }, + "cost": { + "input": 4.998, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 8000, + "input": 8000, + "output": 4096 + }, + "cost": { + "input": 2.006, + "output": 2.006 + } + }, + "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, + "limit": { + "context": 8000, + "input": 8000, + "output": 4096 + }, + "cost": { + "input": 0.2006, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 64000, + "input": 64000, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 1.7 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + }, + "cost": { + "input": 0.7, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + }, + "cost": { + "input": 0.1989, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 127000, + "input": 127000, + "output": 128000 + }, + "cost": { + "input": 1.003, + "output": 1.003 + } + }, + "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, + "limit": { + "context": 158600, + "input": 158600, + "output": 65536 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + }, + "cost": { + "input": 1.989, + "output": 7.99 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + }, + "cost": { + "input": 0.495, + "output": 1.43 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.01, + "output": 0.01 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + }, + "cost": { + "input": 0.0374, + "output": 0.374 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 0.25599999, + "output": 0.30499999 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + }, + "cost": { + "input": 0.165, + "output": 0.66 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 98304 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 24000, + "input": 24000, + "output": 8192 + }, + "cost": { + "input": 0.187, + "output": 0.374 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + }, + "cost": { + "input": 0.4, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 7.497, + "output": 7.497 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 5, + "output": 5 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 1.2002, + "output": 6.001 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 131072 + }, + "cost": { + "input": 0.1394, + "output": 1.3328 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 4.998, + "output": 25.007 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 16000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 2.5, + "output": 11 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + }, + "cost": { + "input": 0.33, + "output": 1.32 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 24576, + "input": 24576, + "output": 8192 + }, + "cost": { + "input": 0.493, + "output": 0.493 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + }, + "cost": { + "input": 5, + "output": 5 + } + }, + "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, + "limit": { + "context": 16000, + "input": 16000, + "output": 8192 + }, + "cost": { + "input": 7.004, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + }, + "cost": { + "input": 0.799, + "output": 1.445 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 16000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + }, + "cost": { + "input": 3.502, + "output": 10.506 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + }, + "cost": { + "input": 0.2499, + "output": 0.6494 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.157, + "output": 0.157 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 31.46, + "output": 31.46 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 8192 + }, + "cost": { + "input": 0.04998, + "output": 0.2006 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.07, + "output": 0.11 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 128000 + }, + "cost": { + "input": 0.782, + "output": 3.893 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 1.7 + } + }, + "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, + "limit": { + "context": 4096, + "input": 4096, + "output": 4096 + }, + "cost": { + "input": 2.5, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 14.994, + "output": 59.993 + } + }, + "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, + "limit": { + "context": 202600, + "input": 202600, + "output": 98304 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 65536 + }, + "cost": { + "input": 1.088, + "output": 4.3996 + } + }, + "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, + "limit": { + "context": 245800, + "output": 65536 + }, + "cost": { + "input": 1.3, + "output": 7.8 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "cost": { + "input": 14.994, + "output": 75.004 + } + }, + "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, + "limit": { + "context": 12000, + "input": 12000, + "output": 4096 + }, + "cost": { + "input": 0.2006, + "output": 0.2006 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + }, + "cost": { + "input": 9.996, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + }, + "cost": { + "input": 2.992, + "output": 14.994 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 2 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 4096 + }, + "cost": { + "input": 0.2006, + "output": 0.2006 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + }, + "cost": { + "input": 1.989, + "output": 7.99 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 1.4, + "output": 5.3 + } + }, + "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, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + }, + "cost": { + "input": 0.1003, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 8192 + }, + "cost": { + "input": 0.0748, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 9.996, + "output": 30.005 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 15.73, + "output": 15.73 + } + }, + "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, + "limit": { + "context": 10000000, + "input": 10000000, + "output": 8192 + }, + "cost": { + "input": 0.1003, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 127000, + "input": 127000, + "output": 128000 + }, + "cost": { + "input": 2.006, + "output": 7.9985 + } + }, + "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, + "limit": { + "context": 1048000, + "input": 1048000, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 65536 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 2.42, + "output": 2.42 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + }, + "cost": { + "input": 0.459, + "output": 1.377 + } + }, + "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, + "limit": { + "context": 991800, + "output": 65536 + }, + "cost": { + "input": 0.19, + "output": 1.16 + } + }, + "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, + "limit": { + "context": 8000, + "input": 8000, + "output": 4096 + }, + "cost": { + "input": 2.499, + "output": 9.996 + } + }, + "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, + "limit": { + "context": 8000, + "input": 8000, + "output": 4096 + }, + "cost": { + "input": 2.499, + "output": 9.996 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 0.17, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65535 + }, + "cost": { + "input": 0.3, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 131000, + "input": 131000, + "output": 65535 + }, + "cost": { + "input": 0.85, + "output": 3.3 + } + }, + "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, + "limit": { + "context": 258048, + "input": 258048, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 203000, + "input": 203000, + "output": 65535 + }, + "cost": { + "input": 1.2, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + }, + "cost": { + "input": 0.7, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262000, + "input": 262000, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.44999999999999996 + } + }, + "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, + "limit": { + "context": 164000, + "input": 164000, + "output": 8192 + }, + "cost": { + "input": 1, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 2, + "output": 2 + } + }, + "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, + "limit": { + "context": 203000, + "input": 203000, + "output": 65535 + }, + "cost": { + "input": 0.75, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65535 + }, + "cost": { + "input": 0.3, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 164000, + "input": 164000, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 1 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 1.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 203000, + "input": 203000, + "output": 65535 + }, + "cost": { + "input": 0.15, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + }, + "cost": { + "input": 2, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65535 + }, + "cost": { + "input": 2, + "output": 2 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 163000, + "input": 163000, + "output": 65536 + }, + "cost": { + "input": 0.27999999999999997, + "output": 0.42000000000000004 + } + }, + "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, + "limit": { + "context": 160000, + "input": 160000, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 163000, + "input": 163000, + "output": 65536 + }, + "cost": { + "input": 0.27999999999999997, + "output": 0.42000000000000004 + } + }, + "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, + "limit": { + "context": 163000, + "input": 163000, + "output": 65536 + }, + "cost": { + "input": 0.27999999999999997, + "output": 0.42000000000000004 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 2.006, + "output": 2.006 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 1, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.69989, + "output": 0.69989 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 4000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + }, + "cost": { + "input": 0.045000000000000005, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8192, + "output": 4096 + }, + "cost": { + "input": 0.306, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 1.7999999999999998, + "output": 1.7999999999999998 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.2006, + "output": 0.39949999999999997 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + }, + "cost": { + "input": 0.408, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.2006, + "output": 0.39949999999999997 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.27999999999999997, + "output": 0.42000000000000004 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 2.006, + "output": 2.992 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 2.006, + "output": 2.992 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.7, + "output": 0.95 + } + }, + "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, + "limit": { + "context": 6144, + "input": 6144, + "output": 4096 + }, + "cost": { + "input": 0.7989999999999999, + "output": 1.2069999999999999 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 36864, + "input": 36864, + "output": 36864 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.44999999999999996 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 128000 + }, + "cost": { + "input": 0.15, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 128000 + }, + "cost": { + "input": 0.3, + "output": 2.55 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 2.55 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 2.55 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 128000 + }, + "cost": { + "input": 0.3, + "output": 2.55 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 128000 + }, + "cost": { + "input": 0.07, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + }, + "cost": { + "input": 0.5, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + }, + "cost": { + "input": 0.44, + "output": 0.44 + } + }, + "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, + "limit": { + "context": 16000, + "input": 16000, + "output": 8192 + }, + "cost": { + "input": 4.505, + "output": 4.505 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.27, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 32768 + }, + "cost": { + "input": 0.1989, + "output": 0.595 + } + }, + "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, + "limit": { + "context": 262144, + "input": 262144, + "output": 256000 + }, + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 262144, + "input": 262144, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.8999999999999999 + } + }, + "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, + "limit": { + "context": 262144, + "input": 262144, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + }, + "cost": { + "input": 0.25499999999999995, + "output": 0.25499999999999995 + } + }, + "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, + "limit": { + "context": 262144, + "input": 262144, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 32768 + }, + "cost": { + "input": 0.8999999999999999, + "output": 0.8999999999999999 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.1003, + "output": 0.1207 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.0544, + "output": 0.0544 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.060000000000000005, + "output": 0.060000000000000005 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 256000 + }, + "cost": { + "input": 2.006, + "output": 6.001 + } + }, + "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, + "limit": { + "context": 262144, + "input": 262144, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.5, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + }, + "cost": { + "input": 0.05, + "output": 0.23 + } + }, + "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, + "limit": { + "context": 328000, + "input": 328000, + "output": 65536 + }, + "cost": { + "input": 0.085, + "output": 0.46 + } + }, + "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, + "limit": { + "context": 1048576, + "input": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.18000000000000002, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + }, + "cost": { + "input": 0.9009999999999999, + "output": 0.9009999999999999 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + }, + "cost": { + "input": 0.0306, + "output": 0.0493 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + }, + "cost": { + "input": 0.0544, + "output": 0.0544 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + }, + "cost": { + "input": 0.1, + "output": 2 + } + }, + "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, + "limit": { + "context": 4000, + "input": 4000, + "output": 4096 + }, + "cost": { + "input": 0.1003, + "output": 0.1003 + } + }, + "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, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 131072 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + }, + "cost": { + "input": 10, + "output": 20 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 0.476, + "output": 1.428 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 2.856, + "output": 14.246 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 262144 + }, + "cost": { + "input": 0.17, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.17, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.357, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.05, + "output": 0.25 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 16384 + }, + "cost": { + "input": 0.31, + "output": 0.31 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.1003, + "output": 0.1207 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.1003, + "output": 0.1207 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + }, + "cost": { + "input": 0.2006, + "output": 0.2414 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + }, + "cost": { + "input": 0.31, + "output": 0.31 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.408, + "output": 0.595 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + }, + "cost": { + "input": 0.1003, + "output": 0.1207 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + }, + "cost": { + "input": 0.1003, + "output": 0.1207 + } + }, + "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, + "limit": { + "context": 64000, + "input": 64000, + "output": 32768 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 163840, + "input": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27999999999999997, + "output": 0.42000000000000004 + } + }, + "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, + "limit": { + "context": 163840, + "input": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27999999999999997, + "output": 0.42000000000000004 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 163840 + }, + "cost": { + "input": 0.4, + "output": 1.7 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 20 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.088, + "output": 0.35 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 4.998, + "output": 14.993999999999998 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 21, + "output": 168 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 0.64, + "output": 2.588 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.1496, + "output": 0.595 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 9.996, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 14.993999999999998, + "output": 59.993 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 2.499, + "output": 9.996 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 14.993999999999998, + "output": 59.993 + } + }, + "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, + "limit": { + "context": 16385, + "input": 16385, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 9.996, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "cost": { + "input": 9.996, + "output": 30.004999999999995 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 150, + "output": 600 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 9.996, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 1.47, + "output": 5.88 + } + }, + "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, + "limit": { + "context": 1047576, + "input": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.04, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 32768 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 2.499, + "output": 9.996 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 9.996, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "cost": { + "input": 9.996, + "output": 19.992 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0.05, + "output": 0.25 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 1047576, + "input": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8 + } + }, + "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, + "limit": { + "context": 1047576, + "input": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6 + } + }, + "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, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 300000, + "input": 300000, + "output": 5120 + }, + "cost": { + "input": 0.0595, + "output": 0.238 + } + }, + "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, + "limit": { + "context": 300000, + "input": 300000, + "output": 32000 + }, + "cost": { + "input": 0.7989999999999999, + "output": 3.1959999999999997 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 65535 + }, + "cost": { + "input": 0.5099999999999999, + "output": 4.25 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 5120 + }, + "cost": { + "input": 0.0357, + "output": 0.1394 + } + }, + "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, + "limit": { + "context": 20480, + "input": 20480, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 20480, + "input": 20480, + "output": 16384 + }, + "cost": { + "input": 0.306, + "output": 0.357 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.2006, + "output": 0.2006 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.700000007, + "output": 0.700000007 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 65535 + }, + "cost": { + "input": 0.4, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 64000, + "input": 64000, + "output": 96000 + }, + "cost": { + "input": 0.6, + "output": 1.7999999999999998 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 65535 + }, + "cost": { + "input": 0.4, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 64000, + "input": 64000, + "output": 96000 + }, + "cost": { + "input": 0.6, + "output": 1.7999999999999998 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.13999999999999999, + "output": 0.5599999999999999 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + }, + "cost": { + "input": 0.35, + "output": 1.15 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.25499999999999995, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + }, + "cost": { + "input": 0.02, + "output": 0.16 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0.060000000000000005, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.16 + } + }, + "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, + "limit": { + "context": 204800, + "input": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 1000192, + "input": 1000192, + "output": 16384 + }, + "cost": { + "input": 0.1394, + "output": 1.1219999999999999 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + }, + "cost": { + "input": 0.33, + "output": 1.32 + } + }, + "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, + "limit": { + "context": 65532, + "input": 65532, + "output": 2048 + }, + "cost": { + "input": 0.30200000000000005, + "output": 1.2069999999999999 + } + }, + "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, + "limit": { + "context": 204800, + "input": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.29, + "output": 1.74 + } + }, + "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, + "limit": { + "context": 258048, + "input": 258048, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.29, + "output": 1.74 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.1003, + "output": 0.1003 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + }, + "cost": { + "input": 0.272, + "output": 0.272 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.2006, + "output": 0.2006 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 96000 + }, + "cost": { + "input": 0.2992, + "output": 0.2992 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 8000 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 8000 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 32000, + "input": 32000, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 8192 + }, + "cost": { + "input": 0.0748, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 2 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + }, + "cost": { + "input": 1.15, + "output": 8 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.53, + "output": 2.73 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.53, + "output": 2.73 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 262144 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 262144 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 40960 + }, + "cost": { + "input": 0.13999999999999999, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + }, + "cost": { + "input": 3.995, + "output": 7.99 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + }, + "cost": { + "input": 0.2006, + "output": 0.2006 + } + }, + "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, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + }, + "cost": { + "input": 0.7989999999999999, + "output": 1.394 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.08, + "output": 0.24000000000000002 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 131072 + }, + "cost": { + "input": 0.6052, + "output": 2.4225000000000003 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "cost": { + "input": 4.998, + "output": 25.007 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "cost": { + "input": 4.998, + "output": 25.007 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "cost": { + "input": 2.992, + "output": 14.993999999999998 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "cost": { + "input": 4.998, + "output": 25.007 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "cost": { + "input": 4.998, + "output": 25.007 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "cost": { + "input": 2.992, + "output": 14.993999999999998 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "cost": { + "input": 4.998, + "output": 25.007 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 2.006, + "output": 2.006 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.7989999999999999, + "output": 0.7989999999999999 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 2.006, + "output": 2.006 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.7989999999999999, + "output": 0.7989999999999999 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 1.4, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.7, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.7, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + }, + "cost": { + "input": 0.7, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + }, + "cost": { + "input": 0.7, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 0.102, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 0.102, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 0.102, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 0.102, + "output": 0.306 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "cost": { + "input": 0.31, + "output": 0.31 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 0.49299999999999994, + "output": 0.49299999999999994 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + }, + "cost": { + "input": 0.7, + "output": 0.7 + } + } + } + }, + "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"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.25, "output": 10, "cache_read": 0.125 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } }, - "gpt-3.5-turbo": { - "id": "gpt-3.5-turbo", - "name": "GPT-3.5-turbo", + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.6, + "output": 3 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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": false, - "structured_output": false, + "tool_call": true, "temperature": true, - "knowledge": "2021-09-01", - "release_date": "2023-03-01", - "last_updated": "2023-11-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2024-12-06", + "last_updated": "2024-12-06", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.59, + "output": 0.79 + } + }, + "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.5, "output": 1.5, "cache_read": 1.25 }, - "limit": { "context": 16385, "output": 4096 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 20, + "output": 40 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 1.2, + "output": 6 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.79, + "output": 0.79 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75 + } }, "gpt-5.4": { "id": "gpt-5.4", @@ -1112,4666 +17818,45 @@ "knowledge": "2025-08-31", "release_date": "2026-03-05", "last_updated": "2026-03-05", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, "cost": { "input": 2.5, - "output": 15, - "cache_read": 0.25, - "context_over_200k": { "input": 5, "output": 22.5, "cache_read": 0.5 } + "output": 15 + } + }, + "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"] }, - "limit": { "context": 1050000, "input": 922000, "output": 128000 } - }, - "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"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 15, "output": 60, "cache_read": 7.5 }, - "limit": { "context": 200000, "output": 100000 } - }, - "codex-mini-latest": { - "id": "codex-mini-latest", - "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 } - }, - "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"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 2, "output": 8, "cache_read": 0.5 }, - "limit": { "context": 200000, "output": 100000 } - }, - "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.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-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 } - }, - "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-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 } - }, - "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 } - }, - "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.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-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 } - }, - "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-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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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/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/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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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/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 } - } - } - }, - "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-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 } - }, - "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-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 } - }, - "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-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-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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - } - } - }, - "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.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.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": { - "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": { - "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-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 } - }, - "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 } - } - } - }, - "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": { - "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/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-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-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.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-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/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/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/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/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-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.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/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/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/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.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-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-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-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-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-08-31", - "release_date": "2026-02-05", - "last_updated": "2026-02-05", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, "open_weights": false, + "limit": { + "context": 400000, + "output": 128000 + }, "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-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-07-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-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-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-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-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.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-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-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-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 } - }, - "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/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/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/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/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/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/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/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/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/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/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/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/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/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/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-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-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/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/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/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/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 } - }, - "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/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/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/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-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-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/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-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/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.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-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-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/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.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-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/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/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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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.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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "mimo-v2-flash": { - "id": "mimo-v2-flash", - "name": "Mimo-V2-Flash", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": false, - "temperature": true, - "release_date": "2025-12-17", - "last_updated": "2025-12-17", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "limit": { "context": 256000, "output": 256000 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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.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-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 } - }, - "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 } - }, - "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.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 } - }, - "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.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-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.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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "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 } - }, - "xiaomi/mimo-v2-flash": { - "id": "xiaomi/mimo-v2-flash", - "name": "Xiaomi/Mimo-V2-Flash", - "attachment": false, - "reasoning": true, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-12-26", - "last_updated": "2025-12-26", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "limit": { "context": 256000, "output": 256000 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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 } - } - } - }, - "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-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", - "last_updated": "2026-02", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.75, "output": 2.4 }, - "limit": { "context": 200000, "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", - "last_updated": "2025-12", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.45, "output": 1.65 }, - "limit": { "context": 200000, "output": 128000 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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-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-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": { - "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, "output": 0, "cache_read": 0, "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.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, "output": 0, "cache_read": 0, "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, "output": 0 }, - "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-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, "output": 0, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 204800, "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.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, "output": 0 }, - "limit": { "context": 64000, "output": 16384 } - }, - "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.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 } - } - } - }, - "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-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-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": { - "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-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-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", - "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 } - }, - "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-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", - "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-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-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-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-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-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-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-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-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-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-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 } + "input": 1.25, + "output": 10 + } }, "claude-haiku-4-5-20251001": { "id": "claude-haiku-4-5-20251001", @@ -5784,30 +17869,121 @@ "knowledge": "2025-02-28", "release_date": "2025-10-15", "last_updated": "2025-10-15", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5 + } }, - "claude-sonnet-4-5": { - "id": "claude-sonnet-4-5", - "name": "Claude Sonnet 4.5 (latest)", + "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-07-31", - "release_date": "2025-09-29", - "last_updated": "2025-09-29", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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, "cache_read": 0.3, "cache_write": 3.75 }, - "limit": { "context": 200000, "output": 64000 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } }, - "claude-3-7-sonnet-latest": { - "id": "claude-3-7-sonnet-latest", - "name": "Claude Sonnet 3.7 (latest)", + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 8 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "claude-3-7-sonnet-20250219": { + "id": "claude-3-7-sonnet-20250219", + "name": "Claude Sonnet 3.7", "family": "claude-sonnet", "attachment": true, "reasoning": true, @@ -5816,909 +17992,219 @@ "knowledge": "2024-10-31", "release_date": "2025-02-19", "last_updated": "2025-02-19", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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-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-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-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 } - } - } - }, - "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 } - } - } - }, - "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-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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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.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-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.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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15 + } }, "o3": { "id": "o3", "name": "o3", + "family": "o", "attachment": true, - "reasoning": false, + "reasoning": true, "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2026-01", - "last_updated": "2026-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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": 10, "output": 40 }, - "limit": { "context": 131072, "output": 131072 } + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8 + } }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "gpt-5.1": { - "id": "gpt-5.1", - "name": "gpt-5.1", + "gpt-5": { + "id": "gpt-5", + "name": "GPT-5", "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"] }, + "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.125, "output": 9 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } }, - "gpt-5-chat-latest": { - "id": "gpt-5-chat-latest", - "name": "gpt-5-chat-latest", + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75 + } + }, + "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, - "release_date": "2026-01", - "last_updated": "2026-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "knowledge": "2024-04", + "release_date": "2025-04-14", + "last_updated": "2025-04-14", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.125, "output": 9 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8 + } }, - "grok-4-fast-reasoning": { - "id": "grok-4-fast-reasoning", - "name": "grok-4-fast-reasoning", - "family": "grok", + "gpt-4.1-mini": { + "id": "gpt-4.1-mini", + "name": "GPT-4.1 Mini", + "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"] }, + "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.18, "output": 0.45 }, - "limit": { "context": 2000000, "output": 2000000 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6 + } }, "gpt-5.1-codex": { "id": "gpt-5.1-codex", - "name": "gpt-5.1-codex", - "family": "gpt-codex", + "name": "GPT-5.1 Codex", + "family": "gpt", "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"] }, + "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.125, "output": 9 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } }, - "gpt-5.2-pro": { - "id": "gpt-5.2-pro", - "name": "gpt-5.2-pro", - "family": "gpt-pro", + "gpt-4o-2024-11-20": { + "id": "gpt-4o-2024-11-20", + "name": "GPT-4o (2024-11-20)", + "family": "gpt", "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 } - }, - "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 } + "knowledge": "2024-10", + "release_date": "2024-11-20", + "last_updated": "2024-11-20", + "modalities": { + "input": ["text", "image", "audio"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } }, "deepseek/deepseek-v3.1": { "id": "deepseek/deepseek-v3.1", @@ -6727,46 +18213,190 @@ "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"] }, + "release_date": "2025-01-20", + "last_updated": "2025-01-20", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.27, "output": 1 }, - "limit": { "context": 163840, "output": 32768 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.55, + "output": 1.66 + } }, - "deepseek/deepseek-r1-0528": { - "id": "deepseek/deepseek-r1-0528", - "name": "DeepSeek R1 0528", - "family": "deepseek-thinking", + "Qwen/QwQ-32B": { + "id": "Qwen/QwQ-32B", + "name": "QwQ 32B", + "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"] }, + "release_date": "2024-11-28", + "last_updated": "2024-11-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.7, "output": 2.5 }, - "limit": { "context": 163840, "output": 32768 } + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } }, - "zai-org/glm-4.7-flash": { - "id": "zai-org/glm-4.7-flash", - "name": "GLM-4.7-Flash", + "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, + "limit": { + "context": 262144, + "output": 8192 + }, + "cost": { + "input": 0.13, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.09, + "output": 0.29 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.29, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.11, + "output": 0.38 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "zai-org/glm-5": { + "id": "zai-org/glm-5", + "name": "GLM-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"] }, + "release_date": "2026-02-11", + "last_updated": "2026-02-11", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.07, "output": 0.4 }, - "limit": { "context": 200000, "output": 128000 } + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2 + } }, "zai-org/glm-4.5": { "id": "zai-org/glm-4.5", @@ -6775,318 +18405,3291 @@ "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 3.5, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.14, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.02, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 7 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.27, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.08, + "output": 0.44 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 2.5, + "cache_read": 0.0625 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32000 + }, + "cost": { + "input": 0.25, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "tiers": [ + { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 0.5, + "output": 3, + "cache_read": 0.05 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125, + "tiers": [ + { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3 + } + } + } + }, + "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": "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 } + "release_date": "2025-09-27", + "last_updated": "2026-01-16", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } }, - "zai-org/glm-4.5v": { - "id": "zai-org/glm-4.5v", - "name": "GLM 4.5V", - "family": "glmv", + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.29, + "output": 1.74 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.23, + "output": 1.86 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.29, + "output": 2.32 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.22, + "output": 1.74 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.26, + "output": 2.09 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.23, + "output": 1.86 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.59, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.18, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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": "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 } + "release_date": "2025-10-11", + "last_updated": "2025-11-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.29, + "output": 1 + } }, - "zai-org/glm-4.7": { - "id": "zai-org/glm-4.7", - "name": "GLM-4.7", - "family": "glm", + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.3, + "output": 1.5 + } + }, + "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": "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 } + "release_date": "2025-09-25", + "last_updated": "2025-11-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } }, - "baidu/ernie-4.5-300b-a47b-paddle": { - "id": "baidu/ernie-4.5-300b-a47b-paddle", - "name": "ERNIE 4.5 300B A47B", + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.27, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.13, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.18, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 131000, + "output": 4000 + }, + "cost": { + "input": 0.59, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.09, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.09, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.06, + "output": 0.06 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.14, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.18, + "output": 2 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.15, + "output": 0.58 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.29, + "output": 1 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.18, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.05, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.45, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 262000, + "output": 131000 + }, + "cost": { + "input": 0.09, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.2, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 131000, + "output": 4000 + }, + "cost": { + "input": 0.59, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.14, + "output": 0.86 + } + }, + "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, + "limit": { + "context": 205000, + "output": 205000 + }, + "cost": { + "input": 0.5, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.86 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 33000, + "output": 33000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 205000, + "output": 205000 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 205000, + "output": 205000 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 205000, + "output": 205000 + }, + "cost": { + "input": 1, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.5, + "output": 2.18 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 0.42 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.55, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.45, + "output": 2.25 + } + }, + "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, + "limit": { + "context": 192000, + "output": 131000 + }, + "cost": { + "input": 0.3, + "output": 1.22 + } + }, + "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, + "limit": { + "context": 197000, + "output": 131000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 0.42 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.5, + "output": 2.18 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.18, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 4000, + "output": 4000 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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": "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 } + "release_date": "2025-07-02", + "last_updated": "2025-11-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.28, + "output": 1.1 + } }, - "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 } - }, - "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 } - }, - "minimax/minimax-m2.1": { - "id": "minimax/minimax-m2.1", - "name": "Minimax M2.1", - "family": "minimax", + "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": "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 } + "release_date": "2025-04-18", + "last_updated": "2025-11-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } }, - "qwen/qwen3-235b-a22b-instruct-2507": { - "id": "qwen/qwen3-235b-a22b-instruct-2507", + "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, + "limit": { + "context": 33000, + "output": 33000 + }, + "cost": { + "input": 0.27, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 33000, + "output": 33000 + }, + "cost": { + "input": 0.086, + "output": 0.086 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.086, + "output": 0.086 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.55, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.21, + "output": 0.57 + } + } + } + }, + "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, - "structured_output": true, "temperature": true, - "release_date": "2026-01", - "last_updated": "2026-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-08-23", + "last_updated": "2025-08-23", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 0.8 }, - "limit": { "context": 131072, "output": 16384 } + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.3 + } }, - "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-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-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 } - }, - "qwen/qwen3-coder-480b-a35b-instruct": { - "id": "qwen/qwen3-coder-480b-a35b-instruct", + "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, - "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 } + "release_date": "2025-08-23", + "last_updated": "2025-08-23", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } }, - "qwen/qwen3-next-80b-a3b-thinking": { - "id": "qwen/qwen3-next-80b-a3b-thinking", - "name": "Qwen3 Next 80B A3B Thinking", + "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"] }, + "release_date": "2025-08-23", + "last_updated": "2025-08-23", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 1.5 }, - "limit": { "context": 65536, "output": 65536 } + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } }, - "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-instruct": { - "id": "qwen/qwen3-next-80b-a3b-instruct", - "name": "Qwen3 Next 80B A3B Instruct", - "family": "qwen", + "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, - "structured_output": true, "temperature": true, - "release_date": "2026-01", - "last_updated": "2026-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-07-28", + "last_updated": "2025-07-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 1.5 }, - "limit": { "context": 65536, "output": 65536 } + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.1, + "output": 0.5 + } }, - "qwen/qwen3-32b-fp8": { - "id": "qwen/qwen3-32b-fp8", - "name": "Qwen3 32B", - "family": "qwen", + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 75000, + "output": 163840 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 75000, + "output": 163840 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 75000, + "output": 163840 + }, + "cost": { + "input": 0.5, + "output": 2.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.5 + } + } + } + }, + "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, + "limit": { + "context": 196608, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "sonar-deep-research": { + "id": "sonar-deep-research", + "name": "Perplexity Sonar Deep Research", "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 } + "temperature": false, + "knowledge": "2025-01", + "release_date": "2025-02-01", + "last_updated": "2025-09-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "reasoning": 3 + } }, - "moonshotai/kimi-k2.5": { - "id": "moonshotai/kimi-k2.5", - "name": "Kimi K2.5", - "family": "kimi", + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 1, + "output": 1 + } + }, + "sonar-reasoning-pro": { + "id": "sonar-reasoning-pro", + "name": "Sonar Reasoning Pro", + "family": "sonar-reasoning", "attachment": true, "reasoning": true, - "tool_call": true, - "structured_output": true, + "tool_call": false, "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-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 } - }, - "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 } - }, - "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 } + "knowledge": "2025-09-01", + "release_date": "2024-01-01", + "last_updated": "2025-09-01", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 8 + } } } }, @@ -7109,10 +21712,20 @@ "knowledge": "2025-09", "release_date": "2025-12-01", "last_updated": "2026-02-28", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.28, "output": 0.42, "cache_read": 0.028 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } }, "deepseek-reasoner": { "id": "deepseek-reasoner", @@ -7121,15 +21734,87 @@ "attachment": true, "reasoning": true, "tool_call": true, - "interleaved": { "field": "reasoning_content" }, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, "knowledge": "2025-09", "release_date": "2025-12-01", "last_updated": "2026-02-28", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.28, "output": 0.42, "cache_read": 0.028 }, - "limit": { "context": 128000, "output": 64000 } + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } } } }, @@ -7141,22 +21826,6 @@ "name": "Llama", "doc": "https://llama.developer.meta.com/docs/models", "models": { - "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 } - }, "llama-3.3-70b-instruct": { "id": "llama-3.3-70b-instruct", "name": "Llama-3.3-70B-Instruct", @@ -7168,10 +21837,19 @@ "knowledge": "2023-12", "release_date": "2024-12-06", "last_updated": "2024-12-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, "cerebras-llama-4-maverick-17b-128e-instruct": { "id": "cerebras-llama-4-maverick-17b-128e-instruct", @@ -7184,42 +21862,19 @@ "knowledge": "2025-01", "release_date": "2025-04-05", "last_updated": "2025-04-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "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 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, "llama-3.3-8b-instruct": { "id": "llama-3.3-8b-instruct", @@ -7232,10 +21887,94 @@ "knowledge": "2023-12", "release_date": "2024-12-06", "last_updated": "2024-12-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, "llama-4-maverick-17b-128e-instruct-fp8": { "id": "llama-4-maverick-17b-128e-instruct-fp8", @@ -7248,404 +21987,1120 @@ "knowledge": "2024-08", "release_date": "2025-04-05", "last_updated": "2025-04-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } } } }, - "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", + "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": { - "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 } - }, - "claude-opus-4-5": { - "id": "claude-opus-4-5", - "name": "Claude Opus 4.5", - "family": "claude-opus", - "attachment": true, - "reasoning": true, - "tool_call": true, + "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-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" - } - }, - "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", - "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 } + "knowledge": "2025-06", + "release_date": "2026-01-20", + "last_updated": "2026-01-28", + "modalities": { + "input": ["text"], + "output": ["text"] }, - "limit": { "context": 200000, "output": 128000 }, - "provider": { - "npm": "@ai-sdk/anthropic", - "api": "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + "open_weights": true, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 } }, - "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" - } - }, - "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 } - }, - "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" - } - }, - "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" - } - }, - "o1-mini": { - "id": "o1-mini", - "name": "o1-mini", - "family": "o-mini", + "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": 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.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 } - }, - "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-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 } - }, - "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-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 } + "knowledge": "2025-06", + "release_date": "2026-01-20", + "last_updated": "2026-01-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "deepseek-v3.2": { - "id": "deepseek-v3.2", - "name": "DeepSeek-V3.2", + "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": "2024-07", - "release_date": "2025-12-01", - "last_updated": "2025-12-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-07", + "release_date": "2025-08-21", + "last_updated": "2025-08-21", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.58, "output": 1.68 }, - "limit": { "context": 128000, "output": 128000 } + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } }, - "o1-preview": { - "id": "o1-preview", - "name": "o1-preview", - "family": "o", + "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": 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-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-05", - "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 } - }, - "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-small-128k-instruct": { - "id": "phi-3-small-128k-instruct", - "name": "Phi-3-small-instruct (128k)", - "family": "phi", - "attachment": false, - "reasoning": false, "tool_call": false, + "structured_output": true, "temperature": true, - "knowledge": "2023-10", - "release_date": "2024-04-23", - "last_updated": "2024-04-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2024-10", + "release_date": "2025-01-23", + "last_updated": "2025-01-23", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 0.6 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "deepseek-r1-0528": { - "id": "deepseek-r1-0528", - "name": "DeepSeek-R1-0528", + "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-05-28", - "last_updated": "2025-05-28", - "modalities": { "input": ["text"], "output": ["text"] }, + "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 } + "limit": { + "context": 64000, + "output": 16000 + }, + "cost": { + "input": 0.7, + "output": 2.5 + } }, - "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, + "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-08", - "release_date": "2025-04-05", - "last_updated": "2025-04-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "knowledge": "2024-07", + "release_date": "2025-12-01", + "last_updated": "2025-12-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.25, "output": 1 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 0.41 + } }, - "cohere-embed-v-4-0": { - "id": "cohere-embed-v-4-0", - "name": "Embed v4", - "family": "cohere-embed", - "attachment": true, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.28, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "deepseek/deepseek-chat-v3-0324": { + "id": "deepseek/deepseek-chat-v3-0324", + "name": "DeepSeek V3 0324", + "family": "deepseek", + "attachment": false, "reasoning": false, "tool_call": false, - "temperature": false, - "release_date": "2025-04-15", - "last_updated": "2025-04-15", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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.12, "output": 0 }, - "limit": { "context": 128000, "output": 1536 } + "limit": { + "context": 16384, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "phi-4-reasoning-plus": { - "id": "phi-4-reasoning-plus", - "name": "Phi-4-reasoning-plus", - "family": "phi", + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 1048756, + "output": 262144 + }, + "status": "alpha", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 8000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 80000 + }, + "cost": { + "input": 0.22, + "output": 0.85 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 46864, + "output": 46864 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 67344, + "output": 67344 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 46864, + "output": 46864 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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-10", - "release_date": "2024-12-11", - "last_updated": "2024-12-11", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2023-12", + "release_date": "2024-08-16", + "last_updated": "2024-08-16", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.125, "output": 0.5 }, - "limit": { "context": 32000, "output": 4096 } + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "grok-3": { - "id": "grok-3", - "name": "Grok 3", + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.13, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.06, + "output": 0.12 + } + }, + "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, + "limit": { + "context": 96000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "status": "beta", + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 12, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 12, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05, + "cache_write": 0.05 + } + }, + "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, + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "x-ai/grok-3-beta": { + "id": "x-ai/grok-3-beta", + "name": "Grok 3 Beta", "family": "grok", "attachment": false, "reasoning": false, @@ -7654,223 +23109,577 @@ "knowledge": "2024-11", "release_date": "2025-02-17", "last_updated": "2025-02-17", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 3, "output": 15, "cache_read": 0.75 }, - "limit": { "context": 131072, "output": 8192 } + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75, + "cache_write": 15 + } }, - "cohere-command-a": { - "id": "cohere-command-a", - "name": "Command A", - "family": "command-a", + "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": "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 } + "knowledge": "2025-07", + "release_date": "2025-07-09", + "last_updated": "2025-07-09", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75, + "cache_write": 15, + "tiers": [ + { + "input": 6, + "output": 30, + "tier": { + "type": "context", + "size": 128000 + } + } + ] + } }, - "gpt-5-nano": { - "id": "gpt-5-nano", - "name": "GPT-5 Nano", - "family": "gpt-nano", - "attachment": true, + "x-ai/grok-3-mini": { + "id": "x-ai/grok-3-mini", + "name": "Grok 3 Mini", + "family": "grok", + "attachment": false, "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"] }, + "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.05, "output": 0.4, "cache_read": 0.01 }, - "limit": { "context": 272000, "output": 128000 } + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "cache_read": 0.075, + "cache_write": 0.5 + } }, - "grok-4-fast-reasoning": { - "id": "grok-4-fast-reasoning", - "name": "Grok 4 Fast (Reasoning)", + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05, + "cache_write": 0.05 + } + }, + "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, - "knowledge": "2025-07", - "release_date": "2025-09-19", - "last_updated": "2025-09-19", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "release_date": "2026-03-12", + "last_updated": "2026-03-12", + "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 } + "limit": { + "context": 2000000, + "output": 30000 + }, + "status": "beta", + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 12, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 12, + "cache_read": 0.4 + } + } }, - "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 } - }, - "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 } - }, - "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-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-05", - "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 } - }, - "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 } - }, - "deepseek-v3.1": { - "id": "deepseek-v3.1", - "name": "DeepSeek-V3.1", - "family": "deepseek", + "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-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 } + "knowledge": "2024-11", + "release_date": "2025-02-17", + "last_updated": "2025-02-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "cache_read": 0.075, + "cache_write": 0.5 + } }, - "gpt-5.1": { - "id": "gpt-5.1", - "name": "GPT-5.1", - "family": "gpt", + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75, + "cache_write": 15 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.066, + "output": 0.26, + "cache_read": 0.029, + "cache_write": 0.029 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.1, + "output": 0.5 + } + }, + "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": false, + "temperature": true, + "release_date": "2026-04-28", + "last_updated": "2026-04-28", + "modalities": { + "input": ["text", "image", "video", "audio"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.04, + "output": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.75, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 128000, + "output": 50000 + }, + "cost": { + "input": 0.25, + "output": 0.75, + "cache_read": 0.025 + } + }, + "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-14", - "last_updated": "2025-11-14", - "modalities": { "input": ["text", "image", "audio"], "output": ["text", "image", "audio"] }, + "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": 272000, "output": 128000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + } }, - "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-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 } - }, - "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 } - }, - "gpt-5.2-chat": { - "id": "gpt-5.2-chat", + "openai/gpt-5.2-chat": { + "id": "openai/gpt-5.2-chat", "name": "GPT-5.2 Chat", "family": "gpt-codex", "attachment": true, @@ -7881,542 +23690,155 @@ "knowledge": "2025-08-31", "release_date": "2025-12-11", "last_updated": "2025-12-11", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.75, "output": 14, "cache_read": 0.175 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "grok-3-mini": { - "id": "grok-3-mini", - "name": "Grok 3 Mini", - "family": "grok", + "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, - "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 } - }, - "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"] }, + "release_date": "2025-08-05", + "last_updated": "2025-08-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.3, "output": 0.61 }, - "limit": { "context": 8192, "output": 2048 } + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.24 + } }, - "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 } - }, - "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 } - }, - "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-5-chat": { - "id": "gpt-5-chat", - "name": "GPT-5 Chat", + "openai/gpt-5-chat": { + "id": "openai/gpt-5-chat", + "name": "GPT-5 Chat (latest)", "family": "gpt-codex", "attachment": true, "reasoning": true, "tool_call": false, - "temperature": false, - "knowledge": "2024-10-24", + "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"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.25, "output": 10, "cache_read": 0.13 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "gpt-5.4": { - "id": "gpt-5.4", - "name": "GPT-5.4", - "family": "gpt", + "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": "2026-03-05", - "last_updated": "2026-03-05", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "release_date": "2025-12-11", + "last_updated": "2025-12-11", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 2.5, "output": 15, "cache_read": 0.25 }, - "limit": { "context": 400000, "input": 272000, "output": 128000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 21, + "output": 168 + } }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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-4.1": { - "id": "gpt-4.1", - "name": "GPT-4.1", - "family": "gpt", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-05", - "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-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 } - }, - "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-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-mini": { - "id": "gpt-5-mini", + "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", + "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"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.25, "output": 2, "cache_read": 0.03 }, - "limit": { "context": 272000, "output": 128000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2 + } }, - "gpt-5.3-codex": { - "id": "gpt-5.3-codex", - "name": "GPT-5.3 Codex", + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4 + } + }, + "openai/gpt-5.3-codex": { + "id": "openai/gpt-5.3-codex", + "name": "GPT-5.3-Codex", "family": "gpt-codex", - "attachment": false, + "attachment": true, "reasoning": true, "tool_call": true, "structured_output": true, @@ -8424,373 +23846,317 @@ "knowledge": "2025-08-31", "release_date": "2026-02-24", "last_updated": "2026-02-24", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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 } - }, - "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-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 } - }, - "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": 2.5, "output": 10, "cache_read": 1.25 }, - "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-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 } - }, - "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" + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 } }, - "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 } - }, - "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 } - }, - "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 } - }, - "gpt-5": { - "id": "gpt-5", - "name": "GPT-5", + "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": "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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"] }, + "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": 15, "output": 120 }, - "limit": { "context": 400000, "output": 272000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } }, - "o3-mini": { - "id": "o3-mini", - "name": "o3-mini", - "family": "o-mini", + "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": 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 } - }, - "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"] }, + "temperature": true, + "release_date": "2025-08-05", + "last_updated": "2026-01-31", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.1, "output": 0 }, - "limit": { "context": 512, "output": 1024 } + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "gpt-5.4-pro": { - "id": "gpt-5.4-pro", + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "output": 100000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "openai/gpt-5.4-pro": { + "id": "openai/gpt-5.4-pro", "name": "GPT-5.4 Pro", "family": "gpt-pro", "attachment": true, @@ -8801,164 +24167,9693 @@ "knowledge": "2025-08-31", "release_date": "2026-03-05", "last_updated": "2026-03-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 30, "output": 180 }, - "limit": { "context": 400000, "input": 272000, "output": 128000 } + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "cache_read": 30 + } }, - "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 } - }, - "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 } - }, - "gpt-5.1-codex-mini": { - "id": "gpt-5.1-codex-mini", - "name": "GPT-5.1 Codex Mini", + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.2 + } + }, + "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-11-14", - "last_updated": "2025-11-14", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "release_date": "2025-10-06", + "last_updated": "2025-10-06", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.25, "output": 2, "cache_read": 0.025 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 400000, + "output": 272000 + }, + "cost": { + "input": 15, + "output": 120 + } }, - "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 } - }, - "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 } - } - } - }, - "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-4.7-flash": { - "id": "glm-4.7-flash", - "name": "GLM-4.7-Flash", - "family": "glm-flash", + "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, - "knowledge": "2025-04", - "release_date": "2026-01-19", - "last_updated": "2026-01-19", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-08-05", + "last_updated": "2025-08-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 200000, "output": 131072 } + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "glm-5-turbo": { - "id": "glm-5-turbo", + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.072, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 128000, + "output": 96000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131000 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } + }, + "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, + "limit": { + "context": 128000, + "output": 96000 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.6, + "output": 1.9, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 128000, + "output": 96000 + }, + "cost": { + "input": 0.2, + "output": 1.1 + } + }, + "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" }, + "interleaved": { + "field": "reasoning_content" + }, "structured_output": true, "temperature": true, "release_date": "2026-03-16", "last_updated": "2026-03-16", - "modalities": { "input": ["text"], "output": ["text"] }, + "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 } + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 0.96, + "output": 3.2, + "cache_read": 0.192, + "cache_write": 0 + } }, - "glm-4.5": { - "id": "glm-4.5", - "name": "GLM-4.5", + "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, + "limit": { + "context": 64000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 200000, + "output": 65535 + }, + "cost": { + "input": 0.07, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 196600, + "output": 118000 + }, + "cost": { + "input": 0.28, + "output": 1.15, + "cache_read": 0.28, + "cache_write": 1.15 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 1000000 + }, + "cost": { + "input": 0.2, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 40000 + }, + "cost": { + "input": 0.4, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.65, + "output": 3.25, + "cache_read": 0.13, + "cache_write": 0.8125 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.26, + "output": 0.78, + "cache_read": 0.052, + "cache_write": 0.325 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.065, + "output": 0.26 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.325, + "output": 1.95, + "cache_read": 0.0325, + "cache_write": 0.40625 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 1.2, + "output": 6, + "cache_read": 0.156, + "cache_write": 0.975 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.38, + "output": 1.53 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 262144, + "output": 81920 + }, + "cost": { + "input": 0.195, + "output": 1.56 + } + }, + "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, + "limit": { + "context": 262144, + "output": 81920 + }, + "cost": { + "input": 0.078, + "output": 0.312 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.14, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 128000, + "output": 66536 + }, + "cost": { + "input": 0.3, + "output": 1.5, + "cache_read": 0.039, + "cache_write": 0.24375 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.14, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 160000, + "output": 65536 + }, + "cost": { + "input": 0.07, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 262144, + "output": 66536 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.15, + "output": 0.85 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "reasoning": 12, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.02, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "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 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "reasoning": 12, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 66000 + }, + "cost": { + "input": 2, + "output": 12 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.03, + "output": 0.09 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.14, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.03, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "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, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.0375 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 96000, + "output": 96000 + }, + "cost": { + "input": 0.01703, + "output": 0.06815 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.031 + } + }, + "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, + "limit": { + "context": 96000, + "output": 96000 + }, + "cost": { + "input": 0.04, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.13, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "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, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.55, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5 + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5 + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 393216 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 393216 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 1000000 + }, + "cost": { + "input": 1.25, + "output": 2.5, + "cache_read": 0.2, + "context_over_200k": { + "input": 2.5, + "output": 5, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2.5, + "output": 5, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "context_over_200k": { + "input": 5, + "output": 22.5, + "cache_read": 0.5 + }, + "tiers": [ + { + "input": 5, + "output": 22.5, + "cache_read": 0.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "context_over_200k": { + "input": 60, + "output": 270 + }, + "tiers": [ + { + "input": 60, + "output": 270, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125, + "context_over_200k": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + }, + "tiers": [ + { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08, + "context_over_200k": { + "input": 0.8, + "output": 4, + "cache_read": 0.16 + }, + "tiers": [ + { + "input": 0.8, + "output": 4, + "cache_read": 0.16, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01 + } + } + } + }, + "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, + "limit": { + "context": 202800, + "output": 131072 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } + }, + "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, + "limit": { + "context": 160000, + "output": 160000 + }, + "cost": { + "input": 0.56, + "output": 1.68, + "cache_read": 0.28 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.22, + "output": 0.88 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.56, + "output": 1.68 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 198000, + "output": 198000 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.55, + "output": 2.19 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.3 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.15 + } + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 3.5, + "output": 14 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 2.1, + "output": 8.4 + } + } + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 128000 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 202752, + "output": 32768 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 128000 + }, + "status": "deprecated", + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08, + "tiers": [ + { + "input": 0.8, + "output": 4, + "cache_read": 0.16, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 0.8, + "output": 4, + "cache_read": 0.16 + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 0.625 + } + }, + "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, + "limit": { + "context": 202752, + "output": 32768 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.0028 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.0145 + } + }, + "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-01", + "release_date": "2026-02-12", + "last_updated": "2026-02-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 65536 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 128000 + }, + "status": "deprecated", + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0.2, + "output": 1.2, + "cache_read": 0.02, + "cache_write": 0.25 + } + } + } + }, + "databricks": { + "id": "databricks", + "env": ["DATABRICKS_HOST", "DATABRICKS_TOKEN"], + "npm": "@ai-sdk/openai-compatible", + "api": "https://${DATABRICKS_HOST}/ai-gateway/mlflow/v1", + "name": "Databricks", + "doc": "https://docs.databricks.com/aws/en/machine-learning/foundation-models/", + "models": { + "databricks-gpt-oss-120b": { + "id": "databricks-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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.072, + "output": 0.28 + } + }, + "databricks-gpt-oss-20b": { + "id": "databricks-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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.2 + } + }, + "databricks-claude-haiku-4-5": { + "id": "databricks-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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "databricks-claude-sonnet-4-6": { + "id": "databricks-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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "databricks-gemini-3-pro": { + "id": "databricks-gemini-3-pro", + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "databricks-gemini-3-1-pro": { + "id": "databricks-gemini-3-1-pro", + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "databricks-gpt-5-4-mini": { + "id": "databricks-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, + "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" + } + } + } + } + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "databricks-claude-opus-4-6": { + "id": "databricks-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, + "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" + } + } + } + } + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "databricks-gemini-2-5-pro": { + "id": "databricks-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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125, + "context_over_200k": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + }, + "tiers": [ + { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "databricks-gpt-5-nano": { + "id": "databricks-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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "databricks-gpt-5-4": { + "id": "databricks-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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "experimental": { + "modes": { + "fast": { + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5 + }, + "provider": { + "body": { + "service_tier": "priority" + } + } + } + } + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "context_over_200k": { + "input": 5, + "output": 22.5, + "cache_read": 0.5 + }, + "tiers": [ + { + "input": 5, + "output": 22.5, + "cache_read": 0.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "databricks-gemini-3-1-flash-lite": { + "id": "databricks-gemini-3-1-flash-lite", + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "input_audio": 0.5 + } + }, + "databricks-gpt-5": { + "id": "databricks-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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "databricks-claude-opus-4-1": { + "id": "databricks-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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "databricks-gpt-5-2": { + "id": "databricks-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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "databricks-gpt-5-5": { + "id": "databricks-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, + "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" + } + } + } + } + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "databricks-gemini-3-flash": { + "id": "databricks-gemini-3-flash", + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "input_audio": 1 + } + }, + "databricks-claude-opus-4-5": { + "id": "databricks-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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "databricks-gpt-5-mini": { + "id": "databricks-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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "databricks-claude-sonnet-4": { + "id": "databricks-claude-sonnet-4", + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "databricks-gpt-5-1": { + "id": "databricks-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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "databricks-claude-opus-4-7": { + "id": "databricks-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, + "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" + } + } + } + } + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "databricks-gemini-2-5-flash": { + "id": "databricks-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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.03, + "input_audio": 1 + } + }, + "databricks-gpt-5-4-nano": { + "id": "databricks-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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "databricks-claude-sonnet-4-5": { + "id": "databricks-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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + } + } + }, + "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, + "limit": { + "context": 106000, + "output": 4096 + }, + "cost": { + "input": 0.22, + "output": 0.95, + "cache_read": 0.11, + "cache_write": 0.44 + } + }, + "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, + "limit": { + "context": 262144, + "output": 4096 + }, + "cost": { + "input": 0.1, + "output": 0.8, + "cache_read": 0.05, + "cache_write": 0.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 4096 + }, + "cost": { + "input": 0.11, + "output": 0.6, + "cache_read": 0.055, + "cache_write": 0.22 + } + }, + "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, + "limit": { + "context": 32000, + "output": 4096 + }, + "cost": { + "input": 0.05, + "output": 0.22, + "cache_read": 0.025, + "cache_write": 0.1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 0.4, + "output": 1.75, + "cache_read": 0.2, + "cache_write": 0.8 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 1.5, + "cache_read": 0.25, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 1, + "cache_write": 4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.02, + "output": 0.04, + "cache_read": 0.01, + "cache_write": 0.04 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.05, + "output": 0.22, + "cache_read": 0.025, + "cache_write": 0.1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.13, + "output": 0.38, + "cache_read": 0.065, + "cache_write": 0.26 + } + }, + "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, + "limit": { + "context": 430000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.075, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 16000, + "output": 4096 + }, + "cost": { + "input": 0.35, + "output": 0.4, + "cache_read": 0.175, + "cache_write": 0.7 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 8.75, + "cache_read": 1, + "cache_write": 4 + } + }, + "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, + "limit": { + "context": 64000, + "output": 4096 + }, + "cost": { + "input": 0.03, + "output": 0.14, + "cache_read": 0.015, + "cache_write": 0.06 + } + }, + "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, + "limit": { + "context": 131072, + "output": 4096 + }, + "cost": { + "input": 0.04, + "output": 0.4, + "cache_read": 0.02, + "cache_write": 0.08 + } + }, + "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, + "limit": { + "context": 32768, + "output": 4096 + }, + "cost": { + "input": 0.55, + "output": 2.25, + "cache_read": 0.275, + "cache_write": 1.1 + } + }, + "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, + "limit": { + "context": 32768, + "output": 4096 + }, + "cost": { + "input": 0.39, + "output": 1.9, + "cache_read": 0.195, + "cache_write": 0.78 + } + } + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.287, + "output": 1.147, + "reasoning": 2.868 + } + }, + "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, + "limit": { + "context": 32768, + "output": 4096 + }, + "cost": { + "input": 0.115, + "output": 0.287 + } + }, + "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, + "limit": { + "context": 4096, + "output": 3072 + }, + "cost": { + "input": 0.144, + "output": 0.287 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.574, + "output": 2.411 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.087, + "output": 0.144 + } + }, + "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, + "limit": { + "context": 34096, + "output": 4096 + }, + "cost": { + "input": 0.717, + "output": 0.717 + } + }, + "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, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0.23, + "output": 0.918, + "input_audio": 3.584, + "output_audio": 7.168 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.072, + "output": 0.287, + "reasoning": 0.717 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.43, + "output": 2.58, + "reasoning": 2.58 + } + }, + "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, + "limit": { + "context": 4096, + "output": 3072 + }, + "cost": { + "input": 0.287, + "output": 0.861 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.23, + "output": 0.574 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.115, + "output": 0.287 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0.86, + "output": 3.15 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0.287, + "output": 0.861 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.287, + "output": 1.147, + "reasoning": 2.868 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.345, + "output": 1.377 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.115, + "output": 0.287, + "reasoning": 1.147 + } + }, + "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, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0.058, + "output": 0.23, + "input_audio": 3.584, + "output_audio": 7.168 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.022, + "output": 0.216 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.287, + "output": 0.717 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.574, + "output": 2.294 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.172, + "output": 1.72, + "reasoning": 1.72 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 0.625, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.2, + "cache_write": 2.5, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "cache_write": 2.5 + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.861, + "output": 3.441 + } + }, + "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, + "limit": { + "context": 202752, + "output": 128000 + }, + "cost": { + "input": 0.87, + "output": 3.48, + "cache_read": 0.17 + } + }, + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.058, + "output": 0.23, + "input_audio": 3.584, + "output_audio": 7.168 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.574, + "output": 1.721 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.574, + "output": 1.721 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.286705, + "output": 1.14682, + "reasoning": 2.867051 + } + }, + "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, + "limit": { + "context": 4096, + "output": 3072 + }, + "cost": { + "input": 0.574, + "output": 1.721 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.287, + "output": 0.861 + } + }, + "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, + "limit": { + "context": 53248, + "output": 4096 + }, + "cost": { + "input": 0.032, + "output": 0.032 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 7.742, + "output": 23.367 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.144, + "output": 1.434 + } + }, + "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, + "limit": { + "context": 16384, + "output": 8192 + }, + "cost": { + "input": 0.259, + "output": 0.775 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0.287, + "output": 0.861 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.23, + "output": 0.574 + } + }, + "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": true, - "cost": { "input": 0.6, "output": 2.2, "cache_read": 0.11, "cache_write": 0 }, - "limit": { "context": 131072, "output": 98304 } + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.144, + "output": 0.574 + } }, - "glm-4.7-flashx": { - "id": "glm-4.7-flashx", - "name": "GLM-4.7-FlashX", - "family": "glm-flash", + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0.072, + "output": 0.144 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.072, + "output": 0.144 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.144, + "output": 0.431 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1024 + }, + "cost": { + "input": 0.058, + "output": 0.144 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.287, + "output": 0.861 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.574, + "output": 2.294 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.287, + "output": 0.861 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.144, + "output": 0.574 + } + }, + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.23, + "output": 0.918, + "input_audio": 3.584, + "output_audio": 7.168 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.929, + "output": 3.858 + } + }, + "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": "2026-01-19", - "last_updated": "2026-01-19", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-04", + "last_updated": "2025-04", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.07, "output": 0.4, "cache_read": 0.01, "cache_write": 0 }, - "limit": { "context": 200000, "output": 131072 } + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.108, + "output": 0.431, + "reasoning": 1.076 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.143353, + "output": 1.433525, + "reasoning": 4.300576 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.287, + "output": 0.431 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.861, + "output": 3.441 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.216, + "output": 0.861 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.144, + "output": 0.287 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 16384 + }, + "cost": { + "input": 0.044, + "output": 0.087, + "reasoning": 0.431 + } + }, + "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, + "limit": { + "context": 16384, + "output": 8192 + }, + "cost": { + "input": 0.101, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 4096, + "output": 3072 + }, + "cost": { + "input": 0.574, + "output": 1.721 + } + }, + "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, + "limit": { + "context": 245800, + "output": 65536 + }, + "cost": { + "input": 1.32, + "output": 7.9, + "cache_read": 0.132 + } + }, + "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, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0.087, + "output": 0.345, + "input_audio": 5.448 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.573, + "output": 3.44, + "reasoning": 3.44 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0.144, + "output": 0.431 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 2.294, + "output": 6.881 + } + }, + "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, + "limit": { + "context": 65536, + "output": 8192 + }, + "cost": { + "input": 0.287, + "output": 1.147 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.574, + "output": 2.294 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 1.147, + "output": 4.588 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.574, + "output": 2.294 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.144, + "output": 0.574, + "reasoning": 1.434 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 10000000, + "output": 8192 + }, + "cost": { + "input": 0.072, + "output": 0.287 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 0.42 + } + }, + "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, + "limit": { + "context": 163840, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 2.18 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1, + "output": 5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } + } + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + } + } + }, + "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, + "limit": { + "context": 196608, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.125, + "output": 9 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 0.18, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 200000, + "output": 65536 + }, + "cost": { + "input": 4.5, + "output": 22.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.09, + "output": 0.36 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 18.9, + "output": 151.2 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.225, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.045, + "output": 0.36 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.8, + "output": 10.8 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 200000 + }, + "cost": { + "input": 0.135, + "output": 3.15 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 2.7, + "output": 13.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 1.125, + "output": 9 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 0.18, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.575, + "output": 12.6 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 200000 + }, + "cost": { + "input": 1.125, + "output": 9 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 0.09, + "output": 0.36 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 0.27, + "output": 2.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.225, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.18, + "output": 1.35 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.125, + "output": 9 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 0.18, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 1.1, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 2.7, + "output": 13.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.125, + "output": 9 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 13.5, + "output": 67.5 + } + }, + "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, + "limit": { + "context": 20000, + "output": 64000 + }, + "cost": { + "input": 0.9, + "output": 4.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 2.7, + "output": 13.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 10, + "output": 40 + } + }, + "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, + "limit": { + "context": 400000, + "output": 272000 + }, + "cost": { + "input": 13.5, + "output": 108 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 0.09, + "output": 0.36 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.125, + "output": 9 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 13.5, + "output": 67.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.125, + "output": 9 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 0.18, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.28, + "output": 1.14 + } + }, + "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, + "limit": { + "context": 163840, + "output": 32768 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 163840, + "output": 32768 + }, + "cost": { + "input": 0.7, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.07, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 40000 + }, + "cost": { + "input": 0.55, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 123000, + "output": 16000 + }, + "cost": { + "input": 0.42, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 123000, + "output": 12000 + }, + "cost": { + "input": 0.28, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 40960, + "output": 20000 + }, + "cost": { + "input": 0.1, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 3 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 40960, + "output": 20000 + }, + "cost": { + "input": 0.09, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.29, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 40960, + "output": 20000 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.57, + "output": 2.3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 0.57, + "output": 2.29 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 0.57, + "output": 2.29 + } + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } }, "glm-4.6": { "id": "glm-4.6", @@ -8968,2322 +33863,172 @@ "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-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.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.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.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 } - } - } - }, - "xai": { - "id": "xai", - "env": ["XAI_API_KEY"], - "npm": "@ai-sdk/xai", - "name": "xAI", - "doc": "https://docs.x.ai/docs/models", - "models": { - "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-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-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-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-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-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-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-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-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-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-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-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-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-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": { - "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-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-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 } + "knowledge": "2024-10", + "release_date": "2024-12-01", + "last_updated": "2025-11-13", + "modalities": { + "input": ["text"], + "output": ["text"] }, - "limit": { "context": 2000000, "output": 30000 } - }, - "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-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-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-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-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": 200000, + "output": 128000 }, - "limit": { "context": 2000000, "output": 30000 } - }, - "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 } + "input": 0, + "output": 0 + } + }, + "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"] }, - "limit": { "context": 2000000, "output": 30000 } + "open_weights": false, + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "grok-vision-beta": { - "id": "grok-vision-beta", - "name": "Grok Vision Beta", - "family": "grok-vision", - "attachment": true, + "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-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 } + "knowledge": "2024-12", + "release_date": "2025-01-01", + "last_updated": "2025-01-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "grok-4-1-fast": { - "id": "grok-4-1-fast", - "name": "Grok 4.1 Fast", - "family": "grok", - "attachment": true, + "qwen3-235b": { + "id": "qwen3-235b", + "name": "Qwen3-235B-A22B", + "family": "qwen", + "attachment": false, "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 } - } - } - }, - "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": { - "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.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/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-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.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/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/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/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/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/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/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 } - }, - "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-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.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/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-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-image-1.5": { - "id": "openai/gpt-image-1.5", - "name": "gpt-image-1.5", - "attachment": true, - "reasoning": false, - "tool_call": true, - "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-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/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/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/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-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/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/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/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 } - }, - "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/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-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/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-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-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-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-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-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/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.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-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-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.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-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-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 } - }, - "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-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/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/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/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 } - }, - "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/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/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/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/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/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 } - }, - "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-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-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-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-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.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-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 } - }, - "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-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 } - }, - "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.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 } - }, - "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": { - "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 } - }, - "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": { - "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-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.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.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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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/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/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/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/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-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/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/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.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/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/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-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/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-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-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 } - }, - "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 } - }, - "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 } - }, - "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/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-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/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 } - }, - "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 } - }, - "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", + "knowledge": "2024-10", + "release_date": "2024-12-01", + "last_updated": "2024-12-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "kimi-k2": { + "id": "kimi-k2", + "name": "Kimi-K2", "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 } - }, - "novita/kimi-k2.5": { - "id": "novita/kimi-k2.5", - "name": "kimi-k2.5", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": false, - "release_date": "2026-01-27", - "last_updated": "2026-01-27", - "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, - "open_weights": false, - "limit": { "context": 256000, "output": 262144 } - }, - "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/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, + "attachment": false, "reasoning": false, "tool_call": true, - "temperature": false, - "release_date": "2025-09-30", - "last_updated": "2025-09-30", - "modalities": { "input": ["text"], "output": ["text"] }, + "temperature": true, + "knowledge": "2024-10", + "release_date": "2024-12-01", + "last_updated": "2024-12-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "limit": { "context": 0, "output": 0 } + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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/glm-4.7": { - "id": "novita/glm-4.7", - "name": "glm-4.7", - "attachment": true, - "reasoning": true, + "qwen3-max-preview": { + "id": "qwen3-max-preview", + "name": "Qwen3-Max-Preview", + "family": "qwen", + "attachment": false, + "reasoning": false, "tool_call": true, "temperature": true, - "release_date": "2025-12-22", - "last_updated": "2025-12-22", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2024-12", + "release_date": "2025-01-01", + "last_updated": "2025-01-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "limit": { "context": 205000, "output": 131072 } + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "novita/deepseek-v3.2": { - "id": "novita/deepseek-v3.2", - "name": "DeepSeek-V3.2", - "attachment": true, - "reasoning": true, + "deepseek-v3": { + "id": "deepseek-v3", + "name": "DeepSeek-V3", + "family": "deepseek", + "attachment": false, + "reasoning": false, "tool_call": true, "temperature": true, - "release_date": "2025-12-01", - "last_updated": "2025-12-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2024-10", + "release_date": "2024-12-26", + "last_updated": "2024-12-26", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.27, "output": 0.4, "cache_read": 0.13 }, - "limit": { "context": 128000, "output": 0 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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, - "limit": { "context": 0, "output": 0 } - }, - "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 } - }, - "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 } - }, - "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, - "limit": { "context": 0, "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 } - }, - "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": { - "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 } - }, - "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": { - "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 } + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } } } }, @@ -11304,10 +34049,19 @@ "temperature": true, "release_date": "2025-06-09", "last_updated": "2025-06-09", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 15, "output": 75 }, - "limit": { "context": 512000, "output": 32000 } + "limit": { + "context": 512000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75 + } }, "v0-1.0-md": { "id": "v0-1.0-md", @@ -11319,10 +34073,19 @@ "temperature": true, "release_date": "2025-05-22", "last_updated": "2025-05-22", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 3, "output": 15 }, - "limit": { "context": 128000, "output": 32000 } + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 3, + "output": 15 + } }, "v0-1.5-md": { "id": "v0-1.5-md", @@ -11334,393 +34097,211 @@ "temperature": true, "release_date": "2025-06-09", "last_updated": "2025-06-09", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 3, "output": 15 }, - "limit": { "context": 128000, "output": 32000 } + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 3, + "output": 15 + } } } }, - "opencode": { - "id": "opencode", - "env": ["OPENCODE_API_KEY"], + "huggingface": { + "id": "huggingface", + "env": ["HF_TOKEN"], "npm": "@ai-sdk/openai-compatible", - "api": "https://opencode.ai/zen/v1", - "name": "OpenCode Zen", - "doc": "https://opencode.ai/docs/zen", + "api": "https://router.huggingface.co/v1", + "name": "Hugging Face", + "doc": "https://huggingface.co/docs/inference-providers", "models": { - "gpt-5.2-codex": { - "id": "gpt-5.2-codex", - "name": "GPT-5.2 Codex", - "family": "gpt-codex", + "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": 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" } - }, - "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" }, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, - "knowledge": "2024-12", - "release_date": "2025-12-16", - "last_updated": "2025-12-16", - "modalities": { "input": ["text"], "output": ["text"] }, + "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, "output": 0, "cache_read": 0 }, - "limit": { "context": 262144, "output": 65536 }, - "status": "deprecated" + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } }, - "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" } - }, - "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" } - }, - "big-pickle": { - "id": "big-pickle", - "name": "Big Pickle", - "family": "big-pickle", - "attachment": false, - "reasoning": true, - "tool_call": 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 }, - "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" } - }, - "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" - }, - "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" } - }, - "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" } - }, - "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" } - }, - "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 } - }, - "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 } - }, - "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" } - }, - "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 } - }, - "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" } - }, - "kimi-k2": { - "id": "kimi-k2", - "name": "Kimi K2", - "family": "kimi", + "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": "2024-10", - "release_date": "2025-09-05", - "last_updated": "2025-09-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-04", + "release_date": "2026-02-03", + "last_updated": "2026-02-03", + "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" + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 1.5 + } }, - "claude-opus-4-6": { - "id": "claude-opus-4-6", - "name": "Claude Opus 4.6", - "family": "claude-opus", - "attachment": true, - "reasoning": true, + "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-08-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": 1000000, "output": 128000 }, - "provider": { "npm": "@ai-sdk/anthropic" } + "knowledge": "2025-04", + "release_date": "2025-09-11", + "last_updated": "2025-09-11", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 66536 + }, + "cost": { + "input": 0.25, + "output": 1 + } }, - "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, + "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-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" } + "knowledge": "2024-12", + "release_date": "2025-01-01", + "last_updated": "2025-01-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32000, + "output": 4096 + }, + "cost": { + "input": 0.01, + "output": 0 + } }, - "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-07-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" } - }, - "grok-code": { - "id": "grok-code", - "name": "Grok Code Fast 1", - "family": "grok", - "attachment": true, + "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-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" + "knowledge": "2025-04", + "release_date": "2025-07-25", + "last_updated": "2025-07-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 3 + } }, - "gpt-5.4": { - "id": "gpt-5.4", - "name": "GPT-5.4", - "family": "gpt", - "attachment": true, - "reasoning": true, + "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, - "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 2 + } + }, + "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": "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-sdk/openai" } + "knowledge": "2024-12", + "release_date": "2025-01-01", + "last_updated": "2025-01-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32000, + "output": 2048 + }, + "cost": { + "input": 0.01, + "output": 0 + } }, - "qwen3-coder": { - "id": "qwen3-coder", - "name": "Qwen3 Coder", + "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, @@ -11729,1529 +34310,186 @@ "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" - }, - "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" - }, - "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" - }, - "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-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" } - }, - "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" - }, - "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" } - }, - "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 } + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 66536 }, - "limit": { "context": 1000000, "output": 64000 }, - "provider": { "npm": "@ai-sdk/anthropic" } - }, - "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" } - }, - "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" } - }, - "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" } + "output": 2 + } }, - "glm-5": { - "id": "glm-5", - "name": "GLM-5", + "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": "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 } - }, - "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, "output": 0, "cache_read": 0 }, - "limit": { "context": 400000, "input": 272000, "output": 128000 }, - "provider": { "npm": "@ai-sdk/openai" } - }, - "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": 1000000, "output": 128000 } - }, - "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 }, - "provider": { "npm": "@ai-sdk/anthropic" } - }, - "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" } - }, - "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" - }, - "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" - }, - "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 } + "interleaved": { + "field": "reasoning_content" }, - "limit": { "context": 1048576, "output": 65536 }, - "provider": { "npm": "@ai-sdk/google" } - }, - "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" } - }, - "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"] }, + "release_date": "2025-08-08", + "last_updated": "2025-08-08", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0, "cache_read": 0 }, - "limit": { "context": 204800, "output": 131072 }, - "status": "deprecated" - }, - "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" } - }, - "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" } - }, - "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" } - }, - "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 } - }, - "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" } - }, - "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 } - } - } - }, - "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": { - "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.3, "output": 0.9 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } }, "zai-org/GLM-4.7": { "id": "zai-org/GLM-4.7", - "name": "GLM 4.7", + "name": "GLM-4.7", "family": "glm", "attachment": false, "reasoning": true, "tool_call": true, - "structured_output": true, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, - "knowledge": "2025-12", - "release_date": "2026-01-19", - "last_updated": "2026-01-19", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-04", + "release_date": "2025-12-22", + "last_updated": "2025-12-22", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.7, "output": 2.3 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11 + } }, - "meta-llama/Llama-3.3-70B-Instruct": { - "id": "meta-llama/Llama-3.3-70B-Instruct", - "name": "Llama 3.3 70B Instruct", - "family": "llama", + "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, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, - "knowledge": "2023-12", - "release_date": "2025-04-27", - "last_updated": "2025-04-27", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-04-03", + "last_updated": "2026-04-03", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.9, "output": 0.9 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } }, - "intfloat/multilingual-e5-large-instruct": { - "id": "intfloat/multilingual-e5-large-instruct", - "name": "Multilingual-E5-large-instruct", - "family": "text-embedding", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": false, - "knowledge": "2025-04", - "release_date": "2025-04-27", - "last_updated": "2025-04-27", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.02, "output": 0 }, - "limit": { "context": 512, "output": 1024 } - }, - "intfloat/multilingual-e5-large": { - "id": "intfloat/multilingual-e5-large", - "name": "Multilingual-E5-large", - "family": "text-embedding", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": false, - "knowledge": "2025-09", - "release_date": "2025-09-11", - "last_updated": "2025-09-11", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.02, "output": 0 }, - "limit": { "context": 512, "output": 1024 } - }, - "KBLab/kb-whisper-large": { - "id": "KBLab/kb-whisper-large", - "name": "KB-Whisper-Large", - "family": "whisper", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": false, - "knowledge": "2025-04", - "release_date": "2025-04-27", - "last_updated": "2025-04-27", - "modalities": { "input": ["audio"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 3, "output": 3 }, - "limit": { "context": 480000, "output": 4800 } - }, - "BAAI/bge-reranker-v2-m3": { - "id": "BAAI/bge-reranker-v2-m3", - "name": "bge-reranker-v2-m3", - "family": "bge", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": false, - "knowledge": "2025-04", - "release_date": "2025-04-23", - "last_updated": "2025-04-23", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.1, "output": 0.1 }, - "limit": { "context": 512, "output": 512 } - }, - "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.3, "output": 0.3 }, - "limit": { "context": 32000, "output": 8192 } - } - } - }, - "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": { - "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 } - }, - "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 } - } - } - }, - "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-5": { - "id": "glm-5", + "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" }, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, "release_date": "2026-02-11", "last_updated": "2026-02-11", - "modalities": { "input": ["text"], "output": ["text"] }, + "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 } + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } }, - "glm-4.7": { - "id": "glm-4.7", - "name": "GLM-4.7", - "family": "glm", + "XiaomiMiMo/MiMo-V2-Flash": { + "id": "XiaomiMiMo/MiMo-V2-Flash", + "name": "MiMo-V2-Flash", + "family": "mimo", "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-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-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.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.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-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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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-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-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-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 } - }, - "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-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-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 } + "release_date": "2025-12-16", + "last_updated": "2025-12-16", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 4096 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } }, - "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.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/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-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/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/nemotron-3-super-120b-a12b": { - "id": "nvidia/nemotron-3-super-120b-a12b", - "name": "Nemotron 3 Super", - "family": "nemotron", + "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": "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/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/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/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 } - }, - "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.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/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 } - }, - "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/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 } - }, - "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 } - }, - "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/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-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 } - }, - "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/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/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-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-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-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 } - }, - "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 } - }, - "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 } - }, - "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-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.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-r1-0528": { - "id": "deepseek-ai/deepseek-r1-0528", - "name": "Deepseek R1 0528", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, + "knowledge": "2025-05", "release_date": "2025-05-28", "last_updated": "2025-05-28", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 3, + "output": 5 + } }, - "deepseek-ai/deepseek-v3.2": { - "id": "deepseek-ai/deepseek-v3.2", - "name": "DeepSeek V3.2", + "deepseek-ai/DeepSeek-V3.2": { + "id": "deepseek-ai/DeepSeek-V3.2", + "name": "DeepSeek-V3.2", "family": "deepseek", "attachment": false, "reasoning": true, @@ -13260,119 +34498,4675 @@ "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 } + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.28, + "output": 0.4 + } }, - "qwen/qwq-32b": { - "id": "qwen/qwq-32b", - "name": "Qwq 32b", + "moonshotai/Kimi-K2-Thinking": { + "id": "moonshotai/Kimi-K2-Thinking", + "name": "Kimi-K2-Thinking", + "family": "kimi-thinking", "attachment": false, "reasoning": true, - "tool_call": false, - "structured_output": false, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 393216 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.28, + "output": 0.42, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 163000, + "output": 64000 + }, + "cost": { + "input": 0.22, + "output": 0.33 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.28, + "output": 0.43 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.56, + "output": 2.24, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.56, + "output": 2.24, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 65536, + "output": 64000 + }, + "cost": { + "input": 0.21, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 256000, + "output": 80000 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 64000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 64000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 64000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 3, + "output": 9 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 3, + "output": 9 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16380 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 21, + "output": 168 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 400000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.17 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 0.75, + "output": 4.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 0.2, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.17 + } + }, + "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, + "limit": { + "context": 400000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 400000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 45, + "output": 225 + } + }, + "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, + "limit": { + "context": 400000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 3.75, + "output": 18.75 + } + }, + "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, + "limit": { + "context": 400000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12 + } + }, + "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, + "limit": { + "context": 400000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/openai", + "api": "https://zenmux.ai/api/v1" + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.726, + "output": 3.1946, + "cache_read": 0.1743 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.28, + "output": 1.14, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.58, + "output": 2.6, + "cache_read": 0.14 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.07, + "output": 0.42, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.8781, + "output": 3.5126, + "cache_read": 0.1903 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.02, + "output": 0.21, + "cache_read": 0.0043 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.35, + "output": 1.54, + "cache_read": 0.07 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.11, + "output": 0.56, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.88, + "output": 3.48 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.35, + "output": 1.54, + "cache_read": 0.07 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.14, + "output": 0.42, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0.9, + "output": 4.48 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.17, + "output": 1.12, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.03, + "output": 0.28, + "cache_read": 0.01, + "cache_write": 0.0024 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.09, + "output": 0.51, + "cache_read": 0.02, + "cache_write": 0.0024 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.11, + "output": 0.28, + "cache_read": 0.02, + "cache_write": 0.0024 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.45, + "output": 2.24, + "cache_read": 0.09, + "cache_write": 0.0024 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.84, + "output": 3.37 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131070 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 0.3055, + "output": 1.2219 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131070 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 0.611, + "output": 2.4439 + } + }, + "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, + "limit": { + "context": 204000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.38 + } + }, + "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, + "limit": { + "context": 204000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.38 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 0.6, + "output": 4.8, + "cache_read": 0.06, + "cache_write": 0.75 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1020000, + "output": 1020000 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 0.625, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.2, + "cache_write": 2.5, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "cache_write": 2.5 + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 1.2, + "output": 6 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0.8, + "output": 4.8 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 65530 + }, + "cost": { + "input": 0.25, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 1048000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "cache_write": 4.5 + } + }, + "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, + "limit": { + "context": 1048000, + "output": 64000 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 1048000, + "output": 64000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31, + "cache_write": 4.5 + } + }, + "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, + "limit": { + "context": 1048000, + "output": 64000 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.07, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 1048000, + "output": 64000 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.03, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.12, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.16, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 262000, + "output": 64000 + }, + "cost": { + "input": 0.58, + "output": 3.02, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 262000, + "output": 64000 + }, + "cost": { + "input": 1.15, + "output": 8, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262000, + "output": 64000 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262140, + "output": 262140 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 262000, + "output": 64000 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://zenmux.ai/api/anthropic/v1" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.172, + "output": 0.572, + "cache_read": 0.058, + "cache_write": 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-23", + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] + }, + "open_weights": false, + "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" + } + } + } + } + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "context_over_200k": { + "input": 60, + "output": 270 + }, + "tiers": [ + { + "input": 60, + "output": 270, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 265000, + "output": 265000 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08, + "context_over_200k": { + "input": 0.8, + "output": 4, + "cache_read": 0.16 + }, + "tiers": [ + { + "input": 0.8, + "output": 4, + "cache_read": 0.16, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1000000, + "output": 256000 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01 + } + } + } + }, + "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, + "limit": { + "context": 65536, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.25 + } + }, + "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, + "limit": { + "context": 32768, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.25 + } + } + } + }, + "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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 64000, + "output": 16000 + }, + "cost": { + "input": 0.7, + "output": 2.5 + } }, - "qwen/qwen2.5-coder-7b-instruct": { - "id": "qwen/qwen2.5-coder-7b-instruct", - "name": "Qwen2.5 Coder 7b Instruct", + "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": "2024-09-17", - "last_updated": "2024-09-17", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2024-07", + "release_date": "2025-03-25", + "last_updated": "2025-03-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.27, + "output": 1.12, + "cache_read": 0.135 + } }, - "qwen/qwen2.5-coder-32b-instruct": { - "id": "qwen/qwen2.5-coder-32b-instruct", - "name": "Qwen2.5 Coder 32b Instruct", + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.03, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.03, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 160000, + "output": 160000 + }, + "cost": { + "input": 0.7, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 0.06, + "output": 0.09 + } + }, + "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": false, + "tool_call": false, + "temperature": true, + "release_date": "2025-01-20", + "last_updated": "2025-01-20", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 64000, + "output": 32000 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 0.41 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.27, + "output": 1, + "cache_read": 0.135 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.269, + "output": 0.4, + "cache_read": 0.1345 + } + }, + "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, + "limit": { + "context": 64000, + "output": 16000 + }, + "cost": { + "input": 0.4, + "output": 1.3 + } + }, + "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": false, + "tool_call": false, + "temperature": true, + "release_date": "2025-01-20", + "last_updated": "2025-01-20", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 163840, + "output": 32768 + }, + "cost": { + "input": 0.7, + "output": 2.5, + "cache_read": 0.35 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.27, + "output": 1, + "cache_read": 0.135 + } + }, + "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": "2024-11-06", - "last_updated": "2024-11-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "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": 128000, "output": 4096 } + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "qwen/qwen3-coder-480b-a35b-instruct": { - "id": "qwen/qwen3-coder-480b-a35b-instruct", - "name": "Qwen3 Coder 480B A35B Instruct", - "family": "qwen", + "inclusionai/ling-2.6-flash": { + "id": "inclusionai/ling-2.6-flash", + "name": "Ling-2.6-flash", + "family": "ling", "attachment": false, "reasoning": false, "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-24", + "last_updated": "2026-04-24", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.02 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.14, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 202800, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11 + } + }, + "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-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 } + "release_date": "2025-10-13", + "last_updated": "2025-10-13", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.13, + "output": 0.85 + } }, - "qwen/qwen3-next-80b-a3b-thinking": { - "id": "qwen/qwen3-next-80b-a3b-thinking", - "name": "Qwen3-Next-80B-A3B-Thinking", - "family": "qwen", + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 1.8, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.55, + "output": 2.2, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.9, + "cache_read": 0.055 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.07, + "output": 0.4, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.035, + "output": 0.138 + } + }, + "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, + "limit": { + "context": 60288, + "output": 16000 + }, + "cost": { + "input": 0.04, + "output": 0.17 + } + }, + "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": "2024-12-01", - "last_updated": "2025-09-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-08-13", + "last_updated": "2025-08-13", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 262144, "output": 16384 } + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.07, + "output": 0.07 + } }, - "qwen/qwen3-next-80b-a3b-instruct": { - "id": "qwen/qwen3-next-80b-a3b-instruct", - "name": "Qwen3-Next-80B-A3B-Instruct", - "family": "qwen", + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.18, + "output": 0.59 + } + }, + "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-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 } + "knowledge": "2023-12", + "release_date": "2024-12-07", + "last_updated": "2024-12-07", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 120000 + }, + "cost": { + "input": 0.135, + "output": 0.4 + } }, - "qwen/qwen3-235b-a22b": { - "id": "qwen/qwen3-235b-a22b", - "name": "Qwen3-235B-A22B", - "family": "qwen", + "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, + "temperature": true, + "release_date": "2024-09-18", + "last_updated": "2024-09-18", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 32000 + }, + "cost": { + "input": 0.03, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.04, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8000 + }, + "cost": { + "input": 0.51, + "output": 0.74 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.27, + "output": 0.85 + } + }, + "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, + "limit": { + "context": 4096, + "output": 3200 + }, + "cost": { + "input": 0.09, + "output": 0.09 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 1.48, + "output": 1.48 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 1.48, + "output": 1.48 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.05, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 65535, + "output": 8000 + }, + "cost": { + "input": 0.62, + "output": 0.62 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.04, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 40000 + }, + "cost": { + "input": 0.55, + "output": 2.2 + } + }, + "Sao10K/L3-8B-Stheno-v3.2": { + "id": "Sao10K/L3-8B-Stheno-v3.2", + "name": "L3 8B Stheno V3.2", + "family": "llama", + "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, + "limit": { + "context": 8192, + "output": 32000 + }, + "cost": { + "input": 0.05, + "output": 0.05 + } + }, + "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": "2024-12-01", - "last_updated": "2025-09-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-12-19", + "last_updated": "2025-12-19", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 32000 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.39, + "output": 0.39 + } + }, + "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, + "limit": { + "context": 123000, + "output": 16000 + }, + "cost": { + "input": 0.42, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 120000, + "output": 8000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 123000, + "output": 12000 + }, + "cost": { + "input": 0.28, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 30000, + "output": 8000 + }, + "cost": { + "input": 1.4, + "output": 5.6 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, "output": 0 }, - "limit": { "context": 131072, "output": 8192 } + "limit": { + "context": 204800, + "output": 131100 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131100 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.07, + "output": 0.07 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.09, + "output": 0.58 + } + }, + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.25, + "output": 0.97, + "input_audio": 2.2, + "output_audio": 1.788 + } }, "qwen/qwen3.5-397b-a17b": { "id": "qwen/qwen3.5-397b-a17b", @@ -13383,47 +39177,676 @@ "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"] }, + "release_date": "2026-02-17", + "last_updated": "2026-02-17", + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 262144, "output": 8192 } + "limit": { + "context": 262144, + "output": 64000 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } }, - "black-forest-labs/flux.1-dev": { - "id": "black-forest-labs/flux.1-dev", - "name": "FLUX.1-dev", - "family": "flux", + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.8, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.98, + "output": 3.95 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 1 + } + }, + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.25, + "output": 0.97, + "input_audio": 2.2, + "output_audio": 1.788 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.08, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 2.11, + "output": 8.45 + } + }, + "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, + "limit": { + "context": 40960, + "output": 20000 + }, + "cost": { + "input": 0.1, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 128000, + "output": 20000 + }, + "cost": { + "input": 0.03, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 1.5 + } + }, + "qwen/qwen-mt-plus": { + "id": "qwen/qwen-mt-plus", + "name": "Qwen MT Plus", "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 } + "release_date": "2025-09-03", + "last_updated": "2025-09-03", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 16384, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.75 + } }, - "moonshotai/kimi-k2-thinking": { - "id": "moonshotai/kimi-k2-thinking", - "name": "Kimi K2 Thinking", - "family": "kimi-thinking", + "qwen/qwen3-next-80b-a3b-instruct": { + "id": "qwen/qwen3-next-80b-a3b-instruct", + "name": "Qwen3 Next 80B A3B Instruct", "attachment": false, - "reasoning": true, + "reasoning": false, "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"] }, + "release_date": "2025-09-10", + "last_updated": "2025-09-10", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 262144, "output": 262144 } + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 40960, + "output": 20000 + }, + "cost": { + "input": 0.09, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 1.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 160000, + "output": 32768 + }, + "cost": { + "input": 0.07, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 40960, + "output": 20000 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 128000, + "output": 20000 + }, + "cost": { + "input": 0.035, + "output": 0.138 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 32000, + "output": 8192 + }, + "cost": { + "input": 0.38, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "release_date": "2026-04-02", + "last_updated": "2026-04-02", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.14, + "output": 0.4 + } + }, + "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, + "release_date": "2025-03-13", + "last_updated": "2025-03-13", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.05, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 98304, + "output": 16384 + }, + "cost": { + "input": 0.119, + "output": 0.2 + } + }, + "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, + "release_date": "2026-04-02", + "last_updated": "2026-04-02", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.13, + "output": 0.4 + } }, "moonshotai/kimi-k2.5": { "id": "moonshotai/kimi-k2.5", @@ -13432,876 +39855,1124 @@ "attachment": true, "reasoning": true, "tool_call": true, - "interleaved": { "field": "reasoning_content" }, + "interleaved": { + "field": "reasoning_content" + }, + "structured_output": true, "temperature": true, - "knowledge": "2025-07", + "knowledge": "2025-01", "release_date": "2026-01-27", "last_updated": "2026-01-27", - "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 262144, "output": 262144 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } }, - "moonshotai/kimi-k2-instruct-0905": { - "id": "moonshotai/kimi-k2-instruct-0905", + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.57, + "output": 2.3 + } + }, + "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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 262144, "output": 262144 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5 + } }, - "moonshotai/kimi-k2-instruct": { - "id": "moonshotai/kimi-k2-instruct", - "name": "Kimi K2 Instruct", + "moonshotai/kimi-k2-thinking": { + "id": "moonshotai/kimi-k2-thinking", + "name": "Kimi K2 Thinking", "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 } - }, - "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.3-70b-instruct": { - "id": "meta/llama-3.3-70b-instruct", - "name": "Llama 3.3 70b Instruct", - "attachment": false, - "reasoning": false, - "tool_call": true, + "interleaved": { + "field": "reasoning_content" + }, "structured_output": true, "temperature": true, - "release_date": "2024-11-26", - "last_updated": "2024-11-26", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-11-07", + "last_updated": "2025-11-07", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5 + } }, - "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-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 } - }, - "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/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.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/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/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-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 } - }, - "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/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/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 } - }, - "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/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/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-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 } - } - } - }, - "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": { - "openai/gpt-oss-120b": { - "id": "openai/gpt-oss-120b", - "name": "gpt-oss-120b", + "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-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 } - }, - "openai/gpt-oss-20b": { - "id": "openai/gpt-oss-20b", - "name": "gpt-oss-20b", - "attachment": false, - "reasoning": false, - "tool_call": true, - "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.05, "output": 0.2, "cache_read": 0.005, "cache_write": 0.06 }, - "limit": { "context": 128000, "input": 124000, "output": 4096 } - }, - "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 } - }, - "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 } - }, - "zai-org/GLM-4.5-Air": { - "id": "zai-org/GLM-4.5-Air", - "name": "GLM-4.5-Air", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2025-06", - "release_date": "2025-11-15", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.2, "output": 1.2, "cache_read": 0.02, "cache_write": 0.25 }, - "limit": { "context": 128000, "input": 124000, "output": 4096 } - }, - "zai-org/GLM-4.5": { - "id": "zai-org/GLM-4.5", - "name": "GLM-4.5", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2025-06", - "release_date": "2025-11-15", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.6, "output": 2.2, "cache_read": 0.06, "cache_write": 0.75 }, - "limit": { "context": 128000, "input": 124000, "output": 4096 } - }, - "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 } - }, - "zai-org/GLM-4.7-FP8": { - "id": "zai-org/GLM-4.7-FP8", - "name": "GLM-4.7 (FP8)", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2025-12", - "release_date": "2026-01-15", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.4, "output": 2, "cache_read": 0.04, "cache_write": 0.5 }, - "limit": { "context": 128000, "input": 124000, "output": 4096 } - }, - "nvidia/Nemotron-Nano-V2-12b": { - "id": "nvidia/Nemotron-Nano-V2-12b", - "name": "Nemotron-Nano-V2-12b", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2025-01", - "release_date": "2025-03-15", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.07, "output": 0.2, "cache_read": 0.007, "cache_write": 0.08 }, - "limit": { "context": 32000, "input": 30000, "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, + "interleaved": { + "field": "reasoning_content" + }, "structured_output": true, "temperature": true, "knowledge": "2025-05", - "release_date": "2025-08-10", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-04-24", + "last_updated": "2026-04-24", + "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 } + "limit": { + "context": 1048576, + "output": 393216 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } }, - "nvidia/nemotron-3-super-120b-a12b": { - "id": "nvidia/nemotron-3-super-120b-a12b", - "name": "Nemotron-3-Super-120B-A12B", + "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, + "limit": { + "context": 1048576, + "output": 393216 + }, + "cost": { + "input": 1.69, + "output": 3.38, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + } + } + }, + "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, + "limit": { + "context": 8192, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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": "2026-02", - "release_date": "2026-03-11", + "knowledge": "2025-04", + "release_date": "2025-07-25", "last_updated": "2026-03-12", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.3, "output": 0.9 }, - "limit": { "context": 256000, "input": 256000, "output": 32768 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } }, - "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", + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 1, + "output": 3.2 + } + }, + "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-15", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-01-31", + "last_updated": "2026-03-12", + "modalities": { + "input": ["text", "image"], + "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 } - }, - "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 } - }, - "google/gemma-3-27b-it-fast": { - "id": "google/gemma-3-27b-it-fast", - "name": "Gemma-3-27b-it (Fast)", - "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.2, "output": 0.6, "cache_read": 0.02, "cache_write": 0.25 }, - "limit": { "context": 110000, "input": 100000, "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-2-9b-it-fast": { - "id": "google/gemma-2-9b-it-fast", - "name": "Gemma-2-9b-it (Fast)", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "knowledge": "2024-06", - "release_date": "2024-06-27", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.03, "output": 0.09, "cache_read": 0.003, "cache_write": 0.0375 }, - "limit": { "context": 8192, "input": 8000, "output": 4096 } - }, - "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 } - }, - "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, - "structured_output": true, - "temperature": false, - "knowledge": "2024-04", - "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, "cache_read": 0.002, "cache_write": 0.025 }, - "limit": { "context": 8192, "input": 8000, "output": 1024 } + "limit": { + "context": 64000, + "output": 64000 + }, + "cost": { + "input": 0.17, + "output": 0.66 + } }, "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 } - }, - "meta-llama/Meta-Llama-3.1-8B-Instruct-fast": { - "id": "meta-llama/Meta-Llama-3.1-8B-Instruct-fast", - "name": "Meta-Llama-3.1-8B-Instruct (Fast)", - "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.03, "output": 0.09, "cache_read": 0.003, "cache_write": 0.03 }, - "limit": { "context": 128000, "input": 120000, "output": 4096 } - }, - "meta-llama/Llama-3.3-70B-Instruct-fast": { - "id": "meta-llama/Llama-3.3-70B-Instruct-fast", - "name": "Llama-3.3-70B-Instruct (Fast)", - "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.25, "output": 0.75, "cache_read": 0.025, "cache_write": 0.31 }, - "limit": { "context": 128000, "input": 120000, "output": 8192 } - }, - "MiniMaxAI/MiniMax-M2.1": { - "id": "MiniMaxAI/MiniMax-M2.1", - "name": "MiniMax-M2.1", + "family": "llama", "attachment": false, "reasoning": true, "tool_call": true, - "interleaved": { "field": "reasoning_content" }, "structured_output": true, "temperature": true, - "knowledge": "2025-10", - "release_date": "2026-02-01", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2023-12", + "release_date": "2024-12-06", + "last_updated": "2026-03-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.3, "output": 1.2, "reasoning": 1.2, "cache_read": 0.03, "cache_write": 0.375 }, - "limit": { "context": 128000, "input": 120000, "output": 8192 } + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.71, + "output": 0.71 + } }, - "deepseek-ai/DeepSeek-V3-0324": { - "id": "deepseek-ai/DeepSeek-V3-0324", - "name": "DeepSeek-V3-0324", + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.22, + "output": 0.22 + } + }, + "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, - "knowledge": "2024-12", - "release_date": "2025-03-24", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2024-07-23", + "last_updated": "2026-03-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.5, "output": 1.5, "cache_read": 0.05, "cache_write": 0.1875 }, - "limit": { "context": 128000, "input": 120000, "output": 8192 } + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.8, + "output": 0.8 + } }, - "deepseek-ai/DeepSeek-R1-0528-fast": { - "id": "deepseek-ai/DeepSeek-R1-0528-fast", - "name": "DeepSeek R1 0528 Fast", + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.22 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.08, + "output": 0.35 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "deepseek-ai/DeepSeek-V3.1": { + "id": "deepseek-ai/DeepSeek-V3.1", + "name": "DeepSeek V3.1", "family": "deepseek", "attachment": false, - "reasoning": true, + "reasoning": false, "tool_call": true, + "structured_output": true, "temperature": true, - "knowledge": "2025-01", - "release_date": "2025-01-01", - "last_updated": "2025-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-08-21", + "last_updated": "2026-03-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 2, "output": 6 }, - "limit": { "context": 131072, "output": 8192 } + "limit": { + "context": 161000, + "output": 161000 + }, + "cost": { + "input": 0.55, + "output": 1.65 + } }, - "deepseek-ai/DeepSeek-V3-0324-fast": { - "id": "deepseek-ai/DeepSeek-V3-0324-fast", - "name": "DeepSeek-V3-0324 (Fast)", + "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, - "knowledge": "2024-12", - "release_date": "2025-03-24", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.75, "output": 2.25, "cache_read": 0.075, "cache_write": 0.28125 }, - "limit": { "context": 128000, "input": 120000, "output": 8192 } + "release_date": "2025-08-05", + "last_updated": "2026-03-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.05, + "output": 0.2 + } }, - "deepseek-ai/DeepSeek-R1-0528": { - "id": "deepseek-ai/DeepSeek-R1-0528", - "name": "DeepSeek-R1-0528", + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.5, + "output": 2.85 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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" }, + "interleaved": { + "field": "reasoning_content" + }, "structured_output": true, "temperature": true, - "knowledge": "2025-11", - "release_date": "2026-01-15", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-03-27", + "last_updated": "2026-03-27", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26, + "cache_write": 0 + } + } + } + }, + "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": { + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.8, "output": 2.4, "reasoning": 2.4, "cache_read": 0.08, "cache_write": 1 }, - "limit": { "context": 128000, "input": 120000, "output": 32768 } + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.0245, + "output": 0.0978, + "cache_read": 0.01225 + } }, - "deepseek-ai/DeepSeek-V3.2": { - "id": "deepseek-ai/DeepSeek-V3.2", - "name": "DeepSeek-V3.2", + "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" }, + "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"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "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 } + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0.0136, + "output": 0.0543, + "cache_read": 0.0068 + } }, - "intfloat/e5-mistral-7b-instruct": { - "id": "intfloat/e5-mistral-7b-instruct", - "name": "e5-mistral-7b-instruct", - "family": "text-embedding", + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0.06, + "output": 0.22, + "cache_read": 0.03 + } + }, + "Qwen/Qwen3-32B-TEE": { + "id": "Qwen/Qwen3-32B-TEE", + "name": "Qwen3 32B TEE", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-25", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0.08, + "output": 0.24, + "cache_read": 0.04 + } + }, + "Qwen/Qwen3.6-27B-TEE": { + "id": "Qwen/Qwen3.6-27B-TEE", + "name": "Qwen3.6 27B TEE", + "family": "qwen", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-25", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.195, + "output": 1.56, + "cache_read": 0.0975 + } + }, + "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": false, - "temperature": false, - "knowledge": "2023-12", - "release_date": "2024-01-01", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "structured_output": true, + "temperature": true, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.01, "output": 0 }, - "limit": { "context": 32768, "input": 32768, "output": 0 } + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.0272, + "output": 0.1087, + "cache_read": 0.0136 + } }, - "black-forest-labs/flux-dev": { - "id": "black-forest-labs/flux-dev", - "name": "FLUX.1-dev", + "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": false, - "knowledge": "2024-07", - "release_date": "2024-08-01", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["image"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 77, "input": 77, "output": 0 } - }, - "black-forest-labs/flux-schnell": { - "id": "black-forest-labs/flux-schnell", - "name": "FLUX.1-schnell", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": false, - "knowledge": "2024-07", - "release_date": "2024-08-01", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["image"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 77, "input": 77, "output": 0 } - }, - "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"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "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 } + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0.01, + "output": 0.0109, + "cache_read": 0.005 + } }, - "Qwen/Qwen3-30B-A3B-Thinking-2507": { - "id": "Qwen/Qwen3-30B-A3B-Thinking-2507", - "name": "Qwen3-30B-A3B-Thinking-2507", - "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.1, "output": 0.3, "reasoning": 0.3, "cache_read": 0.01, "cache_write": 0.125 }, - "limit": { "context": 128000, "input": 120000, "output": 16384 } - }, - "Qwen/Qwen3-32B": { - "id": "Qwen/Qwen3-32B", - "name": "Qwen3-32B", + "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-12", - "release_date": "2026-01-28", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "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 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.1, + "output": 0.8, + "cache_read": 0.05 + } + }, + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.6, + "cache_read": 0.05 + } + }, + "Qwen/Qwen3-Coder-Next-TEE": { + "id": "Qwen/Qwen3-Coder-Next-TEE", + "name": "Qwen3 Coder Next TEE", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-25", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.12, + "output": 0.75, + "cache_read": 0.06 + } }, "Qwen/Qwen3-235B-A22B-Thinking-2507": { "id": "Qwen/Qwen3-235B-A22B-Thinking-2507", @@ -14310,339 +40981,915 @@ "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.8 }, - "limit": { "context": 262144, "output": 8192 } - }, - "Qwen/Qwen2.5-Coder-7B-fast": { - "id": "Qwen/Qwen2.5-Coder-7B-fast", - "name": "Qwen2.5-Coder-7B (Fast)", - "attachment": false, - "reasoning": false, - "tool_call": true, + "interleaved": { + "field": "reasoning_content" + }, "structured_output": true, "temperature": true, - "knowledge": "2024-09", - "release_date": "2024-09-19", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.03, "output": 0.09, "cache_read": 0.003, "cache_write": 0.03 }, - "limit": { "context": 128000, "input": 120000, "output": 8192 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.11, + "output": 0.6, + "cache_read": 0.055 + } }, - "Qwen/Qwen2.5-VL-72B-Instruct": { - "id": "Qwen/Qwen2.5-VL-72B-Instruct", - "name": "Qwen2.5-VL-72B-Instruct", + "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, + "tool_call": false, "structured_output": true, "temperature": true, - "knowledge": "2024-12", - "release_date": "2025-01-20", - "last_updated": "2026-02-04", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "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 } + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.0543, + "output": 0.2174, + "cache_read": 0.02715 + } }, - "Qwen/Qwen3-32B-fast": { - "id": "Qwen/Qwen3-32B-fast", - "name": "Qwen3-32B (Fast)", - "attachment": false, - "reasoning": false, + "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, - "knowledge": "2025-12", - "release_date": "2026-01-28", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-02-18", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.2, "output": 0.6, "cache_read": 0.02, "cache_write": 0.25 }, - "limit": { "context": 128000, "input": 120000, "output": 8192 } + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.39, + "output": 2.34, + "cache_read": 0.195 + } }, - "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, - "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-Coder-480B-A35B-Instruct": { - "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct", - "name": "Qwen3 Coder 480B A35B Instruct", + "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, - "temperature": true, - "knowledge": "2025-04", - "release_date": "2025-07-23", - "last_updated": "2025-10-04", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.4, "output": 1.8 }, - "limit": { "context": 262144, "output": 66536 } - }, - "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"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "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 } + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.2989, + "output": 1.1957, + "cache_read": 0.14945 + } }, - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", - "name": "Qwen3 235B A22B Instruct 2507", - "family": "qwen", + "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, - "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-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"] }, + "release_date": "2026-04-08", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.01, "output": 0 }, - "limit": { "context": 32768, "input": 32768, "output": 0 } + "limit": { + "context": 202752, + "output": 65535 + }, + "cost": { + "input": 1.05, + "output": 3.5, + "cache_read": 0.525 + } }, - "BAAI/bge-en-icl": { - "id": "BAAI/bge-en-icl", - "name": "BGE-ICL", - "family": "text-embedding", + "zai-org/GLM-4.7-FP8": { + "id": "zai-org/GLM-4.7-FP8", + "name": "GLM 4.7 FP8", + "family": "glm", "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": false, - "knowledge": "2024-06", - "release_date": "2024-07-30", - "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 } - }, - "BAAI/bge-multilingual-gemma2": { - "id": "BAAI/bge-multilingual-gemma2", - "name": "bge-multilingual-gemma2", - "family": "text-embedding", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": false, - "knowledge": "2024-06", - "release_date": "2024-07-30", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.01, "output": 0 }, - "limit": { "context": 8192, "input": 8192, "output": 0 } - }, - "moonshotai/Kimi-K2-Instruct": { - "id": "moonshotai/Kimi-K2-Instruct", - "name": "Kimi-K2-Instruct", - "attachment": true, - "reasoning": false, + "reasoning": true, "tool_call": true, "structured_output": true, "temperature": true, - "knowledge": "2025-10", - "release_date": "2026-01-05", - "last_updated": "2026-02-04", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.5, "output": 2.4, "cache_read": 0.05, "cache_write": 0.625 }, - "limit": { "context": 200000, "input": 190000, "output": 8192 } + "release_date": "2026-01-27", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 202752, + "output": 65535 + }, + "cost": { + "input": 0.2989, + "output": 1.1957, + "cache_read": 0.14945 + } }, - "moonshotai/Kimi-K2.5": { - "id": "moonshotai/Kimi-K2.5", - "name": "Kimi-K2.5", - "family": "kimi", + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 202752, + "output": 65535 + }, + "cost": { + "input": 0.95, + "output": 2.55, + "cache_read": 0.475 + } + }, + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 202752, + "output": 65535 + }, + "cost": { + "input": 0.39, + "output": 1.75, + "cache_read": 0.195 + } + }, + "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" }, + "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"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "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 } + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 0.9, + "cache_read": 0.15 + } }, - "moonshotai/Kimi-K2.5-fast": { - "id": "moonshotai/Kimi-K2.5-fast", - "name": "Kimi-K2.5-fast", - "family": "kimi", - "attachment": true, + "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" }, + "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"] }, + "release_date": "2026-03-11", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "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 } + "limit": { + "context": 202752, + "output": 65535 + }, + "cost": { + "input": 0.4891, + "output": 1.9565, + "cache_read": 0.24455 + } }, - "moonshotai/Kimi-K2-Thinking": { - "id": "moonshotai/Kimi-K2-Thinking", - "name": "Kimi-K2-Thinking", - "attachment": true, + "XiaomiMiMo/MiMo-V2-Flash-TEE": { + "id": "XiaomiMiMo/MiMo-V2-Flash-TEE", + "name": "MiMo V2 Flash TEE", + "family": "mimo", + "attachment": false, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-25", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.09, + "output": 0.29, + "cache_read": 0.045 + } + }, + "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" }, + "interleaved": { + "field": "reasoning_content" + }, "structured_output": true, "temperature": true, - "knowledge": "2025-10", - "release_date": "2026-01-05", - "last_updated": "2026-02-04", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.6, "output": 2.5, "reasoning": 2.5, "cache_read": 0.06, "cache_write": 0.75 }, - "limit": { "context": 128000, "input": 120000, "output": 16384 } - } - } - }, - "togetherai": { - "id": "togetherai", - "env": ["TOGETHER_API_KEY"], - "npm": "@ai-sdk/togetherai", - "name": "Together AI", - "doc": "https://docs.together.ai/docs/serverless-models", - "models": { - "openai/gpt-oss-120b": { - "id": "openai/gpt-oss-120b", - "name": "GPT OSS 120B", + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.0272, + "output": 0.1087, + "cache_read": 0.0136 + } + }, + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 1, + "cache_read": 0.135 + } + }, + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1, + "cache_read": 0.125 + } + }, + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.45, + "output": 2.15, + "cache_read": 0.225 + } + }, + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.28, + "output": 0.42, + "cache_read": 0.14 + } + }, + "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, - "knowledge": "2025-08", - "release_date": "2025-08-05", - "last_updated": "2025-08-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 0.6 }, - "limit": { "context": 131072, "output": 131072 } + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.09, + "output": 0.36, + "cache_read": 0.045 + } }, - "zai-org/GLM-4.7": { - "id": "zai-org/GLM-4.7", + "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, + "temperature": true, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.03, + "output": 0.1, + "cache_read": 0.015 + } + }, + "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, + "temperature": true, + "release_date": "2025-02-12", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.01, + "output": 0.0136, + "cache_read": 0.005 + } + }, + "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": true, + "temperature": true, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 96000, + "output": 96000 + }, + "cost": { + "input": 0.01, + "output": 0.0272, + "cache_read": 0.005 + } + }, + "unsloth/Llama-3.2-1B-Instruct": { + "id": "unsloth/Llama-3.2-1B-Instruct", + "name": "Llama 3.2 1B Instruct", + "family": "unsloth", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2026-01-27", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 16384, + "output": 8192 + }, + "cost": { + "input": 0.01, + "output": 0.0109, + "cache_read": 0.005 + } + }, + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.02, + "output": 0.04, + "cache_read": 0.01 + } + }, + "unsloth/gemma-3-27b-it": { + "id": "unsloth/gemma-3-27b-it", + "name": "gemma 3 27b it", + "family": "unsloth", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 65536 + }, + "cost": { + "input": 0.0272, + "output": 0.1087, + "cache_read": 0.0136 + } + }, + "google/gemma-4-31B-turbo-TEE": { + "id": "google/gemma-4-31B-turbo-TEE", + "name": "gemma 4 31B turbo TEE", + "family": "gemma", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-25", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.13, + "output": 0.38, + "cache_read": 0.065 + } + }, + "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-25", + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65535 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.475 + } + }, + "moonshotai/Kimi-K2.5-TEE": { + "id": "moonshotai/Kimi-K2.5-TEE", + "name": "Kimi K2.5 TEE", + "family": "kimi", + "attachment": true, + "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-04-25", + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65535 + }, + "cost": { + "input": 0.44, + "output": 2, + "cache_read": 0.22 + } + }, + "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-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 196608, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 1.2, + "cache_read": 0.075 + } + }, + "rednote-hilab/dots.ocr": { + "id": "rednote-hilab/dots.ocr", + "name": "dots.ocr", + "family": "rednote", + "attachment": true, + "reasoning": false, + "tool_call": false, + "structured_output": true, + "temperature": true, + "release_date": "2025-12-29", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.01, + "output": 0.0109, + "cache_read": 0.005 + } + }, + "tngtech/DeepSeek-TNG-R1T2-Chimera-TEE": { + "id": "tngtech/DeepSeek-TNG-R1T2-Chimera-TEE", + "name": "DeepSeek TNG R1T2 Chimera TEE", + "family": "deepseek", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-25", + "last_updated": "2026-04-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.3, + "output": 1.1, + "cache_read": 0.15 + } + } + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.0675, + "output": 0.27 + } + }, + "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-07", - "release_date": "2025-07-25", - "last_updated": "2025-07-25", - "modalities": { "input": ["text"], "output": ["text"] }, + "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 }, - "limit": { "context": 200000, "output": 200000 } + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.45, + "output": 1.65 + } }, - "zai-org/GLM-5": { - "id": "zai-org/GLM-5", + "glm-5": { + "id": "glm-5", "name": "GLM-5", "family": "glm", "attachment": false, "reasoning": true, "tool_call": true, - "structured_output": true, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, - "knowledge": "2025-11", "release_date": "2026-02-11", "last_updated": "2026-02-11", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 1, "output": 3.2 }, - "limit": { "context": 202752, "output": 131072 } + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 2.4 + } }, - "zai-org/GLM-4.6": { - "id": "zai-org/GLM-4.6", - "name": "GLM 4.6", + "glm-5.1": { + "id": "glm-5.1", + "name": "GLM-5.1", "family": "glm", "attachment": false, - "reasoning": false, + "reasoning": true, "tool_call": true, + "interleaved": { + "field": "reasoning_content" + }, + "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 }, - "limit": { "context": 200000, "output": 200000 } + "release_date": "2026-03-27", + "last_updated": "2026-03-27", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 3.89 + } }, - "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 } - }, - "MiniMaxAI/MiniMax-M2.5": { - "id": "MiniMaxAI/MiniMax-M2.5", + "minimax-m2.5": { + "id": "minimax-m2.5", "name": "MiniMax-M2.5", "family": "minimax", "attachment": false, @@ -14651,1029 +41898,56 @@ "temperature": true, "release_date": "2026-02-12", "last_updated": "2026-02-12", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.3, "output": 1.2, "cache_read": 0.06 }, - "limit": { "context": 204800, "output": 131072 } - }, - "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 } - }, - "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-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 } - }, - "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.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-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-07", - "release_date": "2025-07-25", - "last_updated": "2025-07-25", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.15, "output": 1.5 }, - "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 } - }, - "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": 131072 } - }, - "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 } + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 0.22, + "output": 0.88 + } } } }, - "firmware": { - "id": "firmware", - "env": ["FIRMWARE_API_KEY"], - "npm": "@ai-sdk/openai-compatible", - "api": "https://app.frogbot.ai/api/v1", - "name": "Firmware", - "doc": "https://docs.frogbot.ai", + "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": { - "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 } - }, - "kimi-k2.5": { - "id": "kimi-k2.5", - "name": "Kimi-K2.5", + "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": 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 } - }, - "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 }, - "limit": { "context": 1000000, "output": 64000 } - }, - "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 } - }, - "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 } - }, - "zai-glm-5": { - "id": "zai-glm-5", - "name": "GLM-5", - "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": false, - "cost": { "input": 1, "output": 3.2, "cache_read": 0.2 }, - "limit": { "context": 198000, "output": 8192 } - }, - "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.03 }, - "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-v3-2": { - "id": "deepseek-v3-2", - "name": "DeepSeek v3.2", - "family": "deepseek", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-07", - "release_date": "2024-12-26", - "last_updated": "2025-09-29", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.58, "output": 1.68, "cache_read": 0.28 }, - "limit": { "context": 128000, "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": "2026-02-17", - "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 } - }, - "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 } - }, - "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 } - }, - "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": { - "id": "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": 272000, "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", "video", "audio", "pdf"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.5, "output": 3, "cache_read": 0.05 }, - "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": "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 } - }, - "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 } - }, - "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-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 } - }, - "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.01 }, - "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, - "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 } - }, - "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 } - }, - "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-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-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 } - } - } - }, - "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/pricing", - "models": { - "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-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-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-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 } + "knowledge": "2024-09-30", + "release_date": "2025-11-13", + "last_updated": "2025-11-13", + "modalities": { + "input": ["text", "image"], + "output": ["text"] }, - "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-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-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": 400000, + "output": 128000 }, - "limit": { "context": 1000000, "output": 64000 } - }, - "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-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 } - }, - "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-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-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-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 } - }, - "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-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-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-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-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.31 }, - "limit": { "context": 1048576, "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, - "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.075, "input_audio": 1 }, - "limit": { "context": 1048576, "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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 } + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } }, "gemini-3.1-flash-lite-preview": { "id": "gemini-3.1-flash-lite-preview", @@ -15687,501 +41961,24 @@ "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-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-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-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-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-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-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-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-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.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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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": "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, "output": 196000 } - }, - "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 } - } - } - }, - "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-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-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-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-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-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-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-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-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-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", - "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 } + "modalities": { + "input": ["text", "image", "video", "audio", "pdf"], + "output": ["text"] }, - "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-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", - "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": 1048576, + "output": 65536 }, - "limit": { "context": 1000000, "output": 128000 } - } - } - }, - "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.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 } - }, - "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 } - }, - "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 } + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "cache_write": 1 + } }, "gemini-3.1-pro-preview": { "id": "gemini-3.1-pro-preview", @@ -16195,31 +41992,14590 @@ "knowledge": "2025-01", "release_date": "2026-02-19", "last_updated": "2026-02-19", - "modalities": { "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "video", "audio", "pdf"], + "output": ["text"] + }, "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, "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 } + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } }, - "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", + "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, + "limit": { + "context": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, + "cost": { + "input": 0.28, + "output": 0.42 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible" + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 81920 + }, + "cost": { + "input": 0.54, + "output": 3.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 81920 + }, + "cost": { + "input": 0.2, + "output": 0.95 + } + }, + "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, + "limit": { + "context": 262144, + "output": 66536 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 66536 + }, + "cost": { + "input": 0.4, + "output": 1.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 81920 + }, + "cost": { + "input": 0.2, + "output": 1 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0.06, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "status": "deprecated", + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0.43, + "output": 1.75, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0.8, + "output": 2.56, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.43, + "output": 1.74, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 10000000, + "output": 16384 + }, + "cost": { + "input": 0.08, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.32 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 163840, + "output": 64000 + }, + "cost": { + "input": 0.5, + "output": 2.15, + "cache_read": 0.35 + } + }, + "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, + "limit": { + "context": 163840, + "output": 64000 + }, + "cost": { + "input": 0.26, + "output": 0.38, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.03, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.05, + "output": 0.24 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.47, + "output": 2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.75, + "output": 3.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 2.8 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.254, + "output": 1.02 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.27, + "output": 0.95, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.28, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3.3, + "output": 16.5, + "cache_read": 0.33 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 16.5, + "output": 82.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.07, + "output": 0.34 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.13, + "output": 0.38 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08, + "context_over_200k": { + "input": 0.8, + "output": 4, + "cache_read": 0.16 + }, + "tiers": [ + { + "input": 0.8, + "output": 4, + "cache_read": 0.16, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01 + } + } + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 8 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.09, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 8000, + "output": 1024 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 8000, + "output": 1024 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.03, + "output": 0.12 + } + }, + "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, + "limit": { + "context": 1040000, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.05, + "output": 0.1, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131000, + "output": 32768 + }, + "cost": { + "input": 0.017, + "output": 0.11 + } + }, + "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, + "limit": { + "context": 32768, + "output": 6554 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 25600 + }, + "cost": { + "input": 2, + "output": 8 + } + }, + "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, + "limit": { + "context": 127072, + "output": 25415 + }, + "cost": { + "input": 1, + "output": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 25600 + }, + "cost": { + "input": 2, + "output": 8 + } + }, + "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, + "limit": { + "context": 32768, + "output": 7168 + }, + "cost": { + "input": 0.15, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.32, + "output": 0.89, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.7, + "output": 0.8, + "cache_read": 0.015 + } + }, + "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, + "limit": { + "context": 64000, + "output": 16000 + }, + "cost": { + "input": 0.7, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.4, + "output": 1.2, + "cache_read": 0.135 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.29, + "output": 0.29 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 0.41 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.0028 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 384000 + }, + "cost": { + "input": 0.435, + "output": 0.87, + "cache_read": 0.003625 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.26, + "output": 0.38, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.2, + "output": 0.77, + "cache_read": 0.095 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.45, + "output": 2.15, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 163840, + "output": 32768 + }, + "cost": { + "input": 0.21, + "output": 0.79, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "status": "beta", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048756, + "output": 262144 + }, + "status": "alpha", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.08, + "output": 0.24, + "cache_read": 0.016 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.045, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 64000 + }, + "cost": { + "input": 0.75, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.22, + "output": 0.85 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65537 + }, + "cost": { + "input": 0.18, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32000 + }, + "cost": { + "input": 0.9, + "output": 3.3 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 131000, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 1.25, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 163840 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.25, + "output": 2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.25, + "output": 2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 8000, + "output": 2000 + }, + "cost": { + "input": 0.75, + "output": 1 + } + }, + "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, + "limit": { + "context": 16384, + "output": 2048 + }, + "cost": { + "input": 3, + "output": 5 + } + }, + "~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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "cache_write": 0.375 + } + }, + "~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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 0.08333333333333334 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 6144, + "output": 4096 + }, + "cost": { + "input": 0.45, + "output": 0.65 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.14, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.13, + "output": 0.4, + "cache_read": 0.055 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 1 + } + }, + "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, + "limit": { + "context": 81920, + "output": 38000 + }, + "cost": { + "input": 0.8, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.9, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 6144, + "output": 1024 + }, + "cost": { + "input": 3.75, + "output": 7.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 52429 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 131072 + }, + "cost": { + "input": 0.35, + "output": 0.56, + "cache_read": 0.015 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.5, + "output": 7.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 256000, + "output": 51200 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0.05, + "output": 0.08 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 65536, + "output": 13108 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.015 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 32000, + "output": 6400 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0.54, + "output": 0.54 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.06, + "output": 0.18, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 25600 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 2824, + "output": 565 + }, + "cost": { + "input": 0.11, + "output": 0.19 + } + }, + "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, + "limit": { + "context": 262144, + "output": 52429 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "~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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "~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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "~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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.32 + } + }, + "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, + "limit": { + "context": 327680, + "output": 16384 + }, + "cost": { + "input": 0.08, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.02, + "output": 0.06 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.049, + "output": 0.049 + } + }, + "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, + "limit": { + "context": 163840, + "output": 32768 + }, + "cost": { + "input": 0.18, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 60000, + "output": 12000 + }, + "cost": { + "input": 0.027, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 80000, + "output": 16384 + }, + "cost": { + "input": 0.051, + "output": 0.34 + } + }, + "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, + "limit": { + "context": 8192, + "output": 16384 + }, + "cost": { + "input": 0.03, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8000 + }, + "cost": { + "input": 0.51, + "output": 0.74 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 4096 + }, + "cost": { + "input": 1.25, + "output": 2.5, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 256000, + "output": 51200 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 0.06, + "output": 0.06 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 1.48, + "output": 1.48 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.04, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.65, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 16000, + "output": 16000 + }, + "cost": { + "input": 3, + "output": 3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.85, + "output": 0.85 + } + }, + "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, + "limit": { + "context": 65535, + "output": 8000 + }, + "cost": { + "input": 0.62, + "output": 0.62 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.08, + "output": 0.35, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.06, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 0.0375, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.1, + "output": 0.5, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 52429 + }, + "cost": { + "input": 0.05, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.04, + "output": 0.16 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 1.2, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 50000 + }, + "cost": { + "input": 0.25, + "output": 0.75, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 5, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 21, + "output": 168 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14 + } + }, + "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, + "limit": { + "context": 16385, + "output": 4096 + }, + "cost": { + "input": 3, + "output": 4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 20, + "output": 80 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.275 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 400000, + "output": 100000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 10, + "output": 10 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180 + } + }, + "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, + "limit": { + "context": 16385, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 10, + "output": 40, + "cache_read": 2.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 150, + "output": 600 + } + }, + "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, + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 8, + "output": 15, + "cache_read": 2 + } + }, + "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, + "limit": { + "context": 8191, + "output": 4096 + }, + "cost": { + "input": 30, + "output": 60 + } + }, + "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, + "limit": { + "context": 8191, + "output": 4096 + }, + "cost": { + "input": 30, + "output": 60 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.03, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 4095, + "output": 4096 + }, + "cost": { + "input": 1, + "output": 2 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.075, + "output": 0.3, + "cache_read": 0.037 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.039, + "output": 0.19 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180 + } + }, + "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, + "limit": { + "context": 4095, + "output": 4096 + }, + "cost": { + "input": 1.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 300000, + "output": 5120 + }, + "cost": { + "input": 0.06, + "output": 0.24 + } + }, + "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, + "limit": { + "context": 300000, + "output": 5120 + }, + "cost": { + "input": 0.8, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32000 + }, + "cost": { + "input": 2.5, + "output": 12.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65535 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 5120 + }, + "cost": { + "input": 0.035, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 1.2, + "output": 4, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 202752, + "output": 65535 + }, + "cost": { + "input": 0.38, + "output": 1.98, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 0.72, + "output": 2.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 1.26, + "output": 3.96 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.13, + "output": 0.85, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 1.2, + "output": 4, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 65536, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 1.8, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 204800, + "output": 204800 + }, + "cost": { + "input": 0.39, + "output": 1.9, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 202752, + "output": 40551 + }, + "cost": { + "input": 0.06, + "output": 0.4, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 123000, + "output": 16000 + }, + "cost": { + "input": 0.42, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 65536, + "output": 28672 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 30000, + "output": 8000 + }, + "cost": { + "input": 0.14, + "output": 0.56 + } + }, + "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, + "limit": { + "context": 120000, + "output": 8000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 123000, + "output": 12000 + }, + "cost": { + "input": 0.28, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "cost": { + "input": 0.85, + "output": 1.25 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.255, + "output": 1, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 1000192, + "output": 1000192 + }, + "cost": { + "input": 0.2, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 196608, + "output": 39322 + }, + "cost": { + "input": 0.27, + "output": 0.95, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 40000 + }, + "cost": { + "input": 0.4, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 65536, + "output": 2048 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.25, + "output": 1.2, + "cache_read": 0.029 + } + }, + "~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, + "limit": { + "context": 1050000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5 + } + }, + "~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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.455, + "output": 1.82, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.26, + "output": 2.08 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.65, + "output": 3.25, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.325, + "output": 3.25 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.195, + "output": 1.56 + } + }, + "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, + "limit": { + "context": 262144, + "output": 52429 + }, + "cost": { + "input": 0.071, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 40960, + "output": 8192 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.39, + "output": 2.34 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1365, + "output": 0.4095, + "cache_read": 0.042 + } + }, + "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, + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0.08, + "output": 0.24, + "cache_read": 0.04 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.8, + "output": 0.8, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 1.04, + "output": 4.16, + "cache_read": 0.32 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.2, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.1612, + "output": 0.96525, + "cache_read": 0.1612 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.26, + "output": 2.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.13, + "output": 1.56 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.08, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.325, + "output": 1.95, + "cache_read": 0.0325, + "cache_write": 0.40625 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 1.2, + "output": 6, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.26, + "output": 0.78 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.09, + "output": 0.3, + "cache_read": 0.04 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.104, + "output": 0.416 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.11, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.0975, + "output": 0.78 + } + }, + "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, + "limit": { + "context": 32768, + "output": 6554 + }, + "cost": { + "input": 0.051, + "output": 0.34 + } + }, + "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, + "limit": { + "context": 32768, + "output": 6554 + }, + "cost": { + "input": 0.04, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.8, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.195, + "output": 0.975, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0.08, + "output": 0.28, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 131072, + "output": 52429 + }, + "cost": { + "input": 0.09, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.12, + "output": 0.75, + "cache_read": 0.035 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.2, + "cache_read": 0.015 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.13, + "output": 0.52 + } + }, + "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, + "limit": { + "context": 160000, + "output": 32768 + }, + "cost": { + "input": 0.07, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.78, + "output": 3.9 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.0325, + "output": 0.13, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 262144, + "output": 52429 + }, + "cost": { + "input": 0.2, + "output": 0.88, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 262144, + "output": 52429 + }, + "cost": { + "input": 0.22, + "output": 1, + "cache_read": 0.022 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.117, + "output": 1.365 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 1.04, + "output": 6.24, + "cache_write": 1.3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.26, + "output": 0.78 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0.12, + "output": 0.39 + } + }, + "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, + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0.06, + "output": 0.24, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.1625, + "output": 1.3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.26, + "output": 1.56 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_write": 0.3125 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 0.8, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 80000 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 1.25, + "output": 10, + "reasoning": 10, + "cache_read": 0.125, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "reasoning": 12 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "reasoning": 0.4, + "cache_read": 0.01, + "cache_write": 0.083333 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025, + "cache_write": 0.083333 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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", "image", "audio", "video", "pdf"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 6554 + }, + "cost": { + "input": 0.02, + "output": 0.04 + } + }, + "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.15, "output": 0.6, "cache_read": 0.0375 }, - "limit": { "context": 1048576, "output": 65536 } + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "reasoning": 1.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "reasoning": 12 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "reasoning": 3, + "cache_read": 0.05, + "cache_write": 0.083333 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "reasoning": 10, + "cache_read": 0.125, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 65536, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 12, + "reasoning": 12 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.14, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.04, + "output": 0.13, + "cache_read": 0.015 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "reasoning": 2.5, + "cache_read": 0.03, + "cache_write": 0.083333 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 19200 + }, + "cost": { + "input": 0.04, + "output": 0.08 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "reasoning": 10, + "cache_read": 0.125, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0.65, + "output": 0.65 + } + }, + "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, + "limit": { + "context": 128000, + "output": 65536 + }, + "cost": { + "input": 0.03, + "output": 0.11, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.12, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "reasoning": 0.4, + "cache_read": 0.01, + "cache_write": 0.083333 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65535 + }, + "cost": { + "input": 0.45, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 26215 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.15 + } + }, + "moonshotai/kimi-k2.6": { + "id": "moonshotai/kimi-k2.6", + "name": "MoonshotAI: Kimi K2.6", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-20", + "last_updated": "2026-05-12", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65535 + }, + "cost": { + "input": 0.75, + "output": 3.5, + "cache_read": 0.375 + } + }, + "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, + "limit": { + "context": 131000, + "output": 26215 + }, + "cost": { + "input": 0.55, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65535 + }, + "cost": { + "input": 0.47, + "output": 2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 4, + "output": 8 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.8, + "output": 1.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.8, + "output": 1.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.7, + "output": 1.4 + } + }, + "~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, + "limit": { + "context": 262142, + "output": 262142 + }, + "cost": { + "input": 0.74, + "output": 3.49, + "cache_read": 0.14 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.55, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.17, + "output": 0.43 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 150, + "cache_read": 3, + "cache_write": 37.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 0.25, + "output": 1.25, + "cache_read": 0.03, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.85, + "output": 3.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 2048 + }, + "cost": { + "input": 0.1, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.25, + "output": 0.85, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08, + "context_over_200k": { + "input": 0.8, + "output": 4, + "cache_read": 0.16 + }, + "tiers": [ + { + "input": 0.8, + "output": 4, + "cache_read": 0.16, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.09, + "output": 0.29, + "cache_read": 0.045 + } + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 0.25, + "output": 1.25, + "cache_read": 0.03, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "reasoning": 3 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.03, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 1, + "output": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + } + } + }, + "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, + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.85, + "output": 1.55 + } + }, + "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, + "limit": { + "context": 16000, + "output": 16000 + }, + "cost": { + "input": 0.8, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.9, + "output": 1.9 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.017, + "output": 0.11 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.026, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.06, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.35, + "output": 0.56 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.35, + "output": 0.56 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.5, + "output": 4.88 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.35, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.11, + "output": 0.19 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.27, + "output": 0.85 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.12, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.48, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.34, + "output": 0.34 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.56, + "output": 6.67 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.049, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.29, + "output": 2.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.027, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.29 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.051, + "output": 0.34 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.12, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.28, + "output": 0.83 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.28, + "output": 0.8299999999999998 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.66, + "output": 1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.012, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.66, + "output": 1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.051, + "output": 0.34 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.35, + "output": 0.56 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.34, + "output": 0.34 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.019, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.0031, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.067, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.012, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "ai-gateway-provider" + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 20, + "output": 80 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "ai-gateway-provider" + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 16385, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 1.5, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 30, + "output": 60 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "provider": { + "npm": "ai-gateway-provider" + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "provider": { + "npm": "ai-gateway-provider" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 0.25, + "output": 1.25, + "cache_read": 0.03, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5 + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + } + } + }, + "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, + "limit": { + "context": 400000, + "input": 128000, + "output": 128000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 144000, + "input": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 264000, + "input": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } }, "gemini-3-pro-preview": { "id": "gemini-3-pro-preview", @@ -16233,63 +56589,13330 @@ "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 } + "modalities": { + "input": ["text", "image", "audio", "video"], + "output": ["text"] }, - "limit": { "context": 1048576, "output": 65536 } + "open_weights": false, + "limit": { + "context": 128000, + "input": 128000, + "output": 64000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } }, - "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, + "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": true, - "knowledge": "2025-01", - "release_date": "2025-06-05", - "last_updated": "2025-06-05", - "modalities": { "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] }, + "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.25, "output": 10, "cache_read": 0.31 }, - "limit": { "context": 1048576, "output": 65536 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "gemini-2.5-pro-preview-05-06": { - "id": "gemini-2.5-pro-preview-05-06", - "name": "Gemini 2.5 Pro Preview 05-06", + "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-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-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": "2025-01", + "release_date": "2025-03-20", + "last_updated": "2025-06-05", + "modalities": { + "input": ["text", "image", "audio", "video"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "input": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 264000, + "input": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 144000, + "input": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 128000, + "output": 128000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 216000, + "input": 128000, + "output": 16000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 264000, + "input": 128000, + "output": 64000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 144000, + "input": 128000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 80000, + "output": 16000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 160000, + "input": 128000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "input": 64000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 144000, + "input": 128000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "input": 64000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "input": 128000, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 128000, + "output": 128000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.4, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.3, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.25, + "output": 1.3 + } + } + } + }, + "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, + "limit": { + "context": 8192, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 1.2, + "output": 4, + "cache_read": 0.24, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.07, + "output": 0.4, + "cache_read": 0.01, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.2, + "output": 1.1, + "cache_read": 0.03, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 1.2, + "output": 4, + "cache_read": 0.24, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 64000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "status": "deprecated", + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "provider": { + "npm": "@ai-sdk/google" + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 262000, + "output": 66000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "deepseek-v4-flash-free": { + "id": "deepseek-v4-flash-free", + "name": "DeepSeek V4 Flash Free", + "family": "deepseek-flash-free", + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 0.625 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "status": "deprecated", + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "status": "deprecated", + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "provider": { + "npm": "@ai-sdk/google" + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.07, + "output": 8.5, + "cache_read": 0.107 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 30, + "output": 180, + "cache_read": 30 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "status": "deprecated", + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 64000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "status": "deprecated", + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 262100, + "output": 32800 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "status": "deprecated", + "provider": { + "npm": "@ai-sdk/google" + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.07, + "output": 8.5, + "cache_read": 0.107 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "status": "deprecated", + "cost": { + "input": 0.4, + "output": 2.5, + "cache_read": 0.4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "status": "deprecated", + "cost": { + "input": 0.45, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.07, + "output": 8.5, + "cache_read": 0.107 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 0.2, + "output": 1.2, + "cache_read": 0.02, + "cache_write": 0.25 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 64000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 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": 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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 30, + "output": 180, + "cache_read": 30 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "status": "deprecated", + "cost": { + "input": 0.4, + "output": 2.5, + "cache_read": 0.4 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 1.07, + "output": 8.5, + "cache_read": 0.107 + } + }, + "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, + "limit": { + "context": 262144, + "output": 64000 + }, + "status": "deprecated", + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/openai" + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "context_over_200k": { + "input": 5, + "output": 22.5, + "cache_read": 0.5 + }, + "tiers": [ + { + "input": 5, + "output": 22.5, + "cache_read": 0.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/anthropic" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + } + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 2.05, + "output": 9.59, + "cache_read": 0.41 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + }, + "cost": { + "input": 0.096, + "output": 0.288, + "cache_read": 0.019 + } + }, + "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, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + }, + "cost": { + "input": 5.21, + "output": 16.44, + "cache_read": 1.04 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "cost": { + "input": 0.13, + "output": 0.4, + "reasoning": 0.4, + "cache_read": 0.013, + "cache_write": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "cost": { + "input": 1, + "output": 3, + "reasoning": 3, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.75, + "cache_read": 0.025, + "cache_write": 0.31 + } + }, + "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, + "limit": { + "context": 262144, + "input": 250000, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 3.6, + "cache_read": 0.06, + "cache_write": 0.75 + } + }, + "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, + "limit": { + "context": 32768, + "input": 32768, + "output": 0 + }, + "cost": { + "input": 0.01, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01, + "cache_write": 0.125 + } + }, + "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, + "limit": { + "context": 262144, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01, + "cache_write": 0.125 + } + }, + "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, + "limit": { + "context": 8000, + "input": 7000, + "output": 8192 + }, + "cost": { + "input": 0.5, + "output": 2, + "cache_read": 0.05, + "cache_write": 0.625 + } + }, + "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, + "limit": { + "context": 8000, + "input": 7000, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 3.6, + "cache_read": 0.06, + "cache_write": 0.75 + } + }, + "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, + "limit": { + "context": 8000, + "input": 7000, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 1.2, + "cache_read": 0.015, + "cache_write": 0.1875 + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 1.2, + "reasoning": 1.2, + "cache_read": 0.015, + "cache_write": 0.18 + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 1.1, + "cache_read": 0.02, + "cache_write": 0.25 + } + }, + "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, + "limit": { + "context": 200000, + "input": 200000, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.1, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "cost": { + "input": 0.13, + "output": 0.4, + "cache_read": 0.013, + "cache_write": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 4096 + }, + "cost": { + "input": 0.02, + "output": 0.06, + "cache_read": 0.002, + "cache_write": 0.025 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 128000, + "input": 120000, + "output": 4096 + }, + "cost": { + "input": 0.6, + "output": 1.8, + "cache_read": 0.06, + "cache_write": 0.75 + } + }, + "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, + "limit": { + "context": 32000, + "input": 30000, + "output": 4096 + }, + "cost": { + "input": 0.06, + "output": 0.24, + "cache_read": 0.006, + "cache_write": 0.075 + } + }, + "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, + "limit": { + "context": 65536, + "input": 60000, + "output": 8192 + }, + "cost": { + "input": 0.06, + "output": 0.24, + "cache_read": 0.006, + "cache_write": 0.075 + } + }, + "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, + "limit": { + "context": 8000, + "input": 7000, + "output": 8192 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.04, + "cache_write": 0.5 + } + }, + "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, + "limit": { + "context": 163000, + "input": 160000, + "output": 16384 + }, + "cost": { + "input": 0.3, + "output": 0.45, + "reasoning": 0.45, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 8000, + "input": 7000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.5, + "cache_read": 0.01, + "cache_write": 0.125 + } + }, + "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, + "limit": { + "context": 128000, + "input": 124000, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "reasoning": 0.6, + "cache_read": 0.015, + "cache_write": 0.18 + } + }, + "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, + "limit": { + "context": 8192, + "input": 8000, + "output": 4096 + }, + "cost": { + "input": 0.02, + "output": 0.06, + "cache_read": 0.002, + "cache_write": 0.025 + } + }, + "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, + "limit": { + "context": 110000, + "input": 100000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01, + "cache_write": 0.125 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 8192 + }, + "cost": { + "input": 0.5, + "output": 2.5, + "cache_read": 0.05, + "cache_write": 0.625 + } + }, + "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, + "limit": { + "context": 256000, + "input": 256000, + "output": 8192 + }, + "cost": { + "input": 0.5, + "output": 2.5, + "reasoning": 2.5, + "cache_read": 0.05, + "cache_write": 0.625 + } + }, + "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, + "limit": { + "context": 196608, + "input": 190000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 8000, + "input": 7000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.75, + "output": 3.5, + "cache_read": 0.15 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 205000, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 262144, + "input": 262144, + "output": 262144 + }, + "cost": { + "input": 0.96, + "output": 4.04, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 0 + }, + "cost": { + "input": 0.27, + "output": 0.4, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 262144, + "input": 245760, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.67, + "output": 3.33 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 128000, + "output": 0 + }, + "cost": { + "input": 0.35, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 0 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 128000, + "output": 0 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 4.5, + "output": 14 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 19, + "output": 150 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 2.2, + "output": 9, + "cache_read": 1.1 + } + }, + "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, + "limit": { + "context": 0, + "output": 0 + }, + "cost": { + "input": 5.0505, + "output": 32.3232, + "cache_read": 1.2626 + } + }, + "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, + "limit": { + "context": 8192, + "output": 4096 + }, + "status": "deprecated", + "cost": { + "input": 27, + "output": 54 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.22, + "output": 1.8, + "cache_read": 0.022 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.045, + "output": 0.36, + "cache_read": 0.0045 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.6, + "output": 13, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 9, + "output": 27 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.6, + "output": 13, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 18, + "output": 72 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 0.99, + "output": 4 + } + }, + "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, + "limit": { + "context": 124096, + "output": 4096 + }, + "cost": { + "input": 0.14, + "output": 0.54, + "cache_read": 0.068 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.8, + "output": 7.2, + "cache_read": 0.45 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.68, + "output": 4, + "cache_read": 0.068 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 0.99, + "output": 4, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.18, + "output": 1.1, + "cache_read": 0.018 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.6, + "output": 13, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.22, + "output": 1.8, + "cache_read": 0.022 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 14, + "output": 54 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 27, + "output": 160 + } + }, + "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, + "limit": { + "context": 16384, + "output": 2048 + }, + "cost": { + "input": 0.45, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 9, + "output": 36, + "cache_read": 2.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 0.99, + "output": 4 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 140, + "output": 540 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 2.2, + "output": 9 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.1, + "output": 9 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.2, + "output": 14, + "cache_read": 0.22 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 4524, + "output": 2048 + }, + "cost": { + "input": 0.45, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.09, + "output": 0.36, + "cache_read": 0.022 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.8, + "output": 7.2, + "cache_read": 0.45 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 14, + "output": 110 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.6, + "output": 13, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.14, + "output": 0.54 + } + }, + "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, + "limit": { + "context": 3500, + "output": 1024 + }, + "cost": { + "input": 1.4, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 1.8, + "output": 7.2, + "cache_read": 0.45 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.36, + "output": 1.4, + "cache_read": 0.09 + } + }, + "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, + "limit": { + "context": 8192, + "output": 4096 + }, + "status": "deprecated", + "cost": { + "input": 27, + "output": 54 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "cost": { + "input": 1.6, + "output": 13, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2 + } + }, + "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", "audio", "video", "pdf"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "video", "audio"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.075, "output": 0.3 }, - "limit": { "context": 1048576, "output": 8192 } + "limit": { + "context": 990000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.42 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 0 + }, + "status": "deprecated", + "cost": { + "input": 1.6, + "output": 9.6 + } + }, + "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, + "limit": { + "context": 1065535, + "output": 65535 + }, + "cost": { + "input": 0.87, + "output": 7, + "cache_read": 0.087 + } + }, + "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, + "limit": { + "context": 65536, + "output": 0 + }, + "cost": { + "input": 0.21, + "output": 1.8, + "cache_read": 0.021 + } + }, + "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, + "limit": { + "context": 1065535, + "output": 65535 + }, + "cost": { + "input": 0.21, + "output": 1.8, + "cache_read": 0.021 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.4, + "output": 2.4, + "cache_read": 0.04 + } + }, + "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, + "limit": { + "context": 65536, + "output": 0 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "status": "deprecated", + "cost": { + "input": 1.6, + "output": 9.6, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 1024000, + "output": 64000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 262144, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 990000, + "output": 8192 + }, + "cost": { + "input": 0.052, + "output": 0.21 + } + }, + "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, + "limit": { + "context": 196608, + "output": 32000 + }, + "cost": { + "input": 13, + "output": 64, + "cache_read": 1.3, + "cache_write": 16 + } + }, + "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, + "limit": { + "context": 189096, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 2.6, + "output": 13, + "cache_read": 0.26, + "cache_write": 3.2 + } + }, + "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, + "limit": { + "context": 189096, + "output": 8192 + }, + "cost": { + "input": 0.21, + "output": 1.1, + "cache_read": 0.021, + "cache_write": 0.26 + } + }, + "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, + "limit": { + "context": 983040, + "output": 128000 + }, + "cost": { + "input": 4.3, + "output": 21, + "cache_read": 0.43, + "cache_write": 5.3 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 128000 + }, + "cost": { + "input": 4.3, + "output": 21, + "cache_read": 0.43, + "cache_write": 5.4 + } + }, + "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, + "limit": { + "context": 983040, + "output": 64000 + }, + "cost": { + "input": 2.6, + "output": 13, + "cache_read": 0.26, + "cache_write": 3.2 + } + }, + "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, + "limit": { + "context": 983040, + "output": 32768 + }, + "cost": { + "input": 2.6, + "output": 13, + "cache_read": 0.26, + "cache_write": 3.2 + } + }, + "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, + "limit": { + "context": 196608, + "output": 64000 + }, + "cost": { + "input": 4.3, + "output": 21, + "cache_read": 0.43, + "cache_write": 5.3 + } + }, + "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, + "limit": { + "context": 196608, + "output": 128000 + }, + "cost": { + "input": 2.6, + "output": 13, + "cache_read": 0.26, + "cache_write": 3.2 + } + }, + "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, + "limit": { + "context": 192512, + "output": 28672 + }, + "cost": { + "input": 13, + "output": 64, + "cache_read": 1.3, + "cache_write": 16 + } + }, + "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, + "limit": { + "context": 189096, + "output": 8192 + }, + "cost": { + "input": 0.68, + "output": 3.4, + "cache_read": 0.068, + "cache_write": 0.85 + } + }, + "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, + "limit": { + "context": 192000, + "output": 64000 + }, + "cost": { + "input": 0.85, + "output": 4.3, + "cache_read": 0.085, + "cache_write": 1.1 + } + }, + "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, + "limit": { + "context": 189096, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 2.6, + "output": 13, + "cache_read": 0.26, + "cache_write": 3.2 + } + }, + "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, + "limit": { + "context": 983040, + "output": 128000 + }, + "cost": { + "input": 2.6, + "output": 13, + "cache_read": 0.26, + "cache_write": 3.2 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 4.5455, + "output": 27.2727, + "cache_read": 0.4545 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 27.2727, + "output": 163.6364 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16400 + }, + "cost": { + "input": 20, + "output": 40 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 0.19999999999999998, + "output": 0.5, + "cache_read": 0.049999999999999996 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.01, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16400 + }, + "cost": { + "input": 0.13, + "output": 0.39 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.08, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 5, + "output": 20, + "cache_read": 2.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.30000000000000004, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.14, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.30000000000000004, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 512, + "output": 2 + }, + "cost": { + "input": 0.01, + "output": 0.01 + } + }, + "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, + "limit": { + "context": 128000, + "output": 65536 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.39999999999999997, + "output": 1.5999999999999999, + "cache_read": 0.09999999999999999 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.03, + "output": 0.13 + } + }, + "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, + "limit": { + "context": 131072, + "output": 40960 + }, + "cost": { + "input": 0.29, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32678 + }, + "cost": { + "input": 0.59, + "output": 0.7899999999999999 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.024999999999999998 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.049999999999999996, + "output": 0.39999999999999997, + "cache_read": 0.005 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 0.25, + "output": 1.25, + "cache_read": 0.03, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.30000000000000004, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.3125, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.19999999999999998, + "output": 0.5, + "cache_read": 0.049999999999999996 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 20, + "output": 80 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.09999999999999999, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.5700000000000001, + "output": 2.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.275 + } + }, + "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, + "limit": { + "context": 127000, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 8 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.049999999999999996, + "output": 0.09999999999999999 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.075, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 130000, + "output": 163840 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.024999999999999998 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.30000000000000004, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0.19999999999999998, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12500000000000003 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.56, + "output": 1.68, + "cache_read": 0.07 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 0.19999999999999998, + "output": 0.5, + "cache_read": 0.049999999999999996 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32678 + }, + "cost": { + "input": 0.049999999999999996, + "output": 0.08 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 127000, + "output": 4096 + }, + "cost": { + "input": 1, + "output": 1 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.5, + "output": 2, + "cache_read": 0.39999999999999997 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 75, + "output": 200 + } + }, + "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, + "limit": { + "context": 41000, + "output": 41000 + }, + "cost": { + "input": 0.08, + "output": 0.29 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 262144, + "output": 81920 + }, + "cost": { + "input": 0.3, + "output": 2.9000000000000004 + } + }, + "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, + "limit": { + "context": 32000, + "output": 8192 + }, + "cost": { + "input": 0.03, + "output": 0.09 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.02, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 262000, + "output": 16384 + }, + "cost": { + "input": 0.14, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.44999999999999996, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12500000000000003 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12500000000000003 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.09999999999999999, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 127000, + "output": 4096 + }, + "cost": { + "input": 1, + "output": 5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 512, + "output": 2 + }, + "cost": { + "input": 0.01, + "output": 0.01 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.09999999999999999, + "output": 0.39999999999999997, + "cache_read": 0.024999999999999998 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.09999999999999999, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.7999999999999999, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 0.41 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.049999999999999996, + "output": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "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, + "limit": { + "context": 131072, + "output": 1024 + }, + "cost": { + "input": 0.21, + "output": 0.21 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.3, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 0.09999999999999999, + "output": 0.39999999999999997, + "cache_read": 0.024999999999999998, + "cache_write": 0.09999999999999999 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.22, + "output": 0.95 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12500000000000003 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.04, + "output": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12500000000000003 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.30000000000000004, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.56, + "output": 1.68, + "cache_read": 0.07 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.02, + "output": 0.049999999999999996 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 262144 + }, + "cost": { + "input": 0.48, + "output": 2 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.39999999999999997, + "output": 1.5999999999999999, + "cache_read": 0.09999999999999999 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.27, + "output": 1, + "cache_read": 0.21600000000000003 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.12500000000000003 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 0.19999999999999998, + "output": 0.5, + "cache_read": 0.049999999999999996 + } + }, + "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, + "limit": { + "context": 127000, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 8 + } + } + } + }, + "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 + } + }, + "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 + } + }, + "kimi-k2.6": { + "id": "kimi-k2.6", + "name": "kimi-k2.6", + "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 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.06, + "output": 0.24 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.15, + "output": 0.65 + } + }, + "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, + "limit": { + "context": 1040000, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 16.5, + "output": 82.5, + "cache_read": 1.65, + "cache_write": 20.625 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 32000, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.35 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.049999999999999996, + "output": 0.09999999999999999 + } + }, + "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, + "limit": { + "context": 300000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 204608, + "output": 128000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 16384 + }, + "cost": { + "input": 0.24, + "output": 0.97 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.035, + "output": 0.14, + "cache_read": 0.00875 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.07, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 202752, + "output": 101376 + }, + "cost": { + "input": 1, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 163840, + "output": 81920 + }, + "cost": { + "input": 0.62, + "output": 1.85 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.07, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.33, + "output": 2.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.22, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 300000, + "output": 8192 + }, + "cost": { + "input": 0.06, + "output": 0.24, + "cache_read": 0.015 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.22, + "output": 0.22 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 202752, + "output": 8192 + }, + "cost": { + "input": 0.12, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.04, + "output": 0.08 + } + }, + "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, + "limit": { + "context": 3500000, + "output": 16384 + }, + "cost": { + "input": 0.17, + "output": 0.66 + } + }, + "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, + "limit": { + "context": 163840, + "output": 81920 + }, + "cost": { + "input": 0.58, + "output": 1.68 + } + }, + "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, + "limit": { + "context": 128000, + "output": 40000 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.14, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.6, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.04, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 196608, + "output": 98304 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.72, + "output": 0.72 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.72, + "output": 0.72 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.6, + "output": 3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 3.3, + "output": 16.5, + "cache_read": 0.33, + "cache_write": 4.125 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.07, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.3, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.22, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.06, + "output": 0.23 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.22, + "output": 0.88 + } + }, + "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, + "limit": { + "context": 122880, + "output": 8192 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 16384 + }, + "cost": { + "input": 0.24, + "output": 0.97 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 3500000, + "output": 16384 + }, + "cost": { + "input": 0.17, + "output": 0.66 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + } + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 0.95, + "output": 3.15 + } + }, + "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, + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32678 + }, + "cost": { + "input": 0.3, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 164000, + "output": 131000 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 164000, + "output": 131000 + }, + "cost": { + "input": 0.77, + "output": 0.77 + } + }, + "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, + "limit": { + "context": 163800, + "output": 131100 + }, + "status": "deprecated", + "cost": { + "input": 0.3, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.1, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "status": "deprecated", + "cost": { + "input": 0.6, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "status": "deprecated", + "cost": { + "input": 0.6, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 3 + } + }, + "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, + "limit": { + "context": 204000, + "output": 204000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.15 + } + } + } + }, + "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, + "limit": { + "context": 2000000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } }, "gemini-3-flash-preview": { "id": "gemini-3-flash-preview", @@ -16303,15 +69926,73 @@ "knowledge": "2025-01", "release_date": "2025-12-17", "last_updated": "2025-12-17", - "modalities": { "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "video", "audio", "pdf"], + "output": ["text"] + }, "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, "cost": { "input": 0.5, "output": 3, - "cache_read": 0.05, - "context_over_200k": { "input": 0.5, "output": 3, "cache_read": 0.05 } + "cache_read": 0.05 + } + }, + "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"] }, - "limit": { "context": 1048576, "output": 65536 } + "open_weights": false, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 198000, + "output": 8192 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } }, "gemini-2.5-pro": { "id": "gemini-2.5-pro", @@ -16324,10 +70005,73 @@ "knowledge": "2025-01", "release_date": "2025-03-20", "last_updated": "2025-06-05", - "modalities": { "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] }, + "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 } + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } }, "gemini-2.5-flash": { "id": "gemini-2.5-flash", @@ -16338,12 +70082,2710 @@ "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"] }, + "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, "cache_write": 0.383 }, - "limit": { "context": 1048576, "output": 65536 } + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 2.5, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.14 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.07, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 192000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 192000, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 196608, + "input": 196601, + "output": 24576 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.1875, + "output": 0.75, + "cache_read": 0.09375 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.35, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 128000 + }, + "cost": { + "input": 1.42, + "output": 2.83, + "cache_read": 0.23, + "tiers": [ + { + "input": 2.83, + "output": 5.67, + "cache_read": 0.45, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.83, + "output": 5.67, + "cache_read": 0.45 + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32768 + }, + "cost": { + "input": 1.5, + "output": 5, + "cache_read": 0.3 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.1625, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 30000 + }, + "cost": { + "input": 0.23, + "output": 0.57, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3.6, + "output": 18, + "cache_read": 0.36, + "cache_write": 4.5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32768 + }, + "cost": { + "input": 0.14, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.7, + "output": 3.75, + "cache_read": 0.07 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 128000 + }, + "cost": { + "input": 1.42, + "output": 2.83, + "cache_read": 0.23, + "tiers": [ + { + "input": 2.83, + "output": 5.67, + "cache_read": 0.45, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.83, + "output": 5.67, + "cache_read": 0.45 + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.1625, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 6, + "output": 30, + "cache_read": 0.6, + "cache_write": 7.5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.35, + "output": 1.5, + "cache_read": 0.04 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.75, + "output": 4.5 + } + }, + "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, + "limit": { + "context": 198000, + "output": 16384 + }, + "cost": { + "input": 0.55, + "output": 2.65, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 131072 + }, + "cost": { + "input": 3.13, + "output": 18.8, + "cache_read": 0.313 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.125, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.25, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 2.19, + "output": 17.5, + "cache_read": 0.219 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 2.19, + "output": 17.5, + "cache_read": 0.219 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.09375, + "output": 0.25 + } + }, + "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, + "limit": { + "context": 198000, + "output": 32768 + }, + "cost": { + "input": 0.375, + "output": 1.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.45, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.3125, + "output": 1.25, + "cache_read": 0.15625 + } + }, + "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, + "limit": { + "context": 128000, + "output": 50000 + }, + "cost": { + "input": 0.3125, + "output": 0.9375, + "cache_read": 0.03125 + } + }, + "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, + "limit": { + "context": 198000, + "output": 16384 + }, + "cost": { + "input": 0.12, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 24000 + }, + "cost": { + "input": 0.14, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 37.5, + "output": 225 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 2.19, + "output": 17.5, + "cache_read": 0.219 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 198000, + "output": 32000 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 198000, + "output": 16384 + }, + "cost": { + "input": 0.85, + "output": 2.75, + "cache_read": 0.3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32000 + }, + "cost": { + "input": 1.42, + "output": 2.83, + "cache_read": 0.23, + "tiers": [ + { + "input": 2.83, + "output": 5.67, + "cache_read": 0.45, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.83, + "output": 5.67, + "cache_read": 0.45 + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.1875, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.07, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 198000, + "output": 32768 + }, + "cost": { + "input": 6, + "output": 30, + "cache_read": 0.6, + "cache_write": 7.5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.17, + "output": 0.35, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 37.5, + "output": 225, + "tiers": [ + { + "input": 75, + "output": 337.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 75, + "output": 337.5 + } + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.9375, + "output": 5.625, + "cache_read": 0.09375 + } + }, + "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, + "limit": { + "context": 198000, + "output": 32768 + }, + "cost": { + "input": 0.34, + "output": 1.19, + "cache_read": 0.04 + } + }, + "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, + "limit": { + "context": 200000, + "output": 24000 + }, + "cost": { + "input": 1.75, + "output": 5.5, + "cache_read": 0.325 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 131072 + }, + "cost": { + "input": 6.25, + "output": 37.5, + "cache_read": 0.625, + "tiers": [ + { + "input": 12.5, + "output": 56.25, + "cache_read": 1.25, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 12.5, + "output": 56.25, + "cache_read": 1.25 + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.325, + "output": 3.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 6, + "output": 30, + "cache_read": 0.6, + "cache_write": 7.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 1.73, + "output": 3.796, + "cache_read": 0.33 + } + }, + "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, + "limit": { + "context": 160000, + "output": 32768 + }, + "cost": { + "input": 0.33, + "output": 0.48, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.625, + "output": 3.75, + "cache_read": 0.0625, + "cache_write": 0.78, + "tiers": [ + { + "input": 2.5, + "output": 7.5, + "cache_read": 0.0625, + "cache_write": 0.78, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.5, + "output": 7.5, + "cache_read": 0.0625, + "cache_write": 0.78 + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 1, + "output": 2, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 198000, + "output": 64000 + }, + "cost": { + "input": 3.75, + "output": 18.75, + "cache_read": 0.375, + "cache_write": 4.69 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 3.125, + "output": 12.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.7, + "output": 2.8 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.56, + "output": 3.5, + "cache_read": 0.22 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.3125, + "output": 1.125, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.1, + "output": 3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.5, + "cache_write": 0.5, + "tiers": [ + { + "input": 5, + "output": 22.5, + "cache_read": 0.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 5, + "output": 22.5, + "cache_read": 0.5 + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.85, + "output": 4.655, + "cache_read": 0.22 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 36, + "output": 180, + "cache_read": 3.6, + "cache_write": 45 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32768 + }, + "cost": { + "input": 1.2, + "output": 4, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.175, + "output": 0.5 + } + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.2958, + "output": 1.1832, + "cache_read": 0.05916 + } + }, + "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, + "limit": { + "context": 204800, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } }, "gemini-3.1-pro-preview-customtools": { "id": "gemini-3.1-pro-preview-customtools", @@ -16357,129 +72799,1212 @@ "knowledge": "2025-01", "release_date": "2026-02-19", "last_updated": "2026-02-19", - "modalities": { "input": ["text", "image", "video", "audio", "pdf"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "audio", "video", "pdf"], + "output": ["text"] + }, "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, "cost": { "input": 2, "output": 12, "cache_read": 0.2, - "context_over_200k": { "input": 4, "output": 18, "cache_read": 0.4 } + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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" }, - "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 } - }, - "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-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-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-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-embedding-001": { - "id": "gemini-embedding-001", - "name": "Gemini Embedding 001", - "family": "gemini", - "attachment": false, - "reasoning": false, - "tool_call": false, + "structured_output": true, "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 } + "knowledge": "2025-01", + "release_date": "2026-01", + "last_updated": "2026-01", + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 0 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.105 + } }, - "openai/gpt-oss-20b-maas": { - "id": "openai/gpt-oss-20b-maas", - "name": "GPT OSS 20B", - "family": "gpt-oss", + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.7042, + "output": 3.09848, + "cache_read": 0.169008 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 1000000 + }, + "cost": { + "input": 1.25, + "output": 2.5, + "cache_read": 0.2, + "tiers": [ + { + "input": 2.5, + "output": 5, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.5, + "output": 5, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 204800, + "output": 13100 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.06, + "output": 0.22 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.154, + "output": 0.308, + "cache_read": 0.0308 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 991000, + "output": 64000 + }, + "cost": { + "input": 0.282, + "output": 1.692, + "cache_read": 0.0282, + "cache_write": 0.3525 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.845, + "output": 3.38, + "cache_read": 0.183112 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.275 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.499, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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": "2025-08-05", - "last_updated": "2025-08-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-03-18", + "last_updated": "2026-03-18", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.07, "output": 0.25 }, - "limit": { "context": 131072, "output": 32768 } + "limit": { + "context": 204800, + "output": 13100 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "openai/gpt-oss-120b-maas": { - "id": "openai/gpt-oss-120b-maas", + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.154, + "output": 0.308, + "cache_read": 0.0308 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 3.9995, + "cache_read": 0.160835 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.478, + "output": 0.956, + "cache_read": 0.004302 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 204800, + "output": 13100 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 240000, + "output": 64000 + }, + "cost": { + "input": 1.268, + "output": 7.608, + "cache_read": 0.1268, + "cache_write": 1.585 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 991000, + "output": 64000 + }, + "cost": { + "input": 0.169, + "output": 1.014, + "cache_read": 0.0169, + "cache_write": 0.21125 + } + } + } + }, + "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, + "limit": { + "context": 32000, + "output": 8000 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 131000, + "output": 32000 + }, + "cost": { + "input": 0.6, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 40000 + }, + "cost": { + "input": 2.25, + "output": 2.75, + "cache_read": 0, + "cache_write": 0 + } + }, + "gpt-oss-120b": { + "id": "gpt-oss-120b", "name": "GPT OSS 120B", "family": "gpt-oss", "attachment": false, @@ -16488,1257 +74013,19 @@ "temperature": true, "release_date": "2025-08-05", "last_updated": "2025-08-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.09, "output": 0.36 }, - "limit": { "context": 131072, "output": 32768 } - }, - "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" + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.25, + "output": 0.69 } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - } - } - }, - "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": { - "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 } - }, - "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/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/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/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-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-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 } - }, - "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 } - }, - "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 } - }, - "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-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.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/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-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 } - }, - "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 } - }, - "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.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-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.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.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.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-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-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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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-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 } - }, - "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-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.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": { - "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 } - }, - "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/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/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-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-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/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/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/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.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/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-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-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-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-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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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/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 } - }, - "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 } } } }, @@ -17760,10 +74047,19 @@ "temperature": true, "release_date": "2025-08-05", "last_updated": "2025-08-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 131072, "output": 32768 } + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } }, "qwen/qwen3-coder-30b": { "id": "qwen/qwen3-coder-30b", @@ -17776,10 +74072,19 @@ "knowledge": "2025-04", "release_date": "2025-07-23", "last_updated": "2025-07-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 262144, "output": 65536 } + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } }, "qwen/qwen3-30b-a3b-2507": { "id": "qwen/qwen3-30b-a3b-2507", @@ -17792,20 +74097,89 @@ "knowledge": "2025-04", "release_date": "2025-07-30", "last_updated": "2025-07-30", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 262144, "output": 16384 } + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } } } }, - "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", + "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, + "limit": { + "context": 120000, + "output": 8000 + }, + "cost": { + "input": 2, + "output": 5 + } + }, + "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, + "limit": { + "context": 250000, + "output": 60000 + }, + "cost": { + "input": 2, + "output": 5 + } + } + } + }, + "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", @@ -17814,1301 +74188,692 @@ "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 2.4, + "output": 10, + "cache_read": 0.6 + } + }, + "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-07", - "release_date": "2025-11", - "last_updated": "2025-12", - "modalities": { "input": ["text"], "output": ["text"] }, + "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, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 262144, "output": 32768 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } }, - "k2p5": { - "id": "k2p5", - "name": "Kimi K2.5", + "kimi-k2-thinking-turbo": { + "id": "kimi-k2-thinking-turbo", + "name": "Kimi K2 Thinking Turbo", "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 } - } - } - }, - "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": { - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, + "knowledge": "2024-08", "release_date": "2025-11-06", "last_updated": "2025-11-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.574, "output": 2.294 }, - "limit": { "context": 262144, "output": 16384 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.15, + "output": 8, + "cache_read": 0.15 + } }, "kimi-k2.5": { "id": "kimi-k2.5", - "name": "Moonshot Kimi K2.5", - "family": "kimi", + "name": "Kimi K2.5", + "family": "kimi-k2.5", "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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": { - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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-12", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.301, "output": 1.205 }, - "limit": { "context": 204800, "output": 131072 } - }, - "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" }, + "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"] }, + "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 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } }, - "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 } - }, - "siliconflow/deepseek-v3-0324": { - "id": "siliconflow/deepseek-v3-0324", - "name": "siliconflow/deepseek-v3-0324", - "family": "deepseek", + "kimi-k2-0905-preview": { + "id": "kimi-k2-0905-preview", + "name": "Kimi K2 0905", + "family": "kimi", "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-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.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 } + "knowledge": "2024-10", + "release_date": "2025-09-05", + "last_updated": "2025-09-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } } } }, - "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", + "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": { - "openai/gpt-5.2-codex": { - "id": "openai/gpt-5.2-codex", - "name": "GPT-5.2-Codex", - "family": "gpt-codex", + "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-08-31", - "release_date": "2026-01-14", - "last_updated": "2026-01-14", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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.75, "output": 14, "cache_read": 0.175 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } }, - "openai/gpt-5.1-codex-mini": { - "id": "openai/gpt-5.1-codex-mini", - "name": "GPT-5.1-Codex-Mini", - "family": "gpt-codex", + "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": "2024-09-30", - "release_date": "2025-11-13", - "last_updated": "2025-11-13", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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": 0.25, "output": 2, "cache_read": 0.025 }, - "limit": { "context": 400000, "output": 100000 } + "limit": { + "context": 200000, + "output": 32000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } }, - "openai/gpt-5.4-pro": { - "id": "openai/gpt-5.4-pro", - "name": "GPT-5.4 Pro", - "family": "gpt-pro", + "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": false, - "temperature": false, - "knowledge": "2025-08-31", - "release_date": "2026-03-05", - "last_updated": "2026-03-05", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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": 30, "output": 180, "cache_read": 30 }, - "limit": { "context": 1050000, "input": 922000, "output": 128000 } + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } }, - "openai/gpt-5-pro": { - "id": "openai/gpt-5-pro", - "name": "GPT-5 Pro", - "family": "gpt-pro", + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/models", + "shape": "completions" + }, + "cost": { + "input": 0.95, + "output": 4 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5 + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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-10-06", - "last_updated": "2025-10-06", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "release_date": "2025-11-14", + "last_updated": "2025-11-14", + "modalities": { + "input": ["text", "image", "audio"], + "output": ["text", "image", "audio"] + }, "open_weights": false, - "cost": { "input": 15, "output": 120 }, - "limit": { "context": 400000, "output": 272000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } }, - "openai/gpt-5": { - "id": "openai/gpt-5", + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 1.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 32000, + "output": 4096 + }, + "cost": { + "input": 0.125, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 512, + "output": 1024 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 60, + "output": 120 + } + }, + "gpt-5": { + "id": "gpt-5", "name": "GPT-5", "family": "gpt", "attachment": true, @@ -19118,168 +74883,854 @@ "knowledge": "2024-09-30", "release_date": "2025-08-07", "last_updated": "2025-08-07", - "modalities": { "input": ["text", "audio", "image", "video"], "output": ["text", "audio", "image"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.25, "output": 10, "cache_read": 0.13 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } }, - "openai/gpt-5.3-codex": { - "id": "openai/gpt-5.3-codex", - "name": "GPT-5.3-Codex", + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.125, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 3, + "output": 4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.17, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.58, + "output": 1.68 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 1.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0.3, + "output": 0.61 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 60, + "output": 120 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 2.68, + "output": 3.54 + } + }, + "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, + "limit": { + "context": 4096, + "output": 1024 + }, + "cost": { + "input": 0.13, + "output": 0.52 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.56, + "output": 1.68 + } + }, + "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, + "limit": { + "context": 8191, + "output": 1536 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.14, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 512, + "output": 1024 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 16.5, + "output": 66, + "cache_read": 8.25 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 128000, + "output": 1536 + }, + "cost": { + "input": 0.12, + "output": 0 + } + }, + "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-02-24", - "last_updated": "2026-02-24", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } }, - "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-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-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-4.1": { - "id": "openai/gpt-4.1", - "name": "GPT-4.1", + "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": "2024-04", - "release_date": "2025-04-14", - "last_updated": "2025-04-14", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "knowledge": "2023-11", + "release_date": "2023-11-06", + "last_updated": "2024-04-09", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 2, "output": 8, "cache_read": 0.5 }, - "limit": { "context": 1047576, "output": 32768 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } }, - "openai/gpt-5.1-chat": { - "id": "openai/gpt-5.1-chat", + "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": true, + "temperature": false, "knowledge": "2024-09-30", - "release_date": "2025-11-13", - "last_updated": "2025-11-13", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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 } + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } }, - "openai/gpt-5.4": { - "id": "openai/gpt-5.4", - "name": "GPT-5.4", - "family": "gpt", + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 5.33, + "output": 16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.37, + "output": 0.37 + } + }, + "cohere-command-a": { + "id": "cohere-command-a", + "name": "Command A", + "family": "command-a", + "attachment": false, "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, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2025-03-13", + "last_updated": "2025-03-13", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 8000 + }, "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 } + "output": 10 + } }, - "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-chat": { - "id": "openai/gpt-5.2-chat", - "name": "GPT-5.2 Chat", - "family": "gpt-codex", - "attachment": true, - "reasoning": true, + "mistral-large-2411": { + "id": "mistral-large-2411", + "name": "Mistral Large 24.11", + "family": "mistral-large", + "attachment": false, + "reasoning": false, "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"] }, + "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": 1.75, "output": 14, "cache_read": 0.175 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 6 + } }, - "openai/gpt-5.2": { - "id": "openai/gpt-5.2", + "gpt-5.2": { + "id": "gpt-5.2", "name": "GPT-5.2", "family": "gpt", "attachment": true, @@ -19290,46 +75741,198 @@ "knowledge": "2025-08-31", "release_date": "2025-12-11", "last_updated": "2025-12-11", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.75, "output": 14, "cache_read": 0.175 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.125 + } }, - "openai/gpt-5.1": { - "id": "openai/gpt-5.1", - "name": "GPT-5.1", - "family": "gpt", - "attachment": true, + "deepseek-v3.2-speciale": { + "id": "deepseek-v3.2-speciale", + "name": "DeepSeek-V3.2-Speciale", + "family": "deepseek", + "attachment": false, "reasoning": true, - "tool_call": true, - "structured_output": true, + "tool_call": false, "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 } + "knowledge": "2024-07", + "release_date": "2025-12-01", + "last_updated": "2025-12-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.58, + "output": 1.68 + } }, - "openai/gpt-4.1-mini": { - "id": "openai/gpt-4.1-mini", - "name": "GPT-4.1 Mini", - "family": "gpt-mini", + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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": "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 } + "knowledge": "2023-12", + "release_date": "2024-09-25", + "last_updated": "2024-09-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 2.04, + "output": 2.04 + } }, - "openai/gpt-5-nano": { - "id": "openai/gpt-5-nano", + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 2.68, + "output": 3.54 + } + }, + "gpt-5-nano": { + "id": "gpt-5-nano", "name": "GPT-5 Nano", "family": "gpt-nano", "attachment": true, @@ -19339,2782 +75942,200 @@ "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-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-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/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.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 } - }, - "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 } - }, - "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-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-30", - "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 } + "modalities": { + "input": ["text", "image"], + "output": ["text"] }, - "limit": { "context": 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": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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": 272000, + "output": 128000 }, - "limit": { "context": 1000000, "output": 128000 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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-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-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", "audio", "video", "pdf"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.25, "output": 10, "cache_read": 0.31, "cache_write": 2.375 }, - "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 } - } - } - }, - "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": { - "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": "2026-01-29", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "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 }, - "limit": { "context": 202752, "output": 202752 } - }, - "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 } - }, - "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 } - }, - "MiniMaxAI/MiniMax-M2.1": { - "id": "MiniMaxAI/MiniMax-M2.1", - "name": "MiniMax M2.1", - "attachment": false, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_content" }, - "structured_output": true, - "temperature": true, - "release_date": "2026-01-13", - "last_updated": "2026-01-29", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.3, "output": 1.2 }, - "limit": { "context": 196608, "output": 196608 } - }, - "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 }, - "limit": { "context": 196608, "output": 196608 } - }, - "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 } - } - } - }, - "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-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 } - }, - "claude-opus-4-5-20251101": { - "id": "claude-opus-4-5-20251101", - "name": "claude-opus-4-5-20251101", - "attachment": true, - "reasoning": false, - "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 } - }, - "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 } - }, - "gpt-5-pro": { - "id": "gpt-5-pro", - "name": "gpt-5-pro", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "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, "output": 272000 } - }, - "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 } - }, - "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 } - }, - "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.2-chat-latest": { - "id": "gpt-5.2-chat-latest", - "name": "gpt-5.2-chat-latest", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "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 } - }, - "gpt-5": { - "id": "gpt-5", - "name": "gpt-5", - "attachment": true, - "reasoning": false, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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": 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", - "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 } - }, - "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 } - }, - "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 } - }, - "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 } + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.01 + } }, "gpt-5-mini": { "id": "gpt-5-mini", - "name": "gpt-5-mini", - "attachment": true, - "reasoning": false, - "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": 0.25, "output": 2 }, - "limit": { "context": 400000, "output": 128000 } - }, - "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 } - }, - "claude-sonnet-4-5-20250929": { - "id": "claude-sonnet-4-5-20250929", - "name": "claude-sonnet-4-5-20250929", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-03", - "release_date": "2025-09-29", - "last_updated": "2025-09-29", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 3, "output": 15 }, - "limit": { "context": 200000, "output": 64000 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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": 1000000, "output": 32768 } - }, - "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 } - }, - "gpt-5.1-chat-latest": { - "id": "gpt-5.1-chat-latest", - "name": "gpt-5.1-chat-latest", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "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 } - }, - "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 } - }, - "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"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 3, "output": 15 }, - "limit": { "context": 200000, "output": 64000 } - }, - "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 } - }, - "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 } - }, - "glm-4.5": { - "id": "glm-4.5", - "name": "GLM-4.5", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "release_date": "2025-07-29", - "last_updated": "2025-07-29", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.286, "output": 1.142 }, - "limit": { "context": 128000, "output": 98304 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "glm-4.6": { - "id": "glm-4.6", - "name": "glm-4.6", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-03", - "release_date": "2025-09-30", - "last_updated": "2025-09-30", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.286, "output": 1.142 }, - "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 } - }, - "glm-4.6v": { - "id": "glm-4.6v", - "name": "GLM-4.6V", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-03", - "release_date": "2025-12-08", - "last_updated": "2025-12-08", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.145, "output": 0.43 }, - "limit": { "context": 128000, "output": 32768 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "claude-opus-4-1-20250805": { - "id": "claude-opus-4-1-20250805", - "name": "claude-opus-4-1-20250805", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-03", - "release_date": "2025-08-05", - "last_updated": "2025-08-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 15, "output": 75 }, - "limit": { "context": 200000, "output": 32000 } - }, - "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": { - "id": "gpt-5.2", - "name": "gpt-5.2", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "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, "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 } - }, - "gpt-5.1": { - "id": "gpt-5.1", - "name": "gpt-5.1", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "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, "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 } - }, - "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 } - }, - "gpt-4.1-mini": { - "id": "gpt-4.1-mini", - "name": "gpt-4.1-mini", + "name": "GPT-5 Mini", "family": "gpt-mini", "attachment": true, - "reasoning": false, + "reasoning": true, "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "release_date": "2025-04-14", - "last_updated": "2025-04-14", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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.4, "output": 1.6 }, - "limit": { "context": 1000000, "output": 32768 } + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.03 + } }, - "qwen3-235b-a22b": { - "id": "qwen3-235b-a22b", - "name": "Qwen3-235B-A22B", - "family": "qwen", + "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, + "limit": { + "context": 32000, + "output": 4096 + }, + "cost": { + "input": 0.125, + "output": 0.5 + } + }, + "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": true, + "tool_call": false, "temperature": true, - "knowledge": "2025-04", - "release_date": "2025-04-29", - "last_updated": "2025-04-29", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2023-10", + "release_date": "2024-04-23", + "last_updated": "2024-04-23", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.13, + "output": 0.52 + } + }, + "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.29, "output": 2.86 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 8191, + "output": 3072 + }, + "cost": { + "input": 0.13, + "output": 0 + } }, - "grok-4-fast-reasoning": { - "id": "grok-4-fast-reasoning", - "name": "grok-4-fast-reasoning", - "attachment": true, + "o1-mini": { + "id": "o1-mini", + "name": "o1-mini", + "family": "o-mini", + "attachment": false, "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"] }, + "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": 0.2, "output": 0.5 }, - "limit": { "context": 2000000, "output": 30000 } + "limit": { + "context": 128000, + "output": 65536 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } }, - "MiniMax-M2": { - "id": "MiniMax-M2", - "name": "MiniMax-M2", + "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": true, + "tool_call": false, "temperature": true, - "release_date": "2025-10-26", - "last_updated": "2025-10-26", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2023-10", + "release_date": "2024-08-20", + "last_updated": "2024-08-20", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.16, + "output": 0.64 + } + }, + "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": 0.33, "output": 1.32 }, - "limit": { "context": 1000000, "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.5v": { - "id": "glm-4.5v", - "name": "GLM-4.5V", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "release_date": "2025-07-29", - "last_updated": "2025-07-29", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.29, "output": 0.86 }, - "limit": { "context": 64000, "output": 16384 } - }, - "claude-haiku-4-5-20251001": { - "id": "claude-haiku-4-5-20251001", - "name": "claude-haiku-4-5-20251001", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-03", - "release_date": "2025-10-16", - "last_updated": "2025-10-16", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1, "output": 5 }, - "limit": { "context": 200000, "output": 64000 } - }, - "glm-4.7": { - "id": "glm-4.7", - "name": "glm-4.7", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-06", - "release_date": "2025-12-22", - "last_updated": "2025-12-22", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.286, "output": 1.142 }, - "limit": { "context": 200000, "output": 131072 } - }, - "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 } - }, - "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 }, - "limit": { "context": 1000000, "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "kwaipilot/kat-coder": { - "id": "kwaipilot/kat-coder", - "name": "KAT-Coder-Pro V1(Free)", - "attachment": false, - "reasoning": false, - "tool_call": true, - "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, "output": 0 }, - "limit": { "context": 256000, "output": 32000 } - }, - "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 } - }, - "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 } - }, - "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/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-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 } - }, - "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.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 } - }, - "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-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-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-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-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-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-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-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-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.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 } - }, - "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 } - }, - "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.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-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-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.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 } - }, - "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 } - }, - "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 } - }, - "skywork/r1v4-lite": { - "id": "skywork/r1v4-lite", - "name": "Skywork R1V4-Lite", - "family": "skywork", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-11-18", - "last_updated": "2025-11-18", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.6 }, - "limit": { "context": 262144, "output": 65536 } - }, - "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-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-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 } - }, - "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-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 } - }, - "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 } - }, - "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.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-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-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-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 } - }, - "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 } - }, - "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 } - }, - "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-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/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-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/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-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-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/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-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-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/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-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-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-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/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-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-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-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-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-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.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/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-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-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/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 } - }, - "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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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", - "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 } + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } }, "deepseek-v3-0324": { "id": "deepseek-v3-0324", - "name": "DeepSeek V3 0324", + "name": "DeepSeek-V3-0324", "family": "deepseek", "attachment": false, "reasoning": false, @@ -22123,62 +76144,80 @@ "knowledge": "2024-07", "release_date": "2025-03-24", "last_updated": "2025-03-24", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.551, "output": 1.654 }, - "limit": { "context": 128000, "output": 128000 } + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 1.14, + "output": 4.56 + } }, - "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 } - }, - "devstral-2512": { - "id": "devstral-2512", - "name": "Devstral 2 2512", + "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": "2025-12", - "release_date": "2025-12-09", - "last_updated": "2025-12-09", - "modalities": { "input": ["text"], "output": ["text"] }, + "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": 262000, "output": 262000 } + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.71, + "output": 0.71 + } }, "kimi-k2.5": { "id": "kimi-k2.5", "name": "Kimi K2.5", - "family": "kimi-thinking", + "family": "kimi", "attachment": false, "reasoning": true, "tool_call": true, - "interleaved": { "field": "reasoning_content" }, + "interleaved": true, + "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"] }, + "release_date": "2026-02-06", + "last_updated": "2026-02-06", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.55, "output": 2.76 }, - "limit": { "context": 256000, "output": 256000 } + "limit": { + "context": 262144, + "output": 262144 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/models", + "shape": "completions" + }, + "cost": { + "input": 0.6, + "output": 3 + } }, - "llama-3.1-405b-instruct": { - "id": "llama-3.1-405b-instruct", - "name": "Llama 3.1 405B Instruct", + "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, @@ -22187,6502 +76226,1372 @@ "knowledge": "2023-12", "release_date": "2024-07-23", "last_updated": "2024-07-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 128000 } + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.61 + } }, - "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-4.1": { - "id": "gpt-4.1", - "name": "GPT 4.1", - "family": "gpt", + "ministral-3b": { + "id": "ministral-3b", + "name": "Ministral 3B", + "family": "ministral", "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 } - }, - "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"] }, + "knowledge": "2024-03", + "release_date": "2024-10-22", + "last_updated": "2024-10-22", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.39, "output": 1.57 }, - "limit": { "context": 400000, "output": 400000 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.04, + "output": 0.04 + } }, - "gpt-oss-120b": { - "id": "gpt-oss-120b", - "name": "GPT Oss 120b", - "family": "gpt-oss", + "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, + "limit": { + "context": 4096, + "output": 1024 + }, + "cost": { + "input": 0.17, + "output": 0.68 + } + }, + "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-01", - "release_date": "2025-08-05", - "last_updated": "2025-08-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "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": 128000 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.78 + } }, - "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 } - }, - "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 } - }, - "qwen3-coder-480b-a35b-instruct": { - "id": "qwen3-coder-480b-a35b-instruct", - "name": "Qwen3 Coder 480B A35B Instruct", - "family": "qwen", + "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": true, + "tool_call": false, "temperature": true, - "knowledge": "2025-01", - "release_date": "2025-07-25", - "last_updated": "2025-07-25", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2023-10", + "release_date": "2024-08-20", + "last_updated": "2024-08-20", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.441, "output": 1.984 }, - "limit": { "context": 262000, "output": 262000 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.13, + "output": 0.52 + } }, - "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 } - }, - "gemini-2.5-pro": { - "id": "gemini-2.5-pro", - "name": "Gemini 2.5 Pro", - "family": "gemini-pro", - "attachment": false, + "phi-4-multimodal": { + "id": "phi-4-multimodal", + "name": "Phi-4-multimodal", + "family": "phi", + "attachment": true, "reasoning": false, - "tool_call": true, + "tool_call": false, "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 } + "knowledge": "2023-10", + "release_date": "2024-12-11", + "last_updated": "2024-12-11", + "modalities": { + "input": ["text", "image", "audio"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.08, + "output": 0.32, + "input_audio": 4 + } }, - "claude-opus4-5": { - "id": "claude-opus4-5", - "name": "Claude Opus 4.5", - "family": "claude-opus", + "codex-mini": { + "id": "codex-mini", + "name": "Codex Mini", + "family": "gpt-codex-mini", "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 } - }, - "nova-pro-v1": { - "id": "nova-pro-v1", - "name": "Nova Pro 1.0", - "family": "nova-pro", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, + "temperature": false, "knowledge": "2024-04", - "release_date": "2024-12-03", - "last_updated": "2024-12-03", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "release_date": "2025-05-16", + "last_updated": "2025-05-16", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.016, "output": 4.061 }, - "limit": { "context": 300000, "output": 5000 } + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.5, + "output": 6, + "cache_read": 0.375 + } }, - "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 } - }, - "intellect-3": { - "id": "intellect-3", - "name": "INTELLECT 3", + "gpt-5.2-chat": { + "id": "gpt-5.2-chat", + "name": "GPT-5.2 Chat", + "family": "gpt-codex", "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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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", - "release_date": "2026-02-05", - "last_updated": "2026-03-13", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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": 5.98, "output": 29.89 }, - "limit": { "context": 1000000, "output": 1000000 } + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } }, - "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 } - }, - "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 } - }, - "kimi-k2-instruct": { - "id": "kimi-k2-instruct", - "name": "Kimi K2 Instruct", - "family": "kimi", + "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": "2025-07-11", - "last_updated": "2025-09-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2024-07-18", + "last_updated": "2024-07-18", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.551, "output": 2.646 }, - "limit": { "context": 131000, "output": 131000 } + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } }, - "claude-4-5-sonnet": { - "id": "claude-4-5-sonnet", - "name": "Claude 4.5 Sonnet", - "family": "claude-sonnet", + "gpt-5.4-mini": { + "id": "gpt-5.4-mini", + "name": "GPT-5.4 Mini", + "family": "gpt-mini", "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 } - } - } - }, - "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": { - "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"] }, + "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.086, "output": 0.086 }, - "limit": { "context": 33000, "output": 33000 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } }, - "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-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-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 } - }, - "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", + "gpt-5.4-nano": { + "id": "gpt-5.4-nano", + "name": "GPT-5.4 Nano", + "family": "gpt-nano", "attachment": true, - "reasoning": false, + "reasoning": true, "tool_call": true, "structured_output": true, - "temperature": true, - "release_date": "2025-08-13", - "last_updated": "2025-11-25", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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.14, "output": 0.86 }, - "limit": { "context": 66000, "output": 66000 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } }, - "zai-org/GLM-4.6V": { - "id": "zai-org/GLM-4.6V", - "name": "zai-org/GLM-4.6V", - "family": "glm", + "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": true, - "release_date": "2025-12-07", - "last_updated": "2025-12-07", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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.3, "output": 0.9 }, - "limit": { "context": 131000, "output": 131000 } + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "context_over_200k": { + "input": 60, + "output": 270 + }, + "tiers": [ + { + "input": 60, + "output": 270, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } }, - "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 } - }, - "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 } - }, - "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": { - "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/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 } - }, - "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/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.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/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": { - "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/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, - "structured_output": true, - "temperature": true, - "release_date": "2026-01-27", - "last_updated": "2026-01-27", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.55, "output": 3 }, - "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-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 } - }, - "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 } - }, - "PaddlePaddle/PaddleOCR-VL-1.5": { - "id": "PaddlePaddle/PaddleOCR-VL-1.5", - "name": "PaddlePaddle/PaddleOCR-VL-1.5", + "gpt-5.4": { + "id": "gpt-5.4", + "name": "GPT-5.4", + "family": "gpt", "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 } - }, - "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 } - }, - "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": { - "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-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"] }, + "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.27, "output": 0.42 }, - "limit": { "context": 164000, "output": 164000 } + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "context_over_200k": { + "input": 5, + "output": 22.5, + "cache_read": 0.5 + }, + "tiers": [ + { + "input": 5, + "output": 22.5, + "cache_read": 0.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } }, - "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.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-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-vl2": { - "id": "deepseek-ai/deepseek-vl2", - "name": "deepseek-ai/deepseek-vl2", - "family": "deepseek", + "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": "2024-12-13", - "last_updated": "2025-11-25", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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.15, "output": 0.15 }, - "limit": { "context": 4000, "output": 4000 } + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } }, - "ByteDance-Seed/Seed-OSS-36B-Instruct": { - "id": "ByteDance-Seed/Seed-OSS-36B-Instruct", - "name": "ByteDance-Seed/Seed-OSS-36B-Instruct", - "family": "seed", + "grok-3": { + "id": "grok-3", + "name": "Grok 3", + "family": "grok", "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"] }, + "knowledge": "2024-11", + "release_date": "2025-02-17", + "last_updated": "2025-02-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.21, "output": 0.57 }, - "limit": { "context": 262000, "output": 262000 } + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } }, - "Qwen/Qwen3.5-35B-A3B": { - "id": "Qwen/Qwen3.5-35B-A3B", - "name": "Qwen/Qwen3.5-35B-A3B", - "family": "qwen", + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 272000 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "grok-3-mini": { + "id": "grok-3-mini", + "name": "Grok 3 Mini", + "family": "grok", "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 } + "knowledge": "2024-11", + "release_date": "2025-02-17", + "last_updated": "2025-02-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "reasoning": 0.5, + "cache_read": 0.075 + } }, - "Qwen/Qwen3.5-397B-A17B": { - "id": "Qwen/Qwen3.5-397B-A17B", - "name": "Qwen/Qwen3.5-397B-A17B", - "family": "qwen", + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "reasoning": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + } + } + }, + "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, + "limit": { + "context": 150000, + "input": 150000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 3 + } + } + } + }, + "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"] }, + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.29, "output": 1.74 }, - "limit": { "context": 262144, "output": 65536 } + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } }, - "Qwen/Qwen3.5-122B-A10B": { - "id": "Qwen/Qwen3.5-122B-A10B", - "name": "Qwen/Qwen3.5-122B-A10B", - "family": "qwen", + "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-02-26", - "last_updated": "2026-02-26", - "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, + "release_date": "2026-04-07", + "last_updated": "2026-04-07", + "modalities": { + "input": ["text"], + "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-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/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-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-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-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-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-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-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-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-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/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-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-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-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/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-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-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-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-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-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-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-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/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-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/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/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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } } } }, - "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", + "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, + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 0.0375, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 0.0375, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 8000, + "output": 8000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + } + } + }, + "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, + "limit": { + "context": 70000, + "output": 70000 + }, + "cost": { + "input": 2.92, + "output": 2.92 + } + }, "openai/gpt-oss-120b": { "id": "openai/gpt-oss-120b", - "name": "GPT OSS 120B", + "name": "OpenAI 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"] }, + "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": 0.24, "output": 0.94 }, - "limit": { "context": 65536, "output": 65536 } + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 2.92, + "output": 2.92 + } }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "Qwen/Qwen3-VL-30B-A3B-Instruct": { - "id": "Qwen/Qwen3-VL-30B-A3B-Instruct", - "name": "Qwen3 VL 30B", - "family": "qwen", + "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, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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/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 } - }, - "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 } - } - } - }, - "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": { - "giga-potato": { - "id": "giga-potato", - "name": "Giga Potato (free)", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "release_date": "2025-08-27", - "last_updated": "2026-03-15", - "modalities": { "input": ["image", "text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 256000, "output": 32000 } - }, - "corethink:free": { - "id": "corethink:free", - "name": "CoreThink (free)", - "attachment": false, - "reasoning": false, - "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": 78000, "output": 8192 } - }, - "giga-potato-thinking": { - "id": "giga-potato-thinking", - "name": "Giga Potato Thinking (free)", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "release_date": "2025-08-27", - "last_updated": "2026-03-15", - "modalities": { "input": ["image", "text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 256000, "output": 32000 } - }, - "morph-warp-grep-v2": { - "id": "morph-warp-grep-v2", - "name": "Morph: WarpGrep V2", - "attachment": false, - "reasoning": false, - "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": 32000 } - }, - "eleutherai/llemma_7b": { - "id": "eleutherai/llemma_7b", - "name": "EleutherAI: Llemma 7b", - "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 } - }, - "meituan/longcat-flash-chat": { - "id": "meituan/longcat-flash-chat", - "name": "Meituan: LongCat Flash Chat", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "release_date": "2025-08-30", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.2, "output": 0.8, "cache_read": 0.2 }, - "limit": { "context": 131072, "output": 131072 } - }, - "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/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.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-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-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-4o:extended": { - "id": "openai/gpt-4o:extended", - "name": "OpenAI: GPT-4o (extended)", - "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": 6, "output": 18 }, - "limit": { "context": 128000, "output": 64000 } - }, - "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-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-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-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-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-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-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-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-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/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-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-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/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/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-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-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/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-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.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/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/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-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/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-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-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/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/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-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-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-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 } - }, - "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-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/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-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-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/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-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-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-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-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/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/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-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-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/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-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/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/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/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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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, + "structured_output": true, "temperature": true, + "knowledge": "2025-03", "release_date": "2025-03-13", "last_updated": "2025-03-13", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 2.5, "output": 10 }, - "limit": { "context": 256000, "output": 8192 } + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.67, + "output": 0.67 + } }, - "kwaipilot/kat-coder-pro": { - "id": "kwaipilot/kat-coder-pro", - "name": "Kwaipilot: KAT-Coder-Pro V1", + "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, - "release_date": "2025-09-30", - "last_updated": "2025-10-24", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.207, "output": 0.828, "cache_read": 0.0414 }, - "limit": { "context": 256000, "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 } - }, - "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 } - }, - "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 } - }, - "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-4.20-beta": { - "id": "x-ai/grok-4.20-beta", - "name": "xAI: Grok 4.20 Beta", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "release_date": "2026-03-12", - "last_updated": "2026-03-15", - "modalities": { "input": ["image", "text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 2, "output": 6 }, - "limit": { "context": 2000000, "output": 32768 } - }, - "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-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-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-4.20-multi-agent-beta": { - "id": "x-ai/grok-4.20-multi-agent-beta", - "name": "xAI: Grok 4.20 Multi-Agent Beta", - "attachment": true, - "reasoning": true, - "tool_call": false, - "temperature": true, - "release_date": "2026-03-12", - "last_updated": "2026-03-15", - "modalities": { "input": ["image", "text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 2, "output": 6 }, - "limit": { "context": 2000000, "output": 32768 } - }, - "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-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-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-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 } - }, - "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 } - }, - "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, - "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-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-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.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": { - "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-sonnet-4.6": { - "id": "anthropic/claude-sonnet-4.6", - "name": "Anthropic: Claude Sonnet 4.6", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "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 } - }, - "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-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-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.5-sonnet": { - "id": "anthropic/claude-3.5-sonnet", - "name": "Anthropic: Claude 3.5 Sonnet", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "release_date": "2024-10-22", - "last_updated": "2026-03-15", - "modalities": { "input": ["image", "pdf", "text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 6, "output": 30 }, - "limit": { "context": 200000, "output": 8192 } - }, - "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-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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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-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-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-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.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 } - }, - "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 } - }, - "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-nano-12b-v2-vl": { - "id": "nvidia/nemotron-nano-12b-v2-vl", - "name": "NVIDIA: Nemotron Nano 12B 2 VL", - "attachment": true, - "reasoning": true, - "tool_call": false, - "temperature": true, - "release_date": "2025-10-28", - "last_updated": "2026-01-31", - "modalities": { "input": ["image", "text", "video"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.6 }, - "limit": { "context": 131072, "output": 26215 } - }, - "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/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-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 } - }, - "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 } - }, - "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 } - }, - "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.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-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.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-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.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-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 } - }, - "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 } - }, - "allenai/olmo-3.1-32b-instruct": { - "id": "allenai/olmo-3.1-32b-instruct", - "name": "AllenAI: Olmo 3.1 32B Instruct", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "release_date": "2026-01-07", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.6 }, - "limit": { "context": 65536, "output": 32768 } - }, - "allenai/olmo-2-0325-32b-instruct": { - "id": "allenai/olmo-2-0325-32b-instruct", - "name": "AllenAI: Olmo 2 32B Instruct", - "attachment": false, - "reasoning": false, - "tool_call": false, - "release_date": "2025-03-15", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.05, "output": 0.2 }, - "limit": { "context": 128000, "output": 32768 } - }, - "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 } - }, - "allenai/olmo-3-7b-think": { - "id": "allenai/olmo-3-7b-think", - "name": "AllenAI: Olmo 3 7B 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.12, "output": 0.2 }, - "limit": { "context": 65536, "output": 65536 } - }, - "allenai/olmo-3.1-32b-think": { - "id": "allenai/olmo-3.1-32b-think", - "name": "AllenAI: Olmo 3.1 32B Think", - "attachment": false, - "reasoning": true, - "tool_call": false, - "temperature": true, - "release_date": "2025-12-17", - "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 } - }, - "allenai/olmo-3-7b-instruct": { - "id": "allenai/olmo-3-7b-instruct", - "name": "AllenAI: Olmo 3 7B Instruct", - "attachment": false, - "reasoning": false, - "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.1, "output": 0.2 }, - "limit": { "context": 65536, "output": 65536 } - }, - "allenai/molmo-2-8b": { - "id": "allenai/molmo-2-8b", - "name": "AllenAI: Molmo2 8B", - "attachment": true, - "reasoning": false, - "tool_call": false, - "temperature": true, - "release_date": "2026-01-09", - "last_updated": "2026-01-31", - "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.2 }, - "limit": { "context": 36864, "output": 36864 } - }, - "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.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/gemma-2-9b-it": { - "id": "google/gemma-2-9b-it", - "name": "Google: Gemma 2 9B", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": true, - "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": 1639 } - }, - "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-pro-preview": { - "id": "google/gemini-3-pro-preview", - "name": "Google: Gemini 3 Pro Preview", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "release_date": "2025-11-18", - "last_updated": "2026-03-15", - "modalities": { "input": ["audio", "image", "pdf", "text", "video"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 2, "output": 12, "reasoning": 12, "cache_read": 0.2, "cache_write": 0.375 }, - "limit": { "context": 1048576, "output": 65536 } - }, - "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-3-4b-it": { - "id": "google/gemma-3-4b-it", - "name": "Google: Gemma 3 4B", - "attachment": true, - "reasoning": false, - "tool_call": false, - "temperature": true, + "knowledge": "2025-03", "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/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-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/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/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 } - }, - "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-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/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-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-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/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/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-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/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-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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "kilo/auto": { - "id": "kilo/auto", - "name": "Kilo: Auto", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "release_date": "2024-06-01", - "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-free": { - "id": "kilo/auto-free", - "name": "Deprecated 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 } - }, - "kilo/auto-small": { - "id": "kilo/auto-small", - "name": "Deprecated 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 } - }, - "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-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-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-405b-instruct": { - "id": "meta-llama/llama-3.1-405b-instruct", - "name": "Meta: Llama 3.1 405B Instruct", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": true, - "release_date": "2024-07-16", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 4, "output": 4 }, - "limit": { "context": 131000, "output": 26200 } - }, - "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.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-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-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-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 } - }, - "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-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-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.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.1-405b": { - "id": "meta-llama/llama-3.1-405b", - "name": "Meta: Llama 3.1 405B (base)", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": true, - "release_date": "2024-08-02", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 4, "output": 4 }, - "limit": { "context": 32768, "output": 32768 } - }, - "openrouter/hunter-alpha": { - "id": "openrouter/hunter-alpha", - "name": "Hunter Alpha", - "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": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 1048576, "output": 32000 } - }, - "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 } - }, - "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/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/healer-alpha": { - "id": "openrouter/healer-alpha", - "name": "Healer Alpha", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "release_date": "2026-03-12", - "last_updated": "2026-03-15", - "modalities": { "input": ["audio", "image", "text", "video"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 262144, "output": 32000 } - }, - "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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:free": { - "id": "arcee-ai/trinity-large-preview:free", - "name": "Arcee AI: Trinity Large Preview (free)", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "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": 131000, "output": 26200 } - }, - "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-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/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 } - }, - "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 } - }, - "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 } - }, - "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/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/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 } - }, - "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-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-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-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-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 } - }, - "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-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": { - "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-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-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 } - }, - "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.5:free": { - "id": "minimax/minimax-m2.5:free", - "name": "MiniMax: MiniMax M2.5 (free)", - "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 }, - "limit": { "context": 204800, "output": 131072 } - }, - "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-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-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/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/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-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/qwq-32b": { - "id": "qwen/qwq-32b", - "name": "Qwen: QwQ 32B", - "attachment": false, - "reasoning": true, - "tool_call": true, - "temperature": true, - "release_date": "2024-11-28", - "last_updated": "2025-04-11", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.15, "output": 0.4 }, - "limit": { "context": 32768, "output": 32768 } - }, - "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-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/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/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-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/qwen2.5-coder-7b-instruct": { - "id": "qwen/qwen2.5-coder-7b-instruct", - "name": "Qwen: Qwen2.5 Coder 7B Instruct", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": true, - "release_date": "2024-09-17", - "last_updated": "2024-11", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.03, "output": 0.09 }, - "limit": { "context": 32768, "output": 6554 } - }, - "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-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/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.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-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-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/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-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-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-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/qwen2.5-vl-32b-instruct": { - "id": "qwen/qwen2.5-vl-32b-instruct", - "name": "Qwen: Qwen2.5 VL 32B Instruct", - "attachment": true, - "reasoning": false, - "tool_call": false, - "temperature": true, - "release_date": "2025-03-24", - "last_updated": "2026-03-15", - "modalities": { "input": ["image", "text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.6, "cache_read": 0.025 }, - "limit": { "context": 128000, "output": 16384 } - }, - "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-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/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/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-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-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-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-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-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/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-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-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/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.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/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-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/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/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/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-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/qwen-2.5-vl-7b-instruct": { - "id": "qwen/qwen-2.5-vl-7b-instruct", - "name": "Qwen: Qwen2.5-VL 7B Instruct", - "attachment": true, - "reasoning": false, - "tool_call": false, - "temperature": true, - "release_date": "2024-08-28", - "last_updated": "2024-09", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.2 }, - "limit": { "context": 32768, "output": 6554 } - }, - "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-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 } - }, - "xiaomi/mimo-v2-flash": { - "id": "xiaomi/mimo-v2-flash", - "name": "Xiaomi: MiMo-V2-Flash", - "attachment": false, - "reasoning": true, - "tool_call": true, - "temperature": true, - "release_date": "2025-12-14", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.09, "output": 0.29, "cache_read": 0.045 }, - "limit": { "context": 262144, "output": 65536 } - }, - "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 } - }, - "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": "2026-01-29", - "last_updated": "2026-01-29", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 256000, "output": 256000 } - }, - "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 } - }, - "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 } - }, - "liquid/lfm-2.2-6b": { - "id": "liquid/lfm-2.2-6b", - "name": "LiquidAI: LFM2-2.6B", - "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.01, "output": 0.02 }, - "limit": { "context": 32768, "output": 32768 } - }, - "liquid/lfm2-8b-a1b": { - "id": "liquid/lfm2-8b-a1b", - "name": "LiquidAI: LFM2-8B-A1B", - "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.01, "output": 0.02 }, - "limit": { "context": 32768, "output": 32768 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "inception/mercury-coder": { - "id": "inception/mercury-coder", - "name": "Inception: Mercury Coder", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "release_date": "2025-02-26", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 0.75 }, - "limit": { "context": 128000, "output": 32000 } - }, - "inception/mercury": { - "id": "inception/mercury", - "name": "Inception: Mercury", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "release_date": "2025-06-26", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 0.75 }, - "limit": { "context": 128000, "output": 32000 } - }, - "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 } - }, - "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 } - }, - "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/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 } - }, - "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 } - }, - "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 } - }, - "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/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/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-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/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/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/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-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/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/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 } - }, - "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/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-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/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-small-creative": { - "id": "mistralai/mistral-small-creative", - "name": "Mistral: Mistral Small Creative", - "attachment": false, - "reasoning": false, - "tool_call": true, - "release_date": "2025-12-17", - "last_updated": "2026-03-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.1, "output": 0.3 }, - "limit": { "context": 32768, "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/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-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/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/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/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/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-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-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 } + "last_updated": "2025-03-13", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.67, + "output": 0.67 + } + }, + "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, + "limit": { + "context": 196000, + "input": 180000, + "output": 16000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } } } }, @@ -28701,122 +77610,789 @@ "attachment": false, "reasoning": true, "tool_call": true, - "interleaved": { "field": "reasoning_content" }, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, "knowledge": "2025-04", "release_date": "2025-12-22", "last_updated": "2025-12-22", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 204800, "output": 131072 } + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } } } }, - "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", + "xai": { + "id": "xai", + "env": ["XAI_API_KEY"], + "npm": "@ai-sdk/xai", + "name": "xAI", + "doc": "https://docs.x.ai/docs/models", "models": { - "ZhipuAI/GLM-4.5": { - "id": "ZhipuAI/GLM-4.5", - "name": "GLM-4.5", - "family": "glm", + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 2, + "output": 10, + "cache_read": 2 + } + }, + "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, + "limit": { + "context": 8192, + "output": 4096 + }, + "cost": { + "input": 5, + "output": 15, + "cache_read": 5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 30000 + }, + "cost": { + "input": 1.25, + "output": 2.5, + "cache_read": 0.2, + "tiers": [ + { + "input": 2.5, + "output": 5, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.5, + "output": 5, + "cache_read": 0.4 + } + } + }, + "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": "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 } + "knowledge": "2024-11", + "release_date": "2025-02-17", + "last_updated": "2025-02-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 4, + "reasoning": 4, + "cache_read": 0.15 + } }, - "ZhipuAI/GLM-4.6": { - "id": "ZhipuAI/GLM-4.6", - "name": "GLM-4.6", - "family": "glm", + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "reasoning": 0.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 8192, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 10, + "cache_read": 2 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 12, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 12, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 4, + "reasoning": 4, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 2, + "output": 10, + "cache_read": 2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 12, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 12, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 12, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 12, + "cache_read": 0.4 + } + } + }, + "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-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 } + "release_date": "2025-07-09", + "last_updated": "2025-07-09", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "reasoning": 15, + "cache_read": 0.75 + } }, - "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-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 } - }, - "Qwen/Qwen3-Coder-30B-A3B-Instruct": { - "id": "Qwen/Qwen3-Coder-30B-A3B-Instruct", - "name": "Qwen3 Coder 30B A3B Instruct", - "family": "qwen", + "grok-2-latest": { + "id": "grok-2-latest", + "name": "Grok 2 Latest", + "family": "grok", "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 } + "knowledge": "2024-08", + "release_date": "2024-08-20", + "last_updated": "2024-12-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 2, + "output": 10, + "cache_read": 2 + } }, - "Qwen/Qwen3-30B-A3B-Instruct-2507": { - "id": "Qwen/Qwen3-30B-A3B-Instruct-2507", - "name": "Qwen3 30B A3B Instruct 2507", - "family": "qwen", + "grok-beta": { + "id": "grok-beta", + "name": "Grok Beta", + "family": "grok-beta", "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 } + "knowledge": "2024-08", + "release_date": "2024-11-01", + "last_updated": "2024-11-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 4096 + }, + "cost": { + "input": 5, + "output": 15, + "cache_read": 5 + } }, + "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, + "limit": { + "context": 8192, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 10, + "cache_read": 2 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "reasoning": 0.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 8192, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 10, + "cache_read": 2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + } + } + }, + "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", @@ -28824,2802 +78400,160 @@ "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.09, + "output": 0.6 + } + }, + "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": "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 } - } - } - }, - "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": { - "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.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-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-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.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": 7.5e-7, "output": 0.0000045, "cache_read": 7.5e-8 }, - "limit": { "context": 400000, "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-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-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-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-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.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-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-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-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/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 } + "release_date": "2026-02", + "last_updated": "2026-02", + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] }, - "limit": { "context": 1050000, "input": 922000, "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-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.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": 2e-7, "output": 0.00000125, "cache_read": 2e-8 }, - "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-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.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-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-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-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-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-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-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/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.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 } - }, - "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 } - }, - "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 } - }, - "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-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-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": { - "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-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-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-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-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-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 } - }, - "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 } - }, - "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-30", - "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": 65536 }, - "limit": { "context": 1000000, "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, - "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-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-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, - "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 } + "input": 0.4, + "output": 2.4, + "reasoning": 2.4 + } }, - "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-3.5-haiku": { - "id": "anthropic/claude-3.5-haiku", - "name": "Claude Haiku 3.5", - "family": "claude-haiku", + "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, - "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.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-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": { - "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 } - }, - "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 } - }, - "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-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.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-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-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"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 16384, "output": 8192 } + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } }, - "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 } - }, - "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": { - "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-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 } - }, - "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-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-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 } - }, - "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 } - }, - "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": { - "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.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-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-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.7": { - "id": "z-ai/glm-4.7", + "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_details" }, - "structured_output": 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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.6, "output": 2.2, "cache_read": 0.11 }, - "limit": { "context": 204800, "output": 131072 } + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } }, - "z-ai/glm-4.6:exacto": { - "id": "z-ai/glm-4.6:exacto", - "name": "GLM 4.6 (exacto)", + "zai-org/GLM-5": { + "id": "zai-org/GLM-5", + "name": "GLM-5", "family": "glm", "attachment": false, "reasoning": true, "tool_call": true, - "structured_output": true, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, - "knowledge": "2025-09", + "release_date": "2026-02-11", + "last_updated": "2026-02-11", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 0.8, + "output": 2.56 + } + }, + "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.6, "output": 1.9, "cache_read": 0.11 }, - "limit": { "context": 200000, "output": 128000 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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/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/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/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 } + "modalities": { + "input": ["text"], + "output": ["text"] }, - "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-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-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/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-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-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-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-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-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-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-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.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, - "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-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": 202752, + "output": 131072 }, - "limit": { "context": 1048576, "output": 65536 } - }, - "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/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 } + "input": 0.45, + "output": 1.9 + } }, - "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-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-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 } - }, - "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 } - }, - "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-mini:free": { - "id": "arcee-ai/trinity-mini:free", - "name": "Trinity Mini", - "family": "trinity-mini", - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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": { - "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-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.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.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 } - }, - "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 } - }, - "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-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 } - }, - "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.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-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-4b:free": { - "id": "qwen/qwen3-4b:free", - "name": "Qwen3 4B (free)", - "family": "qwen", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2025-04", - "release_date": "2025-04-30", - "last_updated": "2025-07-23", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 40960, "output": 40960 } - }, - "qwen/qwen3-coder:free": { - "id": "qwen/qwen3-coder:free", - "name": "Qwen3 Coder 480B A35B Instruct (free)", - "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": 66536 } - }, - "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/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-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-instruct:free": { - "id": "qwen/qwen3-next-80b-a3b-instruct:free", - "name": "Qwen3 Next 80B A3B Instruct (free)", - "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, "output": 0 }, - "limit": { "context": 262144, "output": 262144 } - }, - "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/qwen3.6-plus-preview:free": { - "id": "qwen/qwen3.6-plus-preview:free", - "name": "Qwen3.6 Plus Preview (free)", - "family": "qwen", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2026-03-30", - "last_updated": "2026-03-30", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 1000000, "output": 65536 } - }, - "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.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/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 }, - "limit": { "context": 262144, "output": 32768 } - }, - "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 }, - "limit": { "context": 128000, "output": 66536 } - }, - "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-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 } - }, - "xiaomi/mimo-v2-pro": { - "id": "xiaomi/mimo-v2-pro", - "name": "MiMo-V2-Pro", - "family": "mimo", - "attachment": false, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_details" }, - "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": 1, "output": 3 }, - "limit": { "context": 1048576, "output": 65536 } - }, - "xiaomi/mimo-v2-omni": { - "id": "xiaomi/mimo-v2-omni", - "name": "MiMo-V2-Omni", - "family": "mimo", - "attachment": true, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_details" }, - "structured_output": true, - "temperature": true, - "release_date": "2026-03-18", - "last_updated": "2026-03-18", - "modalities": { "input": ["text", "image", "video", "audio"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.4, "output": 2 }, - "limit": { "context": 262144, "output": 65536 } - }, - "xiaomi/mimo-v2-flash": { - "id": "xiaomi/mimo-v2-flash", - "name": "MiMo-V2-Flash", - "family": "mimo", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2024-12", - "release_date": "2025-12-14", - "last_updated": "2025-12-14", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.1, "output": 0.3, "cache_read": 0.01 }, - "limit": { "context": 262144, "output": 65536 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "stepfun/step-3.5-flash:free": { - "id": "stepfun/step-3.5-flash:free", - "name": "Step 3.5 Flash (free)", - "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, "output": 0 }, - "limit": { "context": 256000, "output": 256000 } - }, - "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 } - }, - "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 } - }, - "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": { - "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-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:free": { - "id": "moonshotai/kimi-k2:free", - "name": "Kimi K2 (free)", - "family": "kimi", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-04", - "release_date": "2025-07-11", - "last_updated": "2025-07-11", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 32800, "output": 32800 } - }, - "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 } - }, - "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 } - }, - "inception/mercury-coder": { - "id": "inception/mercury-coder", - "name": "Mercury Coder", - "family": "mercury", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-04-30", - "last_updated": "2025-04-30", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 0.75, "cache_read": 0.025 }, - "limit": { "context": 128000, "output": 32000 } - }, - "inception/mercury": { - "id": "inception/mercury", - "name": "Mercury", - "family": "mercury", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-06-26", - "last_updated": "2025-06-26", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 0.75, "cache_read": 0.025 }, - "limit": { "context": 128000, "output": 32000 } - }, - "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/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-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-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/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 } - }, - "mistralai/mistral-small-3.2-24b-instruct": { - "id": "mistralai/mistral-small-3.2-24b-instruct", + "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, @@ -31630,6577 +78564,118 @@ "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/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 } - } - } - }, - "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": { - "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.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.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": { - "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.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.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": { - "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.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.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": { - "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.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-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.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" } - }, - "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" } - }, - "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-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": { - "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-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.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 } - }, - "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-01-01", - "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-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-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-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-01-01", - "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" } - }, - "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-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-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-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": { - "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" } - }, - "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-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-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 } - }, - "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-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-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 } - }, - "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 } - }, - "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-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.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.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.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 } - }, - "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.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-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-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-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 } - }, - "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 } - }, - "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 } - }, - "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-pro-preview": { - "id": "google/gemini-3-pro-preview", - "name": "Gemini 3 Pro Preview", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2025-01-01", - "release_date": "2025-11-18", - "last_updated": "2025-11-18", - "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-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 } - }, - "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.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": { - "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.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.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.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 } - }, - "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-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-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 } - }, - "xiaomi/mimo-v2-flash-free": { - "id": "xiaomi/mimo-v2-flash-free", - "name": "MiMo-V2-Flash Free", - "attachment": false, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2025-01-01", - "release_date": "2025-12-17", - "last_updated": "2025-12-17", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 262000, "output": 64000 } - }, - "xiaomi/mimo-v2-pro": { - "id": "xiaomi/mimo-v2-pro", - "name": "MiMo V2 Pro", - "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", "video"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.5, "output": 4.5 }, - "limit": { "context": 1000000, "output": 256000 } - }, - "xiaomi/mimo-v2-omni": { - "id": "xiaomi/mimo-v2-omni", - "name": "MiMo V2 Omni", - "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", "video"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.4, "output": 2 }, - "limit": { "context": 265000, "output": 265000 } - }, - "xiaomi/mimo-v2-flash": { - "id": "xiaomi/mimo-v2-flash", - "name": "MiMo-V2-Flash", - "attachment": false, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2025-01-01", - "release_date": "2025-12-17", - "last_updated": "2025-12-17", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.1, "output": 0.3, "cache_read": 0.01 }, - "limit": { "context": 262000, "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": { - "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 } - }, - "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 } - }, - "kuaishou/kat-coder-pro-v1-free": { - "id": "kuaishou/kat-coder-pro-v1-free", - "name": "KAT-Coder-Pro-V1 Free", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-01-01", - "release_date": "2025-10-23", - "last_updated": "2025-10-23", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 256000, "output": 64000 } - }, - "kuaishou/kat-coder-pro-v1": { - "id": "kuaishou/kat-coder-pro-v1", - "name": "KAT-Coder-Pro-V1", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-01-01", - "release_date": "2025-10-23", - "last_updated": "2025-10-23", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.3, "output": 1.2, "cache_read": 0.06 }, - "limit": { "context": 256000, "output": 64000 } - }, - "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 } - }, - "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-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-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 } - } - } - }, - "perplexity": { - "id": "perplexity", - "env": ["PERPLEXITY_API_KEY"], - "npm": "@ai-sdk/perplexity", - "name": "Perplexity", - "doc": "https://docs.perplexity.ai", - "models": { - "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 } - }, - "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 } - } - } - }, - "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": { - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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.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 } - }, - "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 } - }, - "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", - "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-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", - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } + "modalities": { + "input": ["text", "image"], + "output": ["text"] }, - "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 } - }, - "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 } - } - } - }, - "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-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": { - "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-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-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-03-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 } - }, - "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-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-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-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-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-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-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-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-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-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 } - } - } - }, - "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.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 } - }, - "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.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 } - }, - "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" } - }, - "glm-5": { - "id": "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 }, - "provider": { "npm": "@ai-sdk/openai-compatible" } - }, - "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" } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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": 32768, + "output": 8192 }, - "limit": { "context": 1048576, "output": 65535 } + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "llama-3.3-70b-versatile": { - "id": "llama-3.3-70b-versatile", - "name": "Meta Llama 3.3 70B Versatile", - "family": "llama", + "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, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "codex-mini-latest": { - "id": "codex-mini-latest", - "name": "OpenAI Codex Mini Latest", - "family": "gpt-codex-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": 1.5, "output": 6, "cache_read": 0.375 }, - "limit": { "context": 200000, "output": 100000 } - }, - "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 } - }, - "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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.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"] }, + "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 } + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.02, + "output": 0.04 + } }, - "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": { - "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": { - "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-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 } - }, - "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 } - } - } - }, - "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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "deepinfra": { - "id": "deepinfra", - "env": ["DEEPINFRA_API_KEY"], - "npm": "@ai-sdk/deepinfra", - "name": "Deep Infra", - "doc": "https://deepinfra.com/models", - "models": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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.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-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.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-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.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 } - }, - "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.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 } - }, - "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 } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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.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 } - }, - "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-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 } - } - } - }, - "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-pro": { - "id": "mimo-v2-pro", - "name": "MiMo-V2-Pro", - "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"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 1, "output": 3, "cache_read": 0.2 }, - "limit": { "context": 1000000, "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": true, - "cost": { "input": 0.4, "output": 2, "cache_read": 0.08 }, - "limit": { "context": 256000, "output": 128000 } - }, - "mimo-v2-flash": { - "id": "mimo-v2-flash", - "name": "MiMo-V2-Flash", + "XiaomiMiMo/MiMo-V2-Flash": { + "id": "XiaomiMiMo/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"] }, + "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, "cache_read": 0.01 }, - "limit": { "context": 256000, "output": 64000 } - } - } - }, - "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": { - "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, - "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 } + "limit": { + "context": 262144, + "output": 32000 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } }, - "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, - "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 } - }, - "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 } - }, - "meta.llama3-1-405b-instruct-v1:0": { - "id": "meta.llama3-1-405b-instruct-v1:0", - "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": 2.4, "output": 2.4 }, - "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": "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 } - }, - "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", - "release_date": "2026-02-17", - "last_updated": "2026-03-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": 1000000, "output": 64000 } - }, - "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 } - }, - "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 } - }, - "us.anthropic.claude-sonnet-4-20250514-v1:0": { - "id": "us.anthropic.claude-sonnet-4-20250514-v1:0", - "name": "Claude Sonnet 4 (US)", - "family": "claude-sonnet", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "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 } - }, - "meta.llama3-3-70b-instruct-v1:0": { - "id": "meta.llama3-3-70b-instruct-v1:0", + "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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.72, "output": 0.72 }, - "limit": { "context": 128000, "output": 4096 } - }, - "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, - "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 } - }, - "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 } - }, - "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, - "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 } - }, - "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 } - }, - "anthropic.claude-3-5-sonnet-20240620-v1:0": { - "id": "anthropic.claude-3-5-sonnet-20240620-v1:0", - "name": "Claude Sonnet 3.5", - "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, "cache_read": 0.3, "cache_write": 3.75 }, - "limit": { "context": 200000, "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, - "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 } - }, - "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, - "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 } - }, - "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, - "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 } - }, - "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, - "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 } - }, - "anthropic.claude-3-5-sonnet-20241022-v2:0": { - "id": "anthropic.claude-3-5-sonnet-20241022-v2:0", - "name": "Claude Sonnet 3.5 v2", - "family": "claude-sonnet", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "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 } - }, - "deepseek.v3-v1:0": { - "id": "deepseek.v3-v1:0", - "name": "DeepSeek-V3.1", - "family": "deepseek", - "attachment": false, - "reasoning": true, - "tool_call": 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 } - }, - "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 } - }, - "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 } - }, - "meta.llama3-2-1b-instruct-v1:0": { - "id": "meta.llama3-2-1b-instruct-v1:0", - "name": "Llama 3.2 1B 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"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.1, "output": 0.1 }, - "limit": { "context": 131000, "output": 4096 } - }, - "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, - "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 } - }, - "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, - "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 } - }, - "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 } - }, - "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 } - }, - "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", - "release_date": "2026-02-17", - "last_updated": "2026-03-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": 1000000, "output": 64000 } - }, - "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, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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, - "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 } - }, - "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, - "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.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, - "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 } - }, - "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 } - }, - "qwen.qwen3-32b-v1:0": { - "id": "qwen.qwen3-32b-v1:0", - "name": "Qwen3 32B (dense)", - "family": "qwen", - "attachment": false, - "reasoning": true, - "tool_call": 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 } - }, - "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, - "temperature": true, - "knowledge": "2025-05", - "release_date": "2026-02-05", - "last_updated": "2026-03-18", - "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-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, - "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 } - }, - "meta.llama3-2-11b-instruct-v1:0": { - "id": "meta.llama3-2-11b-instruct-v1:0", - "name": "Llama 3.2 11B 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.16, "output": 0.16 }, - "limit": { "context": 128000, "output": 4096 } - }, - "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, - "temperature": true, - "knowledge": "2025-05", - "release_date": "2026-02-05", - "last_updated": "2026-03-18", - "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 } - }, - "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, - "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-20250514-v1:0": { - "id": "anthropic.claude-sonnet-4-20250514-v1:0", - "name": "Claude Sonnet 4", - "family": "claude-sonnet", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "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 } - }, - "mistral.ministral-3-3b-instruct": { - "id": "mistral.ministral-3-3b-instruct", - "name": "Ministral 3 3B", - "family": "ministral", - "attachment": false, - "reasoning": false, - "tool_call": 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 } - }, - "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 } - }, - "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, - "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 } - }, - "mistral.magistral-small-2509": { - "id": "mistral.magistral-small-2509", - "name": "Magistral Small 1.2", - "family": "magistral", - "attachment": false, - "reasoning": true, - "tool_call": 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 } - }, - "us.anthropic.claude-opus-4-20250514-v1:0": { - "id": "us.anthropic.claude-opus-4-20250514-v1:0", - "name": "Claude Opus 4 (US)", - "family": "claude-opus", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "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 } - }, - "eu.anthropic.claude-sonnet-4-20250514-v1:0": { - "id": "eu.anthropic.claude-sonnet-4-20250514-v1:0", - "name": "Claude Sonnet 4 (EU)", - "family": "claude-sonnet", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "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 } - }, - "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, - "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 } - }, - "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 } - }, - "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, - "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 } - }, - "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, - "temperature": true, - "knowledge": "2025-05", - "release_date": "2026-02-05", - "last_updated": "2026-03-18", - "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-7-sonnet-20250219-v1:0": { - "id": "anthropic.claude-3-7-sonnet-20250219-v1:0", - "name": "Claude Sonnet 3.7", - "family": "claude-sonnet", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "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": 8192 } - }, - "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, - "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 } - }, - "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, - "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 } - }, - "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 } - }, - "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, - "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 } - }, - "meta.llama3-2-90b-instruct-v1:0": { - "id": "meta.llama3-2-90b-instruct-v1:0", - "name": "Llama 3.2 90B 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.72, "output": 0.72 }, - "limit": { "context": 128000, "output": 4096 } - }, - "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, - "temperature": true, - "knowledge": "2025-05", - "release_date": "2026-02-05", - "last_updated": "2026-03-18", - "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-5-haiku-20241022-v1:0": { - "id": "anthropic.claude-3-5-haiku-20241022-v1:0", - "name": "Claude Haiku 3.5", - "family": "claude-haiku", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-07", - "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 } - }, - "meta.llama3-2-3b-instruct-v1:0": { - "id": "meta.llama3-2-3b-instruct-v1:0", - "name": "Llama 3.2 3B 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"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.15, "output": 0.15 }, - "limit": { "context": 131000, "output": 4096 } - }, - "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, - "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 } - }, - "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.ministral-3-14b-instruct": { - "id": "mistral.ministral-3-14b-instruct", - "name": "Ministral 14B 3.0", - "family": "ministral", - "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.2, "output": 0.2 }, - "limit": { "context": 128000, "output": 4096 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "anthropic.claude-3-haiku-20240307-v1:0": { - "id": "anthropic.claude-3-haiku-20240307-v1:0", - "name": "Claude Haiku 3", - "family": "claude-haiku", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-02", - "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 }, - "limit": { "context": 200000, "output": 4096 } - }, - "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, - "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 } - }, - "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 } - }, - "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 } - }, - "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, - "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 } - }, - "amazon.nova-premier-v1:0": { - "id": "amazon.nova-premier-v1:0", - "name": "Nova Premier", - "family": "nova", - "attachment": true, - "reasoning": true, - "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": 2.5, "output": 12.5 }, - "limit": { "context": 1000000, "output": 16384 } - }, - "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", - "release_date": "2026-02-17", - "last_updated": "2026-03-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": 1000000, "output": 64000 } - }, - "anthropic.claude-opus-4-20250514-v1:0": { - "id": "anthropic.claude-opus-4-20250514-v1:0", - "name": "Claude Opus 4", - "family": "claude-opus", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "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 } - }, - "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, - "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 } - }, - "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.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 } - }, - "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, - "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-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, - "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 } - }, - "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", - "release_date": "2026-02-17", - "last_updated": "2026-03-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": 1000000, "output": 64000 } - }, - "global.anthropic.claude-sonnet-4-20250514-v1:0": { - "id": "global.anthropic.claude-sonnet-4-20250514-v1:0", - "name": "Claude Sonnet 4 (Global)", - "family": "claude-sonnet", - "attachment": true, - "reasoning": true, - "tool_call": true, - "temperature": true, - "knowledge": "2024-04", - "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 } - } - } - }, - "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": { - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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.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-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-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-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 } - }, - "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 } - }, - "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.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 } - }, - "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-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 } - }, - "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 } - } - } - }, - "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-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 } - } - } - }, - "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": { - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } }, "deepseek-ai/DeepSeek-V3.1": { "id": "deepseek-ai/DeepSeek-V3.1", "name": "DeepSeek V3.1", "family": "deepseek", "attachment": false, - "reasoning": true, + "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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.5, "output": 1.5 }, - "limit": { "context": 164000, "output": 131000 } + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 1 + } }, "deepseek-ai/DeepSeek-V3-0324": { "id": "deepseek-ai/DeepSeek-V3-0324", @@ -38210,65 +78685,99 @@ "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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.77, "output": 0.77 }, - "limit": { "context": 164000, "output": 131000 } + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.25, + "output": 0.88 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 163840, + "output": 64000 + }, + "cost": { + "input": 0.5, + "output": 2.15 + } }, "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" - }, - "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 } - }, - "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": "2025-08", - "release_date": "2025-09-05", - "last_updated": "2026-03-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-12-03", + "last_updated": "2025-12-03", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.6, "output": 2.5 }, - "limit": { "context": 262144, "output": 262144 }, - "status": "deprecated" + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.26, + "output": 0.38 + } }, "moonshotai/Kimi-K2-Thinking": { "id": "moonshotai/Kimi-K2-Thinking", @@ -38277,1098 +78786,192 @@ "attachment": false, "reasoning": true, "tool_call": true, - "interleaved": { "field": "reasoning_content" }, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, "knowledge": "2024-08", "release_date": "2025-11-06", - "last_updated": "2026-03-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "last_updated": "2025-11-06", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.6, "output": 2.5 }, - "limit": { "context": 262144, "output": 262144 }, - "status": "deprecated" + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.45, + "output": 2.8 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 196608, + "output": 131072 + }, + "cost": { + "input": 0.28, + "output": 1.2 + } } } }, - "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", + "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": { - "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 } - }, - "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 } - }, - "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/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.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.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-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-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-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.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/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/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-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/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-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.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-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.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.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/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-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-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/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/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-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/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-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/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/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/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-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/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-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/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-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-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/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/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-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-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/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 } - }, - "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-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": { - "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/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 } - }, - "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 } - }, - "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-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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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", - "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-haiku-4.5": { - "id": "anthropic/claude-haiku-4.5", + "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, - "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"] }, + "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 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } }, - "anthropic/claude-sonnet-4.6": { - "id": "anthropic/claude-sonnet-4.6", + "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, - "interleaved": true, "temperature": true, - "knowledge": "2025-08", + "knowledge": "2025-08-31", "release_date": "2026-02-17", - "last_updated": "2026-02-17", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "last_updated": "2026-03-13", + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] + }, "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + }, "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 } + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + }, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } }, - "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-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": { - "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-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-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-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.5-haiku": { - "id": "anthropic/claude-3.5-haiku", + "claude-3-5-haiku@20241022": { + "id": "claude-3-5-haiku@20241022", "name": "Claude Haiku 3.5", "family": "claude-haiku", "attachment": true, @@ -39378,13 +78981,78 @@ "knowledge": "2024-07-31", "release_date": "2024-10-22", "last_updated": "2024-10-22", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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 } + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } }, - "anthropic/claude-sonnet-4": { - "id": "anthropic/claude-sonnet-4", + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "claude-sonnet-4@20250514": { + "id": "claude-sonnet-4@20250514", "name": "Claude Sonnet 4", "family": "claude-sonnet", "attachment": true, @@ -39394,13 +79062,24 @@ "knowledge": "2025-03-31", "release_date": "2025-05-22", "last_updated": "2025-05-22", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } }, - "anthropic/claude-3.7-sonnet": { - "id": "anthropic/claude-3.7-sonnet", + "claude-3-7-sonnet@20250219": { + "id": "claude-3-7-sonnet@20250219", "name": "Claude Sonnet 3.7", "family": "claude-sonnet", "attachment": true, @@ -39410,13 +79089,24 @@ "knowledge": "2024-10-31", "release_date": "2025-02-19", "last_updated": "2025-02-19", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } }, - "anthropic/claude-opus-4.1": { - "id": "anthropic/claude-opus-4.1", + "claude-opus-4@20250514": { + "id": "claude-opus-4@20250514", "name": "Claude Opus 4", "family": "claude-opus", "attachment": true, @@ -39426,2461 +79116,480 @@ "knowledge": "2025-03-31", "release_date": "2025-05-22", "last_updated": "2025-05-22", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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 } + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } }, - "anthropic/claude-3-opus": { - "id": "anthropic/claude-3-opus", - "name": "Claude Opus 3", + "claude-opus-4-5@20251101": { + "id": "claude-opus-4-5@20251101", + "name": "Claude Opus 4.5", "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 } - }, - "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 } - }, - "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 } - }, - "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-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"] }, + "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": 0.28, "output": 0.42, "cache_read": 0.03 }, - "limit": { "context": 128000, "output": 64000 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } }, - "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.2-exp": { - "id": "deepseek/deepseek-v3.2-exp", - "name": "DeepSeek V3.2 Exp", - "family": "deepseek", - "attachment": false, + "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-09", + "knowledge": "2025-07-31", "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-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-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 } - }, - "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 } - }, - "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.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.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-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-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.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-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.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-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 } - }, - "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-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-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.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.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.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-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-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-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-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.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-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-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-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-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-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 } - }, - "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-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-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 } - }, - "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-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 } - }, - "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 } - }, - "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/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-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-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 } + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] }, - "limit": { "context": 1000000, "output": 64000 } - }, - "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 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } }, - "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", + "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-01", - "release_date": "2025-09-25", - "last_updated": "2025-09-25", - "modalities": { "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] }, + "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": 0.3, "output": 2.5, "cache_read": 0.03, "cache_write": 0.383 }, - "limit": { "context": 1048576, "output": 65536 } + "limit": { + "context": 1000000, + "output": 128000 + }, + "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 + }, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } }, - "google/text-multilingual-embedding-002": { - "id": "google/text-multilingual-embedding-002", - "name": "Text Multilingual Embedding 002", + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "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 + }, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + } + } + }, + "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, + "limit": { + "context": 100000, + "output": 100000 + }, + "cost": { + "input": 0.24, + "output": 0.94 + } + }, + "Qwen/Qwen3-Embedding-8B": { + "id": "Qwen/Qwen3-Embedding-8B", + "name": "Qwen3 Embedding 8B", "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-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.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-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/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/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-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-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/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-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/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 } - }, - "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.075, "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.31 }, - "limit": { "context": 1048576, "output": 65536 } - }, - "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 } - }, - "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-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-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-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 } - }, - "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": { - "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-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 } - }, - "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 } - }, - "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-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-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-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-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-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-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-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-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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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"] }, + "release_date": "2025-07-30", + "last_updated": "2025-07-30", + "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 } + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0.12, + "output": 0.12 + } }, - "minimax/minimax-m2.1": { - "id": "minimax/minimax-m2.1", - "name": "MiniMax M2.1", - "family": "minimax", + "Qwen/Qwen3-30B-A3B-Instruct-2507-FP8": { + "id": "Qwen/Qwen3-30B-A3B-Instruct-2507-FP8", + "name": "Qwen3 30B 2507", + "family": "qwen", "attachment": false, - "reasoning": true, + "reasoning": false, "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.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"] }, + "release_date": "2025-07-30", + "last_updated": "2025-07-30", + "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": 131000 } + "limit": { + "context": 64000, + "output": 64000 + }, + "cost": { + "input": 0.35, + "output": 1.42 + } }, - "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.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.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 } - }, - "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 } - }, - "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 } - }, - "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.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-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-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-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": { - "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" - }, - "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/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/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/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-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-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-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-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-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-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-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-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-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-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/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/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-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-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 } - }, - "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/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-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 } - }, - "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-small": { - "id": "mistral/devstral-small", - "name": "Devstral Small 1.1", + "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, - "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/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/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-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/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/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/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/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/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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 0.15 }, - "limit": { "context": 128000, "output": 128000 } + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.12, + "output": 0.47 + } }, - "mistral/codestral": { - "id": "mistral/codestral", - "name": "Codestral (latest)", - "family": "codestral", + "mistralai/Voxtral-Small-24B-2507": { + "id": "mistralai/Voxtral-Small-24B-2507", + "name": "Voxtral Small 24B", + "family": "voxtral", "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"] }, + "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.3, "output": 0.9 }, - "limit": { "context": 256000, "output": 4096 } + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.00236, + "output": 0.00236, + "output_audio": 2.36 + } }, - "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/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/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/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/magistral-small": { - "id": "mistral/magistral-small", - "name": "Magistral Small", + "mistralai/Magistral-Small-2509": { + "id": "mistralai/Magistral-Small-2509", + "name": "Magistral Small 1.2 24B", "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"] }, + "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.5, "output": 1.5 }, - "limit": { "context": 128000, "output": 128000 } + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.59, + "output": 2.36 + } }, - "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/mixtral-8x22b-instruct": { - "id": "mistral/mixtral-8x22b-instruct", - "name": "Mixtral 8x22B", - "family": "mixtral", + "microsoft/Phi-4-multimodal-instruct": { + "id": "microsoft/Phi-4-multimodal-instruct", + "name": "Phi-4 15B", + "family": "phi", "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"] }, + "tool_call": false, + "release_date": "2025-01-01", + "last_updated": "2025-01-01", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 2, "output": 6 }, - "limit": { "context": 64000, "output": 64000 } + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.24, + "output": 0.47 + } }, - "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-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", + "KBLab/kb-whisper-large": { + "id": "KBLab/kb-whisper-large", + "name": "KB Whisper", + "family": "whisper", "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 } + "tool_call": false, + "release_date": "2024-10-01", + "last_updated": "2024-10-01", + "modalities": { + "input": ["audio"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 448, + "output": 448 + }, + "cost": { + "input": 0.00236, + "output": 0.00236, + "output_audio": 2.36 + } }, - "meta/llama-3.2-3b": { - "id": "meta/llama-3.2-3b", - "name": "Llama 3.2 3B Instruct", + "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, - "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 } + "release_date": "2024-12-01", + "last_updated": "2024-12-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 1.18, + "output": 1.18 + } }, - "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-1b": { - "id": "meta/llama-3.2-1b", - "name": "Llama 3.2 1B Instruct", - "family": "llama", + "openai/whisper-large-v3": { + "id": "openai/whisper-large-v3", + "name": "Whisper 3 Large", + "family": "whisper", "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.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"] }, + "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": 128000, "output": 4096 } + "limit": { + "context": 448, + "output": 4096 + }, + "cost": { + "input": 0.00236, + "output": 0.00236, + "output_audio": 2.36 + } }, - "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 } - }, - "inception/mercury-2": { - "id": "inception/mercury-2", - "name": "Mercury 2", - "family": "mercury", + "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": "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 } + "release_date": "2025-08-05", + "last_updated": "2025-08-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.24, + "output": 0.94 + } }, - "inception/mercury-coder-small": { - "id": "inception/mercury-coder-small", - "name": "Mercury Coder Small Beta", - "family": "mercury", + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.47, + "output": 5.9 + } + }, + "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": true, - "temperature": true, - "knowledge": "2024-10", - "release_date": "2025-02-26", - "last_updated": "2025-02-26", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 1 }, - "limit": { "context": 32000, "output": 16384 } + "tool_call": false, + "release_date": "2024-06-01", + "last_updated": "2024-06-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 512, + "output": 512 + }, + "cost": { + "input": 0.12, + "output": 0.12 + } } } }, @@ -41892,54 +79601,30 @@ "name": "Synthetic", "doc": "https://synthetic.new/pricing", "models": { - "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: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-Thinking": { - "id": "hf:moonshotai/Kimi-K2-Thinking", - "name": "Kimi K2 Thinking", - "family": "kimi-thinking", + "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": "2025-11", - "release_date": "2025-11-07", - "last_updated": "2025-11-07", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2023-12", + "release_date": "2024-07-23", + "last_updated": "2024-07-23", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.55, "output": 2.19 }, - "limit": { "context": 262144, "output": 262144 } + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 3, + "output": 3 + } }, "hf:meta-llama/Llama-4-Scout-17B-16E-Instruct": { "id": "hf:meta-llama/Llama-4-Scout-17B-16E-Instruct", @@ -41952,26 +79637,19 @@ "knowledge": "2024-08", "release_date": "2025-04-05", "last_updated": "2025-04-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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.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 } + "limit": { + "context": 328000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } }, "hf:meta-llama/Llama-3.3-70B-Instruct": { "id": "hf:meta-llama/Llama-3.3-70B-Instruct", @@ -41984,14 +79662,23 @@ "knowledge": "2023-12", "release_date": "2024-12-06", "last_updated": "2024-12-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.9, "output": 0.9 }, - "limit": { "context": 128000, "output": 32768 } + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.9, + "output": 0.9 + } }, - "hf:meta-llama/Llama-3.1-405B-Instruct": { - "id": "hf:meta-llama/Llama-3.1-405B-Instruct", - "name": "Llama-3.1-405B-Instruct", + "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, @@ -42000,10 +79687,19 @@ "knowledge": "2023-12", "release_date": "2024-07-23", "last_updated": "2024-07-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 3, "output": 3 }, - "limit": { "context": 128000, "output": 32768 } + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } }, "hf:meta-llama/Llama-3.1-70B-Instruct": { "id": "hf:meta-llama/Llama-3.1-70B-Instruct", @@ -42016,10 +79712,19 @@ "knowledge": "2023-12", "release_date": "2024-07-23", "last_updated": "2024-07-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.9, "output": 0.9 }, - "limit": { "context": 128000, "output": 32768 } + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.9, + "output": 0.9 + } }, "hf:meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8": { "id": "hf:meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", @@ -42032,218 +79737,19 @@ "knowledge": "2024-08", "release_date": "2025-04-05", "last_updated": "2025-04-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.22, "output": 0.88 }, - "limit": { "context": 524000, "output": 4096 } - }, - "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-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.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: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-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-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: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": { - "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: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: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: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 } + "limit": { + "context": 524000, + "output": 4096 + }, + "cost": { + "input": 0.22, + "output": 0.88 + } }, "hf:MiniMaxAI/MiniMax-M2": { "id": "hf:MiniMaxAI/MiniMax-M2", @@ -42255,25 +79761,105 @@ "temperature": true, "release_date": "2025-10-27", "last_updated": "2025-10-27", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.55, "output": 2.19 }, - "limit": { "context": 196608, "output": 131000 } + "limit": { + "context": 196608, + "output": 131000 + }, + "cost": { + "input": 0.55, + "output": 2.19 + } }, - "hf:openai/gpt-oss-120b": { - "id": "hf:openai/gpt-oss-120b", - "name": "GPT OSS 120B", - "family": "gpt-oss", + "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": "2025-08-05", - "last_updated": "2025-08-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-02-07", + "last_updated": "2026-02-07", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.1, "output": 0.1 }, - "limit": { "context": 128000, "output": 32768 } + "limit": { + "context": 191488, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.6 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.55, + "output": 2.19 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "status": "beta", + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.6 + } }, "hf:Qwen/Qwen2.5-Coder-32B-Instruct": { "id": "hf:Qwen/Qwen2.5-Coder-32B-Instruct", @@ -42286,42 +79872,19 @@ "knowledge": "2024-10", "release_date": "2024-11-11", "last_updated": "2024-11-11", - "modalities": { "input": ["text"], "output": ["text"] }, + "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-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 } + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.8, + "output": 0.8 + } }, "hf:Qwen/Qwen3-235B-A22B-Instruct-2507": { "id": "hf:Qwen/Qwen3-235B-A22B-Instruct-2507", @@ -42334,6099 +79897,295 @@ "knowledge": "2025-04", "release_date": "2025-04-28", "last_updated": "2025-07-21", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.2, "output": 0.6 }, - "limit": { "context": 256000, "output": 32000 } - } - } - }, - "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-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": true, - "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.18 }, - "limit": { "context": 400000, "output": 128000 } - }, - "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, - "structured_output": true, - "temperature": true, - "release_date": "2025-07-31", - "last_updated": "2025-07-31", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.1, "output": 0.3 }, - "limit": { "context": 262000, "output": 8192 } - }, - "gemini-2.5-flash-lite": { - "id": "gemini-2.5-flash-lite", - "name": "Gemini 2.5 Flash Lite", - "family": "gemini", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-07-22", - "last_updated": "2025-07-22", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.1, "output": 0.4, "cache_read": 0.01 }, - "limit": { "context": 1048576, "output": 65535 } - }, - "grok-4-20-multi-agent-beta-0309": { - "id": "grok-4-20-multi-agent-beta-0309", - "name": "Grok 4.20 Multi-Agent Beta (0309)", - "family": "grok", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": 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 }, - "limit": { "context": 2000000, "output": 30000 } - }, - "grok-imagine-image": { - "id": "grok-imagine-image", - "name": "Grok Imagine Image", - "family": "grok", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2026-03-02", - "last_updated": "2026-03-02", - "modalities": { "input": ["text", "image"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "gpt-5.1-codex-mini": { - "id": "gpt-5.1-codex-mini", - "name": "GPT-5.1 Codex mini", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-11-12", - "last_updated": "2025-11-12", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 2, "cache_read": 0.03 }, - "limit": { "context": 400000, "output": 128000 } - }, - "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-21", - "last_updated": "2025-07-21", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.6 }, - "limit": { "context": 262000, "output": 8192 }, - "status": "beta" - }, - "gpt-5.4-pro": { - "id": "gpt-5.4-pro", - "name": "GPT-5.4 Pro", - "family": "gpt", - "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"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 30, "output": 180 }, - "limit": { "context": 1050000, "output": 128000 } - }, - "claude-opus-4-5-20251101": { - "id": "claude-opus-4-5-20251101", - "name": "Claude Opus 4.5", - "family": "claude", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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 }, - "limit": { "context": 200000, "output": 32000 } - }, - "qwen-image": { - "id": "qwen-image", - "name": "Qwen Image", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-08-04", - "last_updated": "2025-08-04", - "modalities": { "input": ["text"], "output": ["text", "image"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "hermes-2-pro-llama-3-8b": { - "id": "hermes-2-pro-llama-3-8b", - "name": "Hermes 2 Pro Llama 3 8B", - "family": "nousresearch", - "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 }, - "status": "beta" - }, - "pixtral-large-latest": { - "id": "pixtral-large-latest", - "name": "Pixtral Large Latest", - "family": "mistral", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2024-11-18", - "last_updated": "2024-11-18", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 4, "output": 12 }, - "limit": { "context": 128000, "output": 16384 } - }, - "o3-mini": { - "id": "o3-mini", - "name": "o3 Mini", - "family": "gpt", - "attachment": false, - "reasoning": true, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-06-01", - "last_updated": "2025-06-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.1, "output": 4.4, "cache_read": 0.55 }, - "limit": { "context": 200000, "output": 16384 } - }, - "gpt-5.4-mini": { - "id": "gpt-5.4-mini", - "name": "GPT-5.4 Mini", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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.08 }, - "limit": { "context": 400000, "output": 128000 } - }, - "gpt-5-pro": { - "id": "gpt-5-pro", - "name": "GPT-5 Pro", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-08-01", - "last_updated": "2025-08-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 15, "output": 120 }, - "limit": { "context": 400000, "output": 272000 } - }, - "grok-4-fast": { - "id": "grok-4-fast", - "name": "Grok 4 Fast", - "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 } - }, - "qwen-turbo": { - "id": "qwen-turbo", - "name": "Qwen Turbo", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-02-01", - "last_updated": "2025-02-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.05, "output": 0.2 }, - "limit": { "context": 1000000, "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": 16384 } - }, - "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", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-09-25", - "last_updated": "2025-09-25", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.1, "output": 0.4, "cache_read": 0.01 }, - "limit": { "context": 1048576, "output": 65535 } - }, - "qwen-vl-max": { - "id": "qwen-vl-max", - "name": "Qwen VL Max", - "family": "qwen", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-02-01", - "last_updated": "2025-02-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.8, "output": 3.2 }, - "limit": { "context": 131072, "output": 32000 } - }, - "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-23", - "last_updated": "2025-09-23", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.5, "output": 2 }, - "limit": { "context": 131072, "output": 32768 } - }, - "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 } - }, - "kimi-k2-thinking": { - "id": "kimi-k2-thinking", - "name": "Kimi K2 Thinking", - "family": "kimi", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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": 262144, "output": 262144 } - }, - "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": "2024-01-01", - "last_updated": "2024-01-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.11, "output": 0.68, "cache_read": 0.06 }, - "limit": { "context": 262144, "output": 262144 } - }, - "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": true, - "cost": { "input": 1.6, "output": 6.4 }, - "limit": { "context": 131072, "output": 32000 } - }, - "gpt-5.2-chat-latest": { - "id": "gpt-5.2-chat-latest", - "name": "GPT-5.2 Chat", - "family": "gpt", - "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, - "cost": { "input": 1.75, "output": 14, "cache_read": 0.18 }, - "limit": { "context": 128000, "output": 16400 } - }, - "qwen-vl-plus": { - "id": "qwen-vl-plus", - "name": "Qwen VL Plus", - "family": "qwen", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-02-05", - "last_updated": "2025-02-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.21, "output": 0.64 }, - "limit": { "context": 131072, "output": 32000 } - }, - "qwen-max": { - "id": "qwen-max", - "name": "Qwen Max", - "family": "qwen", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-09-05", - "last_updated": "2025-09-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 1.6, "output": 6.4 }, - "limit": { "context": 131072, "output": 32000 } - }, - "glm-image": { - "id": "glm-image", - "name": "GLM-Image", - "family": "glm", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-01-14", - "last_updated": "2025-01-14", - "modalities": { "input": ["text"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "gpt-5": { - "id": "gpt-5", - "name": "GPT-5", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-08-01", - "last_updated": "2025-08-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.25, "output": 10, "cache_read": 0.13 }, - "limit": { "context": 400000, "output": 128000 } - }, - "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, - "structured_output": true, - "temperature": true, - "release_date": "2024-12-06", - "last_updated": "2024-12-06", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.13, "output": 0.4 }, - "limit": { "context": 128000, "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 } - }, - "claude-opus-4-20250514": { - "id": "claude-opus-4-20250514", - "name": "Claude Opus 4 (2025-05-14)", - "family": "claude", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": false, - "temperature": true, - "release_date": "2025-05-22", - "last_updated": "2025-05-22", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 15, "output": 75, "cache_read": 1.5 }, - "limit": { "context": 200000, "output": 16384 } - }, - "gemini-3.1-pro-preview": { - "id": "gemini-3.1-pro-preview", - "name": "Gemini 3.1 Pro (Preview)", - "family": "gemini", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2026-02-19", - "last_updated": "2026-02-19", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 2, "output": 12, "cache_read": 0.2 }, - "limit": { "context": 1048576, "output": 65536 } - }, - "devstral-2512": { - "id": "devstral-2512", - "name": "Devstral 2", - "family": "mistral", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "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": 16384 } - }, - "seedream-4-0": { - "id": "seedream-4-0", - "name": "Seedream 4.0", - "family": "seed", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-09-16", - "last_updated": "2025-09-16", - "modalities": { "input": ["text"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "claude-3-7-sonnet-20250219": { - "id": "claude-3-7-sonnet-20250219", - "name": "Claude 3.7 Sonnet (2025-02-19)", - "family": "claude", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": false, - "temperature": true, - "release_date": "2025-02-19", - "last_updated": "2025-02-19", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 3, "output": 15, "cache_read": 0.3 }, - "limit": { "context": 200000, "output": 8192 } - }, - "kimi-k2.5": { - "id": "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-26", - "last_updated": "2026-01-26", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.6, "output": 3, "cache_read": 0.1 }, - "limit": { "context": 262144, "output": 32768 } - }, - "gemma-3n-e2b-it": { - "id": "gemma-3n-e2b-it", - "name": "Gemma 3n E2B IT", - "family": "gemma", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-06-26", - "last_updated": "2025-06-26", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.08, "output": 0.3 }, - "limit": { "context": 1000000, "output": 16384 } - }, - "llama-guard-4-12b": { - "id": "llama-guard-4-12b", - "name": "Llama Guard 4 12B", - "family": "llama", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-04-30", - "last_updated": "2025-04-30", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.2 }, - "limit": { "context": 131072, "output": 16384 } - }, - "gpt-4-turbo": { - "id": "gpt-4-turbo", - "name": "GPT-4 Turbo", - "family": "gpt", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2023-11-06", - "last_updated": "2023-11-06", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 10, "output": 30 }, - "limit": { "context": 128000, "output": 16384 } - }, - "qwen-image-max": { - "id": "qwen-image-max", - "name": "Qwen Image Max", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-08-04", - "last_updated": "2025-08-04", - "modalities": { "input": ["text"], "output": ["text", "image"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "mistral-large-latest": { - "id": "mistral-large-latest", - "name": "Mistral Large Latest", - "family": "mistral", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-12-02", - "last_updated": "2025-12-02", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 4, "output": 12 }, - "limit": { "context": 128000, "output": 16384 } - }, - "qwq-plus": { - "id": "qwq-plus", - "name": "QwQ Plus", - "family": "qwen", - "attachment": false, - "reasoning": true, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-03-06", - "last_updated": "2025-03-06", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.8, "output": 2.4 }, - "limit": { "context": 131072, "output": 8192 } - }, - "gpt-4o": { - "id": "gpt-4o", - "name": "GPT-4o", - "family": "gpt", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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 } - }, - "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": "2025-10-10", - "last_updated": "2025-10-10", - "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 } - }, - "glm-4.7-flash": { - "id": "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": "2025-12-22", - "last_updated": "2025-12-22", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 200000, "output": 128000 } - }, - "grok-4": { - "id": "grok-4", - "name": "Grok 4", - "family": "grok", - "attachment": true, - "reasoning": false, - "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": 3, "output": 15 }, - "limit": { "context": 256000, "output": 256000 } - }, - "grok-code-fast-1": { - "id": "grok-code-fast-1", - "name": "Grok Code Fast 1", - "family": "grok", - "attachment": false, - "reasoning": false, - "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": false, - "cost": { "input": 0.2, "output": 1.5 }, - "limit": { "context": 256000, "output": 10000 } - }, - "grok-4-20-beta-0309-non-reasoning": { - "id": "grok-4-20-beta-0309-non-reasoning", - "name": "Grok 4.20 Beta Non-Reasoning (0309)", - "family": "grok", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": 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 }, - "limit": { "context": 2000000, "output": 30000 } - }, - "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": true, - "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.18 }, - "limit": { "context": 400000, "output": 128000 } - }, - "qwen-plus-latest": { - "id": "qwen-plus-latest", - "name": "Qwen Plus Latest", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2024-09-09", - "last_updated": "2024-09-09", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.4, "output": 1.2, "cache_read": 0.08 }, - "limit": { "context": 1000000, "output": 32000 } - }, - "gemma-3-4b-it": { - "id": "gemma-3-4b-it", - "name": "Gemma 3 4B IT", - "family": "gemma", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-03-10", - "last_updated": "2025-03-10", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.08, "output": 0.3 }, - "limit": { "context": 1000000, "output": 16384 } - }, - "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": 16384 } - }, - "kimi-k2-thinking-turbo": { - "id": "kimi-k2-thinking-turbo", - "name": "Kimi K2 Thinking Turbo", - "family": "kimi", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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": 262144, "output": 262144 } - }, - "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": 16384 } - }, - "gpt-5-mini": { - "id": "gpt-5-mini", - "name": "GPT-5 Mini", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-08-01", - "last_updated": "2025-08-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 2, "cache_read": 0.03 }, - "limit": { "context": 400000, "output": 128000 } - }, - "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": false, - "cost": { "input": 0.25, "output": 2, "cache_read": 0.05 }, - "limit": { "context": 256000, "output": 16384 } - }, - "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-30", - "last_updated": "2025-07-30", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.1, "output": 0.3 }, - "limit": { "context": 262000, "output": 8192 } - }, - "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": false, - "cost": { "input": 1, "output": 3, "cache_read": 0.5 }, - "limit": { "context": 131072, "output": 16384 } - }, - "claude-opus-4-6": { - "id": "claude-opus-4-6", - "name": "Claude Opus 4.6", - "family": "claude", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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 }, - "limit": { "context": 1000000, "output": 128000 } - }, - "qwen-image-edit-plus": { - "id": "qwen-image-edit-plus", - "name": "Qwen Image Edit Plus", - "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", "image"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "claude-sonnet-4-5-20250929": { - "id": "claude-sonnet-4-5-20250929", - "name": "Claude Sonnet 4.5 (2025-09-29)", - "family": "claude", - "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": false, - "cost": { "input": 3, "output": 15, "cache_read": 0.3 }, - "limit": { "context": 200000, "output": 64000 } - }, - "gpt-4o-mini": { - "id": "gpt-4o-mini", - "name": "GPT-4o Mini", - "family": "gpt", - "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": false, - "cost": { "input": 0.15, "output": 0.6, "cache_read": 0.08 }, - "limit": { "context": 128000, "output": 16384 } - }, - "mistral-small-2506": { - "id": "mistral-small-2506", - "name": "Mistral Small 3.2", - "family": "mistral", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "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 } - }, - "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-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": 65536 } - }, - "gemma-3n-e4b-it": { - "id": "gemma-3n-e4b-it", - "name": "Gemma 3n E4B IT", - "family": "gemma", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-06-26", - "last_updated": "2025-06-26", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.08, "output": 0.3 }, - "limit": { "context": 1000000, "output": 16384 } - }, - "qwen-plus": { - "id": "qwen-plus", - "name": "Qwen Plus", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-01-25", - "last_updated": "2025-01-25", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.4, "output": 1.2, "cache_read": 0.08 }, - "limit": { "context": 131072, "output": 32000 } - }, - "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 } - }, - "claude-sonnet-4-6": { - "id": "claude-sonnet-4-6", - "name": "Claude Sonnet 4.6", - "family": "claude", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2026-02-17", - "last_updated": "2026-02-17", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 3, "output": 15, "cache_read": 0.3 }, - "limit": { "context": 200000, "output": 64000 } - }, - "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, - "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": 1000000, "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, - "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" - }, - "qwen-image-plus": { - "id": "qwen-image-plus", - "name": "Qwen Image Plus", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-08-04", - "last_updated": "2025-08-04", - "modalities": { "input": ["text"], "output": ["text", "image"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "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 } - }, - "minimax-m2": { - "id": "minimax-m2", - "name": "MiniMax M2", - "family": "minimax", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-10-27", - "last_updated": "2025-10-27", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 1, "cache_read": 0.03 }, - "limit": { "context": 196608, "output": 131072 } - }, - "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": false, - "cost": { "input": 0.07, "output": 0.3, "cache_read": 0.02 }, - "limit": { "context": 256000, "output": 16384 } - }, - "gpt-3.5-turbo": { - "id": "gpt-3.5-turbo", - "name": "GPT-3.5 Turbo", - "family": "gpt", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2022-11-30", - "last_updated": "2022-11-30", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.5, "output": 1.5 }, - "limit": { "context": 16385, "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-15", - "last_updated": "2025-10-15", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.05, "output": 0.4, "cache_read": 0.01 }, - "limit": { "context": 262144, "output": 32768 } - }, - "sonar": { - "id": "sonar", - "name": "Sonar", - "family": "sonar", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-01-01", - "last_updated": "2025-01-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1, "output": 1 }, - "limit": { "context": 130000, "output": 16384 } - }, - "qwen3-30b-a3b-fp8": { - "id": "qwen3-30b-a3b-fp8", - "name": "Qwen3 30B A3B FP8", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-04-28", - "last_updated": "2025-04-28", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.09, "output": 0.45 }, - "limit": { "context": 40960, "output": 20000 } - }, - "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 } - }, - "minimax-text-01": { - "id": "minimax-text-01", - "name": "MiniMax Text 01", - "family": "minimax", - "attachment": false, - "reasoning": false, - "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 } - }, - "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" - }, - "gemini-2.0-flash-lite": { - "id": "gemini-2.0-flash-lite", - "name": "Gemini 2.0 Flash Lite", - "family": "gemini", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-02-25", - "last_updated": "2025-02-25", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.08, "output": 0.3 }, - "limit": { "context": 1048576, "output": 8192 }, - "status": "deprecated" - }, - "gpt-5.4": { - "id": "gpt-5.4", - "name": "GPT-5.4", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2026-03-06", - "last_updated": "2026-03-06", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 2.5, "output": 15, "cache_read": 0.25 }, - "limit": { "context": 1050000, "output": 128000 } - }, - "o1": { - "id": "o1", - "name": "o1", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2024-09-12", - "last_updated": "2024-09-12", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 15, "output": 60, "cache_read": 7.5 }, - "limit": { "context": 200000, "output": 16384 } - }, - "o3": { - "id": "o3", - "name": "o3", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-06-01", - "last_updated": "2025-06-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 2, "output": 8, "cache_read": 0.5 }, - "limit": { "context": 200000, "output": 16384 } - }, - "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": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-02-19", - "last_updated": "2025-02-19", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 1.4, "output": 4.2 }, - "limit": { "context": 131072, "output": 32768 } - }, - "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 } - }, - "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": "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 } - }, - "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 } - }, - "gpt-5.3-chat-latest": { - "id": "gpt-5.3-chat-latest", - "name": "GPT-5.3 Chat", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": false, - "temperature": true, - "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.18 }, - "limit": { "context": 128000, "output": 16384 } - }, - "glm-4.5": { - "id": "glm-4.5", - "name": "GLM-4.5", - "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": 0.6, "output": 2.2, "cache_read": 0.11 }, - "limit": { "context": 128000, "output": 16384 } - }, - "minimax-m2.1": { - "id": "minimax-m2.1", - "name": "MiniMax M2.1", - "family": "minimax", - "attachment": false, - "reasoning": true, - "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": true, - "cost": { "input": 0.27, "output": 1.1 }, - "limit": { "context": 196608, "output": 131072 } - }, - "glm-4.7-flashx": { - "id": "glm-4.7-flashx", - "name": "GLM-4.7 FlashX", - "family": "glm", - "attachment": false, - "reasoning": true, - "tool_call": true, - "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.07, "output": 0.4, "cache_read": 0.01 }, - "limit": { "context": 200000, "output": 128000 } - }, - "sonar-reasoning-pro": { - "id": "sonar-reasoning-pro", - "name": "Sonar Reasoning Pro", - "family": "sonar", - "attachment": false, - "reasoning": true, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-03-07", - "last_updated": "2025-03-07", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 2, "output": 8 }, - "limit": { "context": 128000, "output": 16384 } - }, - "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 } - }, - "veo-3.1-fast-generate-preview": { - "id": "veo-3.1-fast-generate-preview", - "name": "Veo 3.1 Fast", - "family": "gemini", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2026-03-14", - "last_updated": "2026-03-14", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 32768, "output": 1 }, - "status": "beta" - }, - "claude-3-haiku-20240307": { - "id": "claude-3-haiku-20240307", - "name": "Claude 3 Haiku (2024-03-07)", - "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": 0.25, "output": 1.25, "cache_read": 0.03 }, - "limit": { "context": 200000, "output": 4096 } - }, - "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 } - }, - "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": 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.17, "output": 0.66 }, - "limit": { "context": 8192, "output": 2048 }, - "status": "beta" - }, - "qwen3-235b-a22b-fp8": { - "id": "qwen3-235b-a22b-fp8", - "name": "Qwen3 235B A22B FP8", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "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.2, "output": 0.8 }, - "limit": { "context": 40960, "output": 20000 } - }, - "claude-sonnet-4-20250514": { - "id": "claude-sonnet-4-20250514", - "name": "Claude Sonnet 4 (2025-05-14)", - "family": "claude", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": false, - "temperature": true, - "release_date": "2025-05-14", - "last_updated": "2025-05-14", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 3, "output": 15, "cache_read": 0.3 }, - "limit": { "context": 200000, "output": 16384 } - }, - "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 } - }, - "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 } - }, - "glm-4.6": { - "id": "glm-4.6", - "name": "GLM-4.6", - "family": "glm", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-09-30", - "last_updated": "2025-09-30", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.6, "output": 2.2, "cache_read": 0.11 }, - "limit": { "context": 200000, "output": 16384 } - }, - "gemini-3-flash-preview": { - "id": "gemini-3-flash-preview", - "name": "Gemini 3 Flash (Preview)", - "family": "gemini", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": 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, "cache_read": 0.05 }, - "limit": { "context": 1048576, "output": 65535 } - }, - "gpt-5.4-nano": { - "id": "gpt-5.4-nano", - "name": "GPT-5.4 Nano", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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 } - }, - "claude-3-5-sonnet": { - "id": "claude-3-5-sonnet", - "name": "Claude 3.5 Sonnet", - "family": "claude", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": false, - "temperature": true, - "release_date": "2024-06-20", - "last_updated": "2024-06-20", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 3, "output": 15, "cache_read": 0.3 }, - "limit": { "context": 200000, "output": 16384 } - }, - "glm-4.6v": { - "id": "glm-4.6v", - "name": "GLM-4.6V", - "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.3, "output": 0.9, "cache_read": 0.05 }, - "limit": { "context": 128000, "output": 16000 } - }, - "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": true, - "temperature": true, - "release_date": "2025-10-14", - "last_updated": "2025-10-14", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.08, "output": 0.5 }, - "limit": { "context": 131072, "output": 8192 } - }, - "gpt-4": { - "id": "gpt-4", - "name": "GPT-4", - "family": "gpt", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": false, - "temperature": true, - "release_date": "2023-03-14", - "last_updated": "2023-03-14", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 30, "output": 60 }, - "limit": { "context": 8192, "output": 8192 } - }, - "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": "2024-01-01", - "last_updated": "2024-01-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.3, "output": 1.2, "cache_read": 0.06 }, - "limit": { "context": 204800, "output": 131100 } - }, - "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, - "structured_output": true, - "temperature": true, - "release_date": "2025-01-31", - "last_updated": "2025-01-31", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.4, "output": 1.8 }, - "limit": { "context": 262000, "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 } - }, - "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, - "structured_output": false, - "temperature": true, - "release_date": "2025-09-10", - "last_updated": "2025-09-10", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.5, "output": 6 }, - "limit": { "context": 131072, "output": 32768 }, - "status": "beta" - }, - "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": false, - "temperature": true, - "release_date": "2025-10-05", - "last_updated": "2025-10-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.7 }, - "limit": { "context": 131072, "output": 32768 } - }, - "gemini-2.5-pro": { - "id": "gemini-2.5-pro", - "name": "Gemini 2.5 Pro", - "family": "gemini", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-03-25", - "last_updated": "2025-03-25", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.25, "output": 10, "cache_read": 0.13 }, - "limit": { "context": 1048576, "output": 65536 } - }, - "claude-opus-4-1-20250805": { - "id": "claude-opus-4-1-20250805", - "name": "Claude Opus 4.1", - "family": "claude", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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 }, - "limit": { "context": 200000, "output": 32000 } - }, - "gemini-2.5-flash": { - "id": "gemini-2.5-flash", - "name": "Gemini 2.5 Flash", - "family": "gemini", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-08-26", - "last_updated": "2025-08-26", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.3, "output": 2.5, "cache_read": 0.03 }, - "limit": { "context": 1048576, "output": 65535 } - }, - "sonar-pro": { - "id": "sonar-pro", - "name": "Sonar Pro", - "family": "sonar", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-03-07", - "last_updated": "2025-03-07", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 3, "output": 15 }, - "limit": { "context": 200000, "output": 16384 } - }, - "qwen3-235b-a22b-thinking-2507": { - "id": "qwen3-235b-a22b-thinking-2507", + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, - "structured_output": true, "temperature": true, + "knowledge": "2025-04", "release_date": "2025-07-25", "last_updated": "2025-07-25", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.2, "output": 0.6 }, - "limit": { "context": 262000, "output": 8192 }, - "status": "beta" + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0.65, + "output": 3 + } }, - "qwen-image-edit-max": { - "id": "qwen-image-edit-max", - "name": "Qwen Image Edit Max", - "family": "qwen", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2026-01-16", - "last_updated": "2026-01-16", - "modalities": { "input": ["text", "image"], "output": ["text", "image"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "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 } - }, - "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, - "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.18 }, - "limit": { "context": 400000, "output": 128000 } - }, - "qwen3-next-80b-a3b-instruct": { - "id": "qwen3-next-80b-a3b-instruct", - "name": "Qwen3 Next 80B A3B Instruct", + "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, - "structured_output": true, "temperature": true, - "release_date": "2025-09-10", - "last_updated": "2025-09-10", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-04", + "release_date": "2025-07-23", + "last_updated": "2025-07-23", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.5, "output": 2 }, - "limit": { "context": 129024, "output": 32768 } + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 2, + "output": 2 + } }, - "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 } - }, - "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": "2025-11-01", - "last_updated": "2025-11-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.25, "output": 10, "cache_read": 0.13 }, - "limit": { "context": 400000, "output": 128000 } - }, - "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 } - }, - "qwen3-vl-plus": { - "id": "qwen3-vl-plus", - "name": "Qwen3 VL Plus", - "family": "qwen", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-09-23", - "last_updated": "2025-09-23", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 1.6, "cache_read": 0.04 }, - "limit": { "context": 262144, "output": 32768 } - }, - "deepseek-v3.1": { - "id": "deepseek-v3.1", + "hf:deepseek-ai/DeepSeek-V3.1": { + "id": "hf:deepseek-ai/DeepSeek-V3.1", "name": "DeepSeek V3.1", "family": "deepseek", - "attachment": true, + "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", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.56, "output": 1.68, "cache_read": 0.11 }, - "limit": { "context": 128000, "output": 32768 } + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.56, + "output": 1.68 + } }, - "gemini-2.0-flash": { - "id": "gemini-2.0-flash", - "name": "Gemini 2.0 Flash", - "family": "gemini", + "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, - "structured_output": true, - "temperature": true, - "release_date": "2025-02-05", - "last_updated": "2025-02-05", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.1, "output": 0.4, "cache_read": 0.03 }, - "limit": { "context": 1048576, "output": 8192 }, - "status": "deprecated" - }, - "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 } - }, - "glm-4.5-flash": { - "id": "glm-4.5-flash", - "name": "GLM-4.5 Flash", - "family": "glm", - "attachment": false, - "reasoning": false, - "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": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 16384 } - }, - "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 }, - "status": "beta" - }, - "gpt-4.1-mini": { - "id": "gpt-4.1-mini", - "name": "GPT-4.1 Mini", - "family": "gpt", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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": 1000000, "output": 16384 } - }, - "qwen-image-max-2025-12-30": { - "id": "qwen-image-max-2025-12-30", - "name": "Qwen Image Max 2025-12-30", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-12-31", - "last_updated": "2025-12-31", - "modalities": { "input": ["text"], "output": ["text", "image"] }, - "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "cogview-4": { - "id": "cogview-4", - "name": "CogView-4", - "family": "glm", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-03-04", - "last_updated": "2025-03-04", - "modalities": { "input": ["text"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "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": 16384 }, - "status": "beta" - }, - "glm-5": { - "id": "glm-5", - "name": "GLM-5", - "family": "glm", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": 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": 202800, "output": 131100 } - }, - "veo-3.1-generate-preview": { - "id": "veo-3.1-generate-preview", - "name": "Veo 3.1", - "family": "gemini", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2026-03-14", - "last_updated": "2026-03-14", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 32768, "output": 1 }, - "status": "beta" - }, - "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-11", - "last_updated": "2025-10-11", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 1 }, - "limit": { "context": 131072, "output": 32768 } - }, - "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" - }, - "qwen-omni-turbo": { - "id": "qwen-omni-turbo", - "name": "Qwen Omni Turbo", - "family": "qwen", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-03-26", - "last_updated": "2025-03-26", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.8 }, - "limit": { "context": 32768, "output": 8192 } - }, - "gpt-5-chat-latest": { - "id": "gpt-5-chat-latest", - "name": "GPT-5 Chat Latest", - "family": "gpt", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, "temperature": true, "release_date": "2025-08-01", "last_updated": "2025-08-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.25, "output": 10, "cache_read": 0.13 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 1.2, + "output": 1.2 + } }, - "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 } - }, - "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 } - }, - "gpt-5-nano": { - "id": "gpt-5-nano", - "name": "GPT-5 Nano", - "family": "gpt", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-08-01", - "last_updated": "2025-08-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.05, "output": 0.4, "cache_read": 0.01 }, - "limit": { "context": 400000, "output": 128000 } - }, - "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": false, - "cost": { "input": 0.25, "output": 2, "cache_read": 0.05 }, - "limit": { "context": 256000, "output": 16384 } - }, - "qwen3-32b-fp8": { - "id": "qwen3-32b-fp8", - "name": "Qwen3 32B FP8", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "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.45 }, - "limit": { "context": 40960, "output": 20000 } - }, - "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" - }, - "mixtral-8x7b-instruct-together": { - "id": "mixtral-8x7b-instruct-together", - "name": "Mixtral 8x7B Instruct", - "family": "mistral", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2023-12-10", - "last_updated": "2023-12-10", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.06, "output": 0.06 }, - "limit": { "context": 32768, "output": 16384 } - }, - "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": true, - "cost": { "input": 1, "output": 5 }, - "limit": { "context": 131072, "output": 8192 } - }, - "glm-4.5-air": { - "id": "glm-4.5-air", - "name": "GLM-4.5 Air", - "family": "glm", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-07-25", - "last_updated": "2025-07-25", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.2, "output": 1.1, "cache_read": 0.03 }, - "limit": { "context": 128000, "output": 16384 } - }, - "gemini-3.1-flash-lite-preview": { - "id": "gemini-3.1-flash-lite-preview", - "name": "Gemini 3.1 Flash Lite (Preview)", - "family": "gemini", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2026-03-03", - "last_updated": "2026-03-03", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 1.5, "cache_read": 0.03 }, - "limit": { "context": 1048576, "output": 65536 } - }, - "grok-3": { - "id": "grok-3", - "name": "Grok-3", - "family": "grok", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": 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 }, - "limit": { "context": 131072, "output": 16384 } - }, - "gemini-3.1-flash-image-preview": { - "id": "gemini-3.1-flash-image-preview", - "name": "Gemini 3.1 Flash Image (Preview)", - "family": "gemini", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2026-02-26", - "last_updated": "2026-02-26", - "modalities": { "input": ["text", "image"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 1.5 }, - "limit": { "context": 65536, "output": 65536 } - }, - "gemini-2.5-flash-image": { - "id": "gemini-2.5-flash-image", - "name": "Gemini 2.5 Flash Image", - "family": "gemini", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-10-02", - "last_updated": "2025-10-02", - "modalities": { "input": ["text", "image"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0.3, "output": 30, "cache_read": 0.03 }, - "limit": { "context": 32768, "output": 32768 } - }, - "glm-4.5v": { - "id": "glm-4.5v", - "name": "GLM-4.5V", - "family": "glm", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-08-11", - "last_updated": "2025-08-11", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.6, "output": 1.8, "cache_read": 0.11 }, - "limit": { "context": 128000, "output": 16000 } - }, - "minimax-m2.7-highspeed": { - "id": "minimax-m2.7-highspeed", - "name": "MiniMax M2.7 Highspeed", - "family": "minimax", - "attachment": false, - "reasoning": true, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2024-01-01", - "last_updated": "2024-01-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.6, "output": 2.4, "cache_read": 0.06 }, - "limit": { "context": 204800, "output": 131100 } - }, - "seedream-4-5": { - "id": "seedream-4-5", - "name": "Seedream 4.5", - "family": "seed", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-12-03", - "last_updated": "2025-12-03", - "modalities": { "input": ["text"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "qwen3-coder-plus": { - "id": "qwen3-coder-plus", - "name": "Qwen3 Coder Plus", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-09-23", - "last_updated": "2025-09-23", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 6, "output": 60 }, - "limit": { "context": 1000000, "output": 66000 } - }, - "claude-haiku-4-5-20251001": { - "id": "claude-haiku-4-5-20251001", - "name": "Claude Haiku 4.5 (2025-10-01)", - "family": "claude", - "attachment": false, - "reasoning": false, - "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": 1, "output": 5, "cache_read": 0.1 }, - "limit": { "context": 200000, "output": 64000 } - }, - "glm-4.7": { - "id": "glm-4.7", - "name": "GLM-4.7", - "family": "glm", - "attachment": false, - "reasoning": true, - "tool_call": true, - "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, "cache_read": 0.11 }, - "limit": { "context": 200000, "output": 128000 } - }, - "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": true, - "cost": { "input": 1.2, "output": 6, "cache_read": 0.24 }, - "limit": { "context": 262144, "output": 65536 } - }, - "grok-imagine-image-pro": { - "id": "grok-imagine-image-pro", - "name": "Grok Imagine Image Pro", - "family": "grok", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2026-03-02", - "last_updated": "2026-03-02", - "modalities": { "input": ["text", "image"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 2000, "output": 4096 } - }, - "qwen-flash": { - "id": "qwen-flash", - "name": "Qwen Flash", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2024-09-09", - "last_updated": "2024-09-09", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.05, "output": 0.4, "cache_read": 0.01 }, - "limit": { "context": 1000000, "output": 32000 } - }, - "deepseek-r1-0528": { - "id": "deepseek-r1-0528", - "name": "DeepSeek R1 (0528)", + "hf:deepseek-ai/DeepSeek-V3": { + "id": "hf:deepseek-ai/DeepSeek-V3", + "name": "DeepSeek V3", "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" - }, - "qwen3-max": { - "id": "qwen3-max", - "name": "Qwen3 Max", - "family": "qwen", - "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", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 3, "output": 15, "cache_read": 0.6 }, - "limit": { "context": 256000, "output": 32800 } - }, - "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 } - }, - "qwen2-5-vl-72b-instruct": { - "id": "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, - "release_date": "2025-01-26", - "last_updated": "2025-01-26", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.13, "output": 0.4 }, - "limit": { "context": 32768, "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 } - }, - "grok-4-20-beta-0309-reasoning": { - "id": "grok-4-20-beta-0309-reasoning", - "name": "Grok 4.20 Beta Reasoning (0309)", - "family": "grok", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": 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 }, - "limit": { "context": 2000000, "output": 30000 } - }, - "qwen3-32b": { - "id": "qwen3-32b", - "name": "Qwen3 32B", - "family": "qwen", - "attachment": false, - "reasoning": false, - "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.3 }, - "limit": { "context": 32768, "output": 8192 } - }, - "gpt-4.1-nano": { - "id": "gpt-4.1-nano", - "name": "GPT-4.1 Nano", - "family": "gpt", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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": 1000000, "output": 16384 } - }, - "gemma-3-12b-it": { - "id": "gemma-3-12b-it", - "name": "Gemma 3 12B IT", - "family": "gemma", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-03-10", - "last_updated": "2025-03-10", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.08, "output": 0.3 }, - "limit": { "context": 1000000, "output": 16384 } - }, - "claude-sonnet-4-5": { - "id": "claude-sonnet-4-5", - "name": "Claude Sonnet 4.5", - "family": "claude", - "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": false, - "cost": { "input": 3, "output": 15, "cache_read": 0.3 }, - "limit": { "context": 200000, "output": 64000 } - }, - "devstral-small-2507": { - "id": "devstral-small-2507", - "name": "Devstral Small 1.1", - "family": "mistral", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-07-21", - "last_updated": "2025-07-21", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.1, "output": 0.3 }, - "limit": { "context": 131072, "output": 16384 } - }, - "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": 16384 } - }, - "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 } - }, - "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 } - }, - "qwen3-4b-fp8": { - "id": "qwen3-4b-fp8", - "name": "Qwen3 4B FP8", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "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.03 }, - "limit": { "context": 128000, "output": 20000 } - }, - "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": false, - "structured_output": false, - "temperature": true, - "release_date": "2025-09-23", - "last_updated": "2025-09-23", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.5, "output": 2 }, - "limit": { "context": 131072, "output": 32768 } - }, - "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": 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.24, "output": 0.97 }, - "limit": { "context": 8192, "output": 2048 }, - "status": "beta" - }, - "qwen3-coder-flash": { - "id": "qwen3-coder-flash", - "name": "Qwen3 Coder Flash", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-07-22", - "last_updated": "2025-07-22", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.3, "output": 1.5, "cache_read": 0.06 }, - "limit": { "context": 1000000, "output": 65536 } - }, - "claude-3-haiku": { - "id": "claude-3-haiku", - "name": "Claude 3 Haiku", - "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": 0.25, "output": 1.25, "cache_read": 0.03 }, - "limit": { "context": 200000, "output": 4096 } - }, - "gemini-2.5-flash-image-preview": { - "id": "gemini-2.5-flash-image-preview", - "name": "Gemini 2.5 Flash Image (Preview)", - "family": "gemini", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-10-02", - "last_updated": "2025-10-02", - "modalities": { "input": ["text", "image"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 0.3, "output": 2.5 }, - "limit": { "context": 32768, "output": 32768 } - }, - "o4-mini": { - "id": "o4-mini", - "name": "o4 Mini", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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": 16384 } - }, - "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" - }, - "gemini-3-pro-image-preview": { - "id": "gemini-3-pro-image-preview", - "name": "Gemini 3 Pro Image (Preview)", - "family": "gemini", - "attachment": true, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "release_date": "2025-11-20", - "last_updated": "2025-11-20", - "modalities": { "input": ["text", "image"], "output": ["text", "image"] }, - "open_weights": false, - "cost": { "input": 2, "output": 12, "cache_read": 0.2 }, - "limit": { "context": 65536, "output": 32768 } - }, - "claude-haiku-4-5": { - "id": "claude-haiku-4-5", - "name": "Claude Haiku 4.5", - "family": "claude", - "attachment": false, - "reasoning": false, - "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": 1, "output": 5, "cache_read": 0.1 }, - "limit": { "context": 200000, "output": 64000 } - }, - "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.01, "output": 0.03 }, - "limit": { "context": 32768, "output": 8192 } - }, - "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": false, - "cost": { "input": 0.25, "output": 2, "cache_read": 0.05 }, - "limit": { "context": 256000, "output": 16384 } - }, - "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": true, - "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": 272000 } - }, - "claude-3-5-sonnet-20241022": { - "id": "claude-3-5-sonnet-20241022", - "name": "Claude 3.5 Sonnet (2024-10-22)", - "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": 3, "output": 15, "cache_read": 0.3 }, - "limit": { "context": 200000, "output": 8192 }, - "status": "deprecated" - }, - "minimax-m2.5": { - "id": "minimax-m2.5", - "name": "MiniMax M2.5", - "family": "minimax", - "attachment": false, - "reasoning": true, - "tool_call": true, - "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.2, "cache_read": 0.03 }, - "limit": { "context": 204800, "output": 131100 } - }, - "mistral-large-2512": { - "id": "mistral-large-2512", - "name": "Mistral Large 3", - "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.5, "output": 1.5 }, - "limit": { "context": 262144, "output": 16384 } - }, - "minimax-m2.5-highspeed": { - "id": "minimax-m2.5-highspeed", - "name": "MiniMax M2.5 Highspeed", - "family": "minimax", - "attachment": false, - "reasoning": true, - "tool_call": false, - "structured_output": false, - "temperature": true, - "release_date": "2024-01-01", - "last_updated": "2024-01-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.6, "output": 2.4, "cache_read": 0.03 }, - "limit": { "context": 204800, "output": 131100 } - }, - "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": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 128000, "output": 16000 } - }, - "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-30", - "last_updated": "2025-07-30", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.1, "output": 0.3 }, - "limit": { "context": 262000, "output": 8192 } - }, - "grok-4-1-fast": { - "id": "grok-4-1-fast", - "name": "Grok 4.1 Fast", - "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 } - }, - "gpt-5.2-pro": { - "id": "gpt-5.2-pro", - "name": "GPT-5.2 Pro", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "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": 272000 } - }, - "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 } - } - } - }, - "groq": { - "id": "groq", - "env": ["GROQ_API_KEY"], - "npm": "@ai-sdk/groq", - "name": "Groq", - "doc": "https://console.groq.com/docs/models", - "models": { - "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" - }, - "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 } - }, - "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"] }, + "last_updated": "2025-05-29", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.75, "output": 0.99 }, - "limit": { "context": 131072, "output": 8192 }, - "status": "deprecated" + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 1.25 + } }, - "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" - }, - "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 } - }, - "qwen-qwq-32b": { - "id": "qwen-qwq-32b", - "name": "Qwen QwQ 32B", - "family": "qwen", + "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": "2024-09", - "release_date": "2024-11-27", - "last_updated": "2024-11-27", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-01", + "release_date": "2025-01-20", + "last_updated": "2025-01-20", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.29, "output": 0.39 }, - "limit": { "context": 131072, "output": 16384 }, - "status": "deprecated" + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.55, + "output": 2.19 + } }, - "llama-guard-3-8b": { - "id": "llama-guard-3-8b", - "name": "Llama Guard 3 8B", - "family": "llama", + "hf:deepseek-ai/DeepSeek-R1-0528": { + "id": "hf:deepseek-ai/DeepSeek-R1-0528", + "name": "DeepSeek R1 (0528)", + "family": "deepseek-thinking", "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" - }, - "mistral-saba-24b": { - "id": "mistral-saba-24b", - "name": "Mistral Saba 24B", - "family": "mistral", - "attachment": false, - "reasoning": false, + "reasoning": true, "tool_call": true, "temperature": true, - "knowledge": "2024-08", - "release_date": "2025-02-06", - "last_updated": "2025-02-06", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-08-01", + "last_updated": "2025-08-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.79, "output": 0.79 }, - "limit": { "context": 32768, "output": 32768 }, - "status": "deprecated" + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 3, + "output": 8 + } }, - "whisper-large-v3": { - "id": "whisper-large-v3", - "name": "Whisper Large V3", - "family": "whisper", + "hf:deepseek-ai/DeepSeek-V3.2": { + "id": "hf:deepseek-ai/DeepSeek-V3.2", + "name": "DeepSeek V3.2", + "family": "deepseek", "attachment": false, - "reasoning": false, - "tool_call": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, "temperature": true, - "knowledge": "2023-09", - "release_date": "2023-09-01", - "last_updated": "2025-09-05", - "modalities": { "input": ["audio"], "output": ["text"] }, + "release_date": "2025-12-01", + "last_updated": "2025-12-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 448, "output": 448 } + "limit": { + "context": 162816, + "input": 162816, + "output": 8000 + }, + "cost": { + "input": 0.27, + "output": 0.4, + "cache_read": 0.27, + "cache_write": 0 + } }, - "whisper-large-v3-turbo": { - "id": "whisper-large-v3-turbo", - "name": "Whisper Large v3 Turbo", - "family": "whisper", + "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": 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, + "reasoning": true, "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" - }, - "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"] }, + "release_date": "2025-09-22", + "last_updated": "2025-09-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0, "output": 0 }, - "limit": { "context": 4096, "output": 4096 } + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 1.2, + "output": 1.2 + } }, - "openai/gpt-oss-120b": { - "id": "openai/gpt-oss-120b", + "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, - "structured_output": true, "temperature": true, "release_date": "2025-08-05", "last_updated": "2025-08-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 0.6 }, - "limit": { "context": 131072, "output": 65536 } + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } }, - "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-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 } - }, - "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-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-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-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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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" - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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": 400000, "input": 272000, "output": 128000 } - }, - "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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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-thinking": { - "id": "kimi-k2-thinking", + "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, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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" - } - }, - "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" - } - }, - "gpt-4-turbo": { - "id": "gpt-4-turbo", - "name": "GPT-4 Turbo", - "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-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": 2.5, "output": 10, "cache_read": 1.25 }, - "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, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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-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-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 } - }, - "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-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", - "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" - } - }, - "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.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 } - }, - "gpt-4.1": { - "id": "gpt-4.1", - "name": "GPT-4.1", - "family": "gpt", - "attachment": true, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-05", - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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-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" - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "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 } - }, - "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" - } - }, - "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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": { - "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 } - }, - "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" - }, - "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 } - }, - "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 } - }, - "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-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-05", - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-05", - "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-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" - } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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" - } - }, - "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 } - }, - "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 } - } - } - }, - "aihubmix": { - "id": "aihubmix", - "env": ["AIHUBMIX_API_KEY"], - "npm": "@ai-sdk/openai-compatible", - "api": "https://aihubmix.com/v1", - "name": "AIHubMix", - "doc": "https://docs.aihubmix.com", - "models": { - "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, - "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-3-pro-preview-search": { - "id": "gemini-3-pro-preview-search", - "name": "Gemini 3 Pro Preview Search", - "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": 2, "output": 12, "cache_read": 0.5 }, - "limit": { "context": 1000000, "output": 65000 } - }, - "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, - "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": 0.25, "output": 2, "cache_read": 0.03 }, - "limit": { "context": 400000, "output": 128000 } - }, - "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, - "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.28, "output": 1.12 }, - "limit": { "context": 262144, "output": 262144 } - }, - "qwen3.5-plus": { - "id": "qwen3.5-plus", - "name": "Qwen 3.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.11, "output": 0.66 }, - "limit": { "context": 1000000, "output": 65536 } - }, - "deepseek-v3.2-fast": { - "id": "deepseek-v3.2-fast", - "name": "DeepSeek-V3.2-Fast", - "family": "deepseek", - "attachment": false, - "reasoning": false, - "tool_call": false, - "knowledge": "2024-07", - "release_date": "2025-12-01", - "last_updated": "2025-12-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 1.1, "output": 3.29 }, - "limit": { "context": 128000, "output": 128000 } - }, - "gpt-5-pro": { - "id": "gpt-5-pro", - "name": "GPT-5-Pro", - "family": "gpt-pro", - "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": 7, "output": 28, "cache_read": 3.5 }, - "limit": { "context": 400000, "output": 128000 } - }, - "qwen3-coder-next": { - "id": "qwen3-coder-next", - "name": "Qwen3 Coder Next", - "family": "qwen", - "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": true, - "cost": { "input": 0.14, "output": 0.55 }, - "limit": { "context": 262144, "input": 262144, "output": 65536 } - }, - "gpt-5": { - "id": "gpt-5", - "name": "GPT-5", - "family": "gpt", - "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": 5, "output": 20, "cache_read": 2.5 }, - "limit": { "context": 400000, "output": 128000 } - }, - "claude-opus-4-5": { - "id": "claude-opus-4-5", - "name": "Claude Opus 4.5", - "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, "cache_read": 0.5, "cache_write": 6.25 }, - "limit": { "context": 200000, "output": 32000 } - }, - "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-07", - "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 } - }, - "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": 2, "output": 12, "cache_read": 0.5 }, - "limit": { "context": 1000000, "output": 65000 } - }, - "coding-glm-5-free": { - "id": "coding-glm-5-free", - "name": "Coding-GLM-5-Free", - "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 }, - "limit": { "context": 204800, "output": 131072 } - }, - "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-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": 1.5, "output": 6, "cache_read": 0.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", - "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.3, - "cache_write": 3.75, - "context_over_200k": { "input": 6, "output": 22, "cache_read": 0.6, "cache_write": 7.5 } + "release_date": "2025-11-07", + "last_updated": "2025-11-07", + "modalities": { + "input": ["text"], + "output": ["text"] }, - "limit": { "context": 200000, "output": 128000 } - }, - "gpt-5.1-codex-max": { - "id": "gpt-5.1-codex-max", - "name": "GPT-5.1-Codex-Max", - "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, - "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, - "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 } + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 }, - "limit": { "context": 200000, "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 } - }, - "deepseek-v3.2-think": { - "id": "deepseek-v3.2-think", - "name": "DeepSeek-V3.2-Think", - "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.3, "output": 0.45 }, - "limit": { "context": 131000, "output": 64000 } - }, - "minimax-m2.1": { - "id": "minimax-m2.1", - "name": "MiniMax M2.1", - "family": "minimax", - "attachment": false, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_details" }, - "temperature": true, - "release_date": "2025-12-23", - "last_updated": "2025-12-23", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.29, "output": 1.15 }, - "limit": { "context": 204800, "output": 131072 } - }, - "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", - "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 } + "input": 0.55, + "output": 2.19 + } }, - "claude-opus-4-6-think": { - "id": "claude-opus-4-6-think", - "name": "Claude Opus 4.6 Think", - "family": "claude-opus", - "attachment": true, - "reasoning": true, - "tool_call": 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": 5, - "output": 25, - "cache_read": 0.3, - "cache_write": 3.75, - "context_over_200k": { "input": 6, "output": 22, "cache_read": 0.6, "cache_write": 7.5 } - }, - "limit": { "context": 200000, "output": 128000 } - }, - "coding-glm-4.7-free": { - "id": "coding-glm-4.7-free", - "name": "Coding GLM 4.7 Free", - "family": "glm", - "attachment": false, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_details" }, - "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 } - }, - "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": 16.5, "output": 82.5, "cache_read": 1.5, "cache_write": 18.75 }, - "limit": { "context": 200000, "output": 32000 } - }, - "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.14, "output": 0.41 }, - "limit": { "context": 128000, "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, - "release_date": "2025-08-01", - "last_updated": "2025-08-01", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.82, "output": 3.29 }, - "limit": { "context": 262144, "output": 131000 } - }, - "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-04", - "release_date": "2025-09-15", - "last_updated": "2025-09-15", - "modalities": { "input": ["text", "image", "audio", "video"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.25, "output": 5, "cache_read": 0.31 }, - "limit": { "context": 2000000, "output": 65000 } - }, - "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-04", - "release_date": "2025-09-15", - "last_updated": "2025-09-15", - "modalities": { "input": ["text", "image", "audio", "video"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.075, "output": 0.3, "cache_read": 0.02 }, - "limit": { "context": 1000000, "output": 65000 } - }, - "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, - "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.28, "output": 2.8 }, - "limit": { "context": 262144, "output": 262144 } - }, - "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 } - }, - "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 } - }, - "coding-glm-4.7": { - "id": "coding-glm-4.7", - "name": "Coding-GLM-4.7", - "family": "glm", - "attachment": false, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_details" }, - "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.27, "output": 1.1, "cache_read": 0.548 }, - "limit": { "context": 204800, "output": 131072 } - }, - "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 } - }, - "coding-minimax-m2.1-free": { - "id": "coding-minimax-m2.1-free", - "name": "Coding MiniMax M2.1 Free", - "family": "minimax", - "attachment": false, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_details" }, - "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 } - }, - "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.88, "output": 2.82 }, - "limit": { "context": 204800, "output": 131072 } - }, - "gpt-5-nano": { - "id": "gpt-5-nano", - "name": "GPT-5-Nano", - "family": "gpt-nano", - "attachment": true, - "reasoning": false, - "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.5, "output": 2, "cache_read": 0.25 }, - "limit": { "context": 128000, "output": 16384 } - }, - "glm-4.7": { - "id": "glm-4.7", - "name": "GLM-4.7", - "family": "glm", - "attachment": false, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_details" }, - "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.27, "output": 1.1, "cache_read": 0.548 }, - "limit": { "context": 204800, "output": 131072 } - }, - "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": "2025-09-23", - "last_updated": "2025-09-23", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.34, "output": 1.37 }, - "limit": { "context": 262144, "output": 65536 } - }, - "Kimi-K2-0905": { - "id": "Kimi-K2-0905", + "hf:moonshotai/Kimi-K2-Instruct-0905": { + "id": "hf:moonshotai/Kimi-K2-Instruct-0905", "name": "Kimi K2 0905", "family": "kimi", "attachment": false, @@ -48436,354 +80195,603 @@ "knowledge": "2024-10", "release_date": "2025-09-05", "last_updated": "2025-09-05", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.55, "output": 2.19 }, - "limit": { "context": 262144, "output": 262144 } + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 1.2, + "output": 1.2 + } }, - "gpt-4.1-nano": { - "id": "gpt-4.1-nano", - "name": "GPT-4.1 nano", - "family": "gpt-nano", - "attachment": true, - "reasoning": false, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.55, + "output": 2.19 + } + }, + "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": "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 } + "release_date": "2026-03-11", + "last_updated": "2026-04-03", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 1, + "cache_read": 0.3 + } }, - "claude-sonnet-4-5": { - "id": "claude-sonnet-4-5", - "name": "Claude Sonnet 4.5", - "family": "claude-sonnet", + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.55, + "output": 2.19 + } + }, + "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, + "limit": { + "context": 196608, + "output": 65536 + }, + "cost": { + "input": 0.06, + "output": 0.4, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.55, + "output": 2.19 + } + }, + "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, + "limit": { + "context": 196608, + "output": 65536 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 1 + } + }, + "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, + "limit": { + "context": 196608, + "output": 65536 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.55, + "output": 2.19 + } + }, + "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-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.3, "output": 16.5, "cache_read": 0.3, "cache_write": 3.75 }, - "limit": { "context": 200000, "output": 64000 } - }, - "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"] }, + "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.3, "output": 0.45 }, - "limit": { "context": 131000, "output": 64000 } - }, - "gpt-5-codex": { - "id": "gpt-5-codex", - "name": "GPT-5-Codex", - "family": "gpt-codex", + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.95 + } + } + } + }, + "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": { + "upstage/solar-10_7b-instruct": { + "id": "upstage/solar-10_7b-instruct", + "name": "solar-10.7b-instruct", "attachment": false, - "reasoning": true, + "reasoning": false, "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 } + "temperature": true, + "release_date": "2024-06-05", + "last_updated": "2025-04-10", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "o4-mini": { - "id": "o4-mini", - "name": "o4-mini", - "family": "o-mini", + "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": true, + "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, + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 4096, + "output": 0 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "black-forest-labs/flux_1-schnell": { + "id": "black-forest-labs/flux_1-schnell", + "name": "FLUX.1-schnell", + "attachment": false, + "reasoning": false, + "tool_call": false, + "structured_output": false, + "temperature": false, + "knowledge": "2024-07", + "release_date": "2024-08-01", + "last_updated": "2026-02-04", + "modalities": { + "input": ["text"], + "output": ["image"] + }, + "open_weights": true, + "limit": { + "context": 77, + "input": 77, + "output": 0 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "black-forest-labs/flux_1-kontext-dev": { + "id": "black-forest-labs/flux_1-kontext-dev", + "name": "FLUX.1-Kontext-dev", + "attachment": true, + "reasoning": false, "tool_call": false, "temperature": false, - "knowledge": "2024-09", - "release_date": "2025-09-15", - "last_updated": "2025-09-15", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.5, "output": 6, "cache_read": 0.75 }, - "limit": { "context": 200000, "output": 65536 } + "release_date": "2025-08-12", + "last_updated": "2025-08-12", + "modalities": { + "input": ["text", "image"], + "output": ["image"] + }, + "open_weights": true, + "limit": { + "context": 40960, + "output": 40960 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "claude-haiku-4-5": { - "id": "claude-haiku-4-5", - "name": "Claude Haiku 4.5", - "family": "claude-haiku", + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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-07-31", - "release_date": "2025-09-29", - "last_updated": "2025-09-29", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1.1, "output": 5.5, "cache_read": 0.11, "cache_write": 1.25 }, - "limit": { "context": 200000, "output": 64000 } - }, - "gpt-5.1-codex": { - "id": "gpt-5.1-codex", - "name": "GPT-5.1 Codex", - "family": "gpt-codex", - "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.13 }, - "limit": { "context": 400000, "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"] }, + "knowledge": "2025-12", + "release_date": "2025-12-08", + "last_updated": "2025-12-09", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.29, "output": 1.15 }, - "limit": { "context": 204800, "output": 131072 } - } - } - }, - "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.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 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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": { - "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": { - "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-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 } - }, - "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 } - } - } - }, - "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": { - "qwen3-coder-30b-a3b-instruct": { - "id": "qwen3-coder-30b-a3b-instruct", - "name": "Qwen3-Coder-30B-A3B-Instruct", + "mistralai/mistral-nemotron": { + "id": "mistralai/mistral-nemotron", + "name": "mistral-nemotron", "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 } - }, - "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 } - }, - "deepseek-r1-distill-llama-70b": { - "id": "deepseek-r1-distill-llama-70b", - "name": "DeepSeek-R1-Distill-Llama-70B", - "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.74, "output": 0.74 }, - "limit": { "context": 131072, "output": 131072 } - }, - "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"] }, + "last_updated": "2025-06-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.11, "output": 0.11 }, - "limit": { "context": 131072, "output": 131072 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "qwen2.5-coder-32b-instruct": { - "id": "qwen2.5-coder-32b-instruct", - "name": "Qwen2.5-Coder-32B-Instruct", + "mistralai/mixtral-8x22b-instruct": { + "id": "mistralai/mixtral-8x22b-instruct", + "name": "Mistral: Mixtral 8x22B Instruct", "attachment": false, "reasoning": false, - "tool_call": false, - "structured_output": true, + "tool_call": true, "temperature": true, - "release_date": "2025-03-24", - "last_updated": "2025-03-24", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2024-04-17", + "last_updated": "2024-04-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.96, "output": 0.96 }, - "limit": { "context": 32768, "output": 32768 } + "limit": { + "context": 65536, + "output": 13108 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "qwen2.5-vl-72b-instruct": { - "id": "qwen2.5-vl-72b-instruct", - "name": "Qwen2.5-VL-72B-Instruct", + "mistralai/mistral-medium-3-instruct": { + "id": "mistralai/mistral-medium-3-instruct", + "name": "Mistral Medium 3", + "family": "mistral-medium", "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 } + "structured_output": false, + "release_date": "2025-09-25", + "last_updated": "2025-09-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 131072, + "input": 131072, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "mistral-7b-instruct-v0.3": { - "id": "mistral-7b-instruct-v0.3", + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "mistralai/magistral-small-2506": { + "id": "mistralai/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, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "mistralai/mistral-7b-instruct-v03": { + "id": "mistralai/mistral-7b-instruct-v03", "name": "Mistral-7B-Instruct-v0.3", "attachment": false, "reasoning": false, @@ -48792,2569 +80800,892 @@ "temperature": true, "release_date": "2025-04-01", "last_updated": "2025-04-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.11, "output": 0.11 }, - "limit": { "context": 65536, "output": 65536 } + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "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 } - }, - "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 } - }, - "mixtral-8x7b-instruct-v0.1": { - "id": "mixtral-8x7b-instruct-v0.1", - "name": "Mixtral-8x7B-Instruct-v0.1", - "attachment": false, - "reasoning": false, - "tool_call": false, - "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.7, "output": 0.7 }, - "limit": { "context": 32768, "output": 32768 } - }, - "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 } - } - } - }, - "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.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.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": { - "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": { - "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-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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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-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.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-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-0905-preview": { - "id": "kimi-k2-0905-preview", - "name": "Kimi K2 0905", - "family": "kimi", + "mistralai/mistral-small-4-119b-2603": { + "id": "mistralai/mistral-small-4-119b-2603", + "name": "mistral-small-4-119b-2603", "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-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 } - } - } - }, - "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": { - "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-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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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-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-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 } - }, - "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-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-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-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-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 } - }, - "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 } - }, - "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": { - "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 } - }, - "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.6, "output": 3.6, "reasoning": 3.6 }, - "limit": { "context": 262144, "output": 65536 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - } - } - }, - "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": { - "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.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 } - }, - "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 } - }, - "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-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": { - "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 } - }, - "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.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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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.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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - } - } - }, - "mistral": { - "id": "mistral", - "env": ["MISTRAL_API_KEY"], - "npm": "@ai-sdk/mistral", - "name": "Mistral", - "doc": "https://docs.mistral.ai/getting-started/models/", - "models": { - "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 } - }, - "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-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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 0.6 }, - "limit": { "context": 256000, "output": 256000 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "ministral-3b-latest": { - "id": "ministral-3b-latest", - "name": "Ministral 3B (latest)", - "family": "ministral", + "sarvamai/sarvam-m": { + "id": "sarvamai/sarvam-m", + "name": "sarvam-m", "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"] }, + "release_date": "2025-07-25", + "last_updated": "2025-07-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.04, "output": 0.04 }, - "limit": { "context": 128000, "output": 128000 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "mistral-medium-latest": { - "id": "mistral-medium-latest", - "name": "Mistral Medium (latest)", - "family": "mistral-medium", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-05", - "release_date": "2025-05-07", - "last_updated": "2025-05-10", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.4, "output": 2 }, - "limit": { "context": 128000, "output": 16384 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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-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-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 } - } - } - }, - "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.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 } - }, - "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-03-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "gemma-3-27b-it": { - "id": "gemma-3-27b-it", - "name": "Gemma-3-27B-IT", - "family": "gemma", + "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": "2026-03-17", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "last_updated": "2025-09-05", + "modalities": { + "input": ["text", "image", "audio"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.25, "output": 0.5 }, - "limit": { "context": 40000, "output": 8192 } + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "llama-3.1-8b-instruct": { - "id": "llama-3.1-8b-instruct", - "name": "Llama 3.1 8B Instruct", - "family": "llama", + "microsoft/phi-4-multimodal-instruct": { + "id": "microsoft/phi-4-multimodal-instruct", + "name": "Phi 4 Multimodal", "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 } + "tool_call": false, + "structured_output": false, + "release_date": "2025-07-26", + "last_updated": "2025-07-26", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "gpt-oss-120b": { - "id": "gpt-oss-120b", - "name": "GPT-OSS 120B", - "family": "gpt-oss", + "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": false, + "reasoning": true, "tool_call": true, + "structured_output": true, "temperature": true, - "release_date": "2024-01-01", - "last_updated": "2026-03-17", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-04-28", + "last_updated": "2026-04-28", + "modalities": { + "input": ["text", "image", "video", "audio"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 0.6 }, - "limit": { "context": 128000, "output": 32768 } + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "bge-multilingual-gemma2": { - "id": "bge-multilingual-gemma2", - "name": "BGE Multilingual Gemma2", - "family": "gemma", + "nvidia/usdvalidate": { + "id": "nvidia/usdvalidate", + "name": "usdvalidate", "attachment": false, "reasoning": false, "tool_call": false, "temperature": false, - "release_date": "2024-07-26", - "last_updated": "2025-06-15", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2024-07-24", + "last_updated": "2025-01-08", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/synthetic-video-detector": { + "id": "nvidia/synthetic-video-detector", + "name": "synthetic-video-detector", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2026-04-16", + "last_updated": "2026-04-16", + "modalities": { + "input": ["video"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/cosmos-transfer1-7b": { + "id": "nvidia/cosmos-transfer1-7b", + "name": "cosmos-transfer1-7b", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-06-13", + "last_updated": "2025-06-30", + "modalities": { + "input": ["text", "image", "video"], + "output": ["video"] + }, + "open_weights": true, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/rerank-qa-mistral-4b": { + "id": "nvidia/rerank-qa-mistral-4b", + "name": "rerank-qa-mistral-4b", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2024-03-17", + "last_updated": "2025-01-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/nv-embedcode-7b-v1": { + "id": "nvidia/nv-embedcode-7b-v1", + "name": "nv-embedcode-7b-v1", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-03-17", + "last_updated": "2025-05-29", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "nvidia/riva-translate-4b-instruct-v1_1": { + "id": "nvidia/riva-translate-4b-instruct-v1_1", + "name": "riva-translate-4b-instruct-v1_1", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-12-12", + "last_updated": "2025-12-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/nemotron-voicechat": { + "id": "nvidia/nemotron-voicechat", + "name": "nemotron-voicechat", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "release_date": "2026-03-16", + "last_updated": "2026-03-16", + "modalities": { + "input": ["text", "audio"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2023-12", + "release_date": "2025-07-25", + "last_updated": "2025-07-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/usdcode": { + "id": "nvidia/usdcode", + "name": "usdcode", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2026-01-01", + "last_updated": "2026-01-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.1, "output": 0 }, - "limit": { "context": 8191, "output": 3072 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "pixtral-12b-2409": { - "id": "pixtral-12b-2409", - "name": "Pixtral 12B 2409", - "family": "pixtral", + "nvidia/llama-3_2-nemoretriever-300m-embed-v1": { + "id": "nvidia/llama-3_2-nemoretriever-300m-embed-v1", + "name": "llama-3_2-nemoretriever-300m-embed-v1", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-07-24", + "last_updated": "2025-07-24", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/llama-3_1-nemotron-safety-guard-8b-v3": { + "id": "nvidia/llama-3_1-nemotron-safety-guard-8b-v3", + "name": "llama-3.1-nemotron-safety-guard-8b-v3", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-10-28", + "last_updated": "2025-10-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/nv-embed-v1": { + "id": "nvidia/nv-embed-v1", + "name": "nv-embed-v1", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2024-06-07", + "last_updated": "2025-07-22", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/gliner-pii": { + "id": "nvidia/gliner-pii", + "name": "gliner-pii", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2026-03-03", + "last_updated": "2026-03-03", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/bevformer": { + "id": "nvidia/bevformer", + "name": "bevformer", "attachment": true, "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2025-03-18", + "last_updated": "2025-07-20", + "modalities": { + "input": ["video"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/nemotron-mini-4b-instruct": { + "id": "nvidia/nemotron-mini-4b-instruct", + "name": "nemotron-mini-4b-instruct", + "attachment": false, + "reasoning": false, "tool_call": true, "temperature": true, - "release_date": "2024-09-25", - "last_updated": "2026-03-17", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "release_date": "2024-08-21", + "last_updated": "2024-08-26", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.2, "output": 0.2 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "voxtral-small-24b-2507": { - "id": "voxtral-small-24b-2507", - "name": "Voxtral Small 24B 2507", - "family": "voxtral", + "nvidia/cosmos-predict1-5b": { + "id": "nvidia/cosmos-predict1-5b", + "name": "cosmos-predict1-5b", "attachment": true, "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-03-18", + "last_updated": "2025-03-18", + "modalities": { + "input": ["text", "image", "video"], + "output": ["video"] + }, + "open_weights": true, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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", + "family": "nemotron", + "attachment": false, + "reasoning": true, "tool_call": true, "temperature": true, - "release_date": "2025-07-01", - "last_updated": "2026-03-17", - "modalities": { "input": ["text", "audio"], "output": ["text"] }, + "knowledge": "2023-12", + "release_date": "2025-04-07", + "last_updated": "2025-04-07", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.15, "output": 0.35 }, - "limit": { "context": 32000, "output": 16384 } + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "whisper-large-v3": { - "id": "whisper-large-v3", + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/cosmos-transfer2_5-2b": { + "id": "nvidia/cosmos-transfer2_5-2b", + "name": "cosmos-transfer2.5-2b", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-02-26", + "last_updated": "2026-02-26", + "modalities": { + "input": ["text", "image", "video"], + "output": ["video"] + }, + "open_weights": true, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/nemotron-content-safety-reasoning-4b": { + "id": "nvidia/nemotron-content-safety-reasoning-4b", + "name": "nemotron-content-safety-reasoning-4b", + "attachment": false, + "reasoning": true, + "tool_call": false, + "temperature": false, + "release_date": "2026-01-22", + "last_updated": "2026-01-22", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/active-speaker-detection": { + "id": "nvidia/active-speaker-detection", + "name": "Active Speaker Detection", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-04-16", + "last_updated": "2026-04-16", + "modalities": { + "input": ["video"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/magpie-tts-zeroshot": { + "id": "nvidia/magpie-tts-zeroshot", + "name": "magpie-tts-zeroshot", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-05-22", + "last_updated": "2025-06-12", + "modalities": { + "input": ["text", "audio"], + "output": ["audio"] + }, + "open_weights": true, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/streampetr": { + "id": "nvidia/streampetr", + "name": "streampetr", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2025-11-13", + "last_updated": "2025-11-13", + "modalities": { + "input": ["video"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/sparsedrive": { + "id": "nvidia/sparsedrive", + "name": "sparsedrive", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2025-03-18", + "last_updated": "2025-07-20", + "modalities": { + "input": ["video"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/nemotron-3-content-safety": { + "id": "nvidia/nemotron-3-content-safety", + "name": "nemotron-3-content-safety", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-04-16", + "last_updated": "2026-04-16", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/llama-nemotron-embed-vl-1b-v2": { + "id": "nvidia/llama-nemotron-embed-vl-1b-v2", + "name": "llama-nemotron-embed-vl-1b-v2", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-02-10", + "last_updated": "2026-02-10", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/studiovoice": { + "id": "nvidia/studiovoice", + "name": "studiovoice", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2024-10-03", + "last_updated": "2025-06-13", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "nvidia/llama-nemotron-rerank-vl-1b-v2": { + "id": "nvidia/llama-nemotron-rerank-vl-1b-v2", + "name": "llama-nemotron-rerank-vl-1b-v2", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-03-31", + "last_updated": "2026-03-31", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 163840, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "openai/whisper-large-v3": { + "id": "openai/whisper-large-v3", "name": "Whisper Large v3", "family": "whisper", "attachment": false, @@ -51363,11241 +81694,948 @@ "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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-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 } - }, - "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 } - }, - "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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-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-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-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 } - } - } - }, - "venice": { - "id": "venice", - "env": ["VENICE_API_KEY"], - "npm": "venice-ai-sdk-provider", - "name": "Venice AI", - "doc": "https://docs.venice.ai", - "models": { - "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 } - }, - "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 } - }, - "aion-labs.aion-2-0": { - "id": "aion-labs.aion-2-0", - "name": "Aion 2.0", - "family": "o", - "attachment": false, - "reasoning": false, - "tool_call": false, - "temperature": true, - "release_date": "2026-03-24", - "last_updated": "2026-03-27", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 1, "output": 2, "cache_read": 0.25 }, - "limit": { "context": 128000, "output": 32768 } - }, - "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 } - }, - "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": "2024-04", - "release_date": "2025-12-10", - "last_updated": "2026-03-12", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.75, "output": 3.2, "cache_read": 0.375 }, - "limit": { "context": 256000, "output": 65536 } - }, - "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-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 } - }, - "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-03-09", - "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 } - }, - "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 } - }, - "grok-code-fast-1": { - "id": "grok-code-fast-1", - "name": "Grok Code Fast 1", - "family": "grok", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2025-12-01", - "last_updated": "2026-03-12", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 1.87, "cache_read": 0.03 }, - "limit": { "context": 256000, "output": 10000 } - }, - "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 } - }, - "grok-4-20-beta": { - "id": "grok-4-20-beta", - "name": "Grok 4.20 Beta", - "family": "grok-beta", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "release_date": "2026-03-12", - "last_updated": "2026-03-16", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { - "input": 2.5, - "output": 7.5, - "cache_read": 0.25, - "context_over_200k": { "input": 5, "output": 15, "cache_read": 0.25 } + "modalities": { + "input": ["audio"], + "output": ["text"] }, - "limit": { "context": 2000000, "output": 128000 } + "open_weights": true, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "grok-4-20-multi-agent-beta": { - "id": "grok-4-20-multi-agent-beta", - "name": "Grok 4.20 Multi-Agent Beta", - "family": "grok-beta", + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "openai/gpt-oss-120b": { + "id": "openai/gpt-oss-120b", + "name": "GPT-OSS-120B", + "family": "gpt-oss", "attachment": true, "reasoning": true, "tool_call": false, - "structured_output": true, "temperature": true, - "release_date": "2026-03-12", - "last_updated": "2026-03-16", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { - "input": 2.5, - "output": 7.5, - "cache_read": 0.25, - "context_over_200k": { "input": 5, "output": 15, "cache_read": 0.25 } + "knowledge": "2025-08", + "release_date": "2025-08-04", + "last_updated": "2025-08-14", + "modalities": { + "input": ["text"], + "output": ["text"] }, - "limit": { "context": 2000000, "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, - "structured_output": true, - "temperature": true, - "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 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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, - "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 } - }, - "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 } - }, - "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-03-16", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.56, "output": 3.5, "cache_read": 0.11 }, - "limit": { "context": 256000, "output": 65536 } - }, - "claude-opus-45": { - "id": "claude-opus-45", - "name": "Claude Opus 4.5", - "family": "claude-opus", - "attachment": true, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2025-03", - "release_date": "2025-12-06", - "last_updated": "2026-01-28", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 6, "output": 30, "cache_read": 0.6, "cache_write": 7.5 }, - "limit": { "context": 198000, "output": 49500 } - }, - "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 } - }, - "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-03-16", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.05, "output": 0.15 }, - "limit": { "context": 256000, "output": 65536 } - }, - "minimax-m27": { - "id": "minimax-m27", - "name": "MiniMax M2.7", + "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-03-18", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.375, "output": 1.5, "cache_read": 0.075 }, - "limit": { "context": 198000, "output": 32768 } - }, - "venice-uncensored": { - "id": "venice-uncensored", - "name": "Venice Uncensored 1.1", - "family": "venice", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": true, - "temperature": true, - "knowledge": "2023-10", - "release_date": "2025-03-18", - "last_updated": "2026-03-12", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.2, "output": 0.9 }, - "limit": { "context": 32000, "output": 8192 } - }, - "openai-gpt-oss-120b": { - "id": "openai-gpt-oss-120b", - "name": "OpenAI GPT OSS 120B", - "family": "gpt-oss", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2025-07", - "release_date": "2025-11-06", - "last_updated": "2026-03-12", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.07, "output": 0.3 }, - "limit": { "context": 128000, "output": 16384 } - }, - "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 } - }, - "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 } - }, - "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 } + "last_updated": "2026-04-11", + "modalities": { + "input": ["text"], + "output": ["text"] }, - "limit": { "context": 1000000, "output": 32768 } - }, - "qwen3-coder-480b-a35b-instruct": { - "id": "qwen3-coder-480b-a35b-instruct", - "name": "Qwen 3 Coder 480b", - "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.75, "output": 3 }, - "limit": { "context": 256000, "output": 65536 } + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "zai-org-glm-4.6": { - "id": "zai-org-glm-4.6", - "name": "GLM 4.6", + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "z-ai/glm4.7": { + "id": "z-ai/glm4.7", + "name": "GLM-4.7", "family": "glm", "attachment": false, - "reasoning": false, + "reasoning": true, "tool_call": true, - "interleaved": { "field": "reasoning_content" }, - "structured_output": true, + "interleaved": { + "field": "reasoning_content" + }, "temperature": true, - "release_date": "2024-04-01", - "last_updated": "2026-03-16", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-04", + "release_date": "2025-12-22", + "last_updated": "2025-12-22", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.85, "output": 2.75, "cache_read": 0.3 }, - "limit": { "context": 198000, "output": 16384 } + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "qwen3-235b-a22b-thinking-2507": { - "id": "qwen3-235b-a22b-thinking-2507", - "name": "Qwen 3 235B A22B Thinking 2507", - "family": "qwen", + "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" }, + "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"] }, + "release_date": "2026-03-27", + "last_updated": "2026-03-27", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.45, "output": 3.5 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "qwen3-4b": { - "id": "qwen3-4b", - "name": "Venice Small", - "family": "qwen", - "attachment": false, - "reasoning": true, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2024-07", - "release_date": "2025-04-29", - "last_updated": "2026-03-12", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.05, "output": 0.15 }, - "limit": { "context": 32000, "output": 4096 } - }, - "hermes-3-llama-3.1-405b": { - "id": "hermes-3-llama-3.1-405b", - "name": "Hermes 3 Llama 3.1 405b", - "family": "hermes", + "meta/esm2-650m": { + "id": "meta/esm2-650m", + "name": "esm2-650m", "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"] }, + "release_date": "2024-08-29", + "last_updated": "2025-03-10", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 1.1, "output": 3 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "claude-sonnet-45": { - "id": "claude-sonnet-45", - "name": "Claude Sonnet 4.5", - "family": "claude-sonnet", - "attachment": true, - "reasoning": true, + "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, - "interleaved": { "field": "reasoning_content" }, "structured_output": true, "temperature": true, - "knowledge": "2025-09", - "release_date": "2025-01-15", - "last_updated": "2026-01-28", - "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": 49500 } + "release_date": "2024-11-26", + "last_updated": "2024-11-26", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "llama-3.3-70b": { - "id": "llama-3.3-70b", - "name": "Llama 3.3 70B", + "meta/esmfold": { + "id": "meta/esmfold", + "name": "esmfold", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2024-03-15", + "last_updated": "2025-06-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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": 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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "meta/llama-guard-4-12b": { + "id": "meta/llama-guard-4-12b", + "name": "Llama Guard 4 12B", + "family": "llama", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2025-04-05", + "last_updated": "2026-04-30", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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": false, + "structured_output": true, + "temperature": true, + "release_date": "2024-09-18", + "last_updated": "2024-09-18", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 32000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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-04-06", - "last_updated": "2026-03-12", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-01-01", + "last_updated": "2025-01-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.7, "output": 2.8 }, - "limit": { "context": 128000, "output": 4096 } + "limit": { + "context": 16000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "mistral-31-24b": { - "id": "mistral-31-24b", - "name": "Venice Medium", - "family": "mistral", - "attachment": true, - "reasoning": false, - "tool_call": true, - "structured_output": true, - "temperature": true, - "knowledge": "2023-10", - "release_date": "2025-03-18", - "last_updated": "2026-03-12", - "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 } - }, - "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-03-16", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.34, "output": 1.19, "cache_read": 0.04 }, - "limit": { "context": 198000, "output": 32768 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "qwen3-vl-235b-a22b": { - "id": "qwen3-vl-235b-a22b", - "name": "Qwen3 VL 235B", + "qwen/qwen-image-edit": { + "id": "qwen/qwen-image-edit", + "name": "Qwen Image Edit", "family": "qwen", "attachment": true, "reasoning": false, - "tool_call": true, - "structured_output": true, + "tool_call": false, + "structured_output": false, "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 } + "release_date": "2025-08-19", + "last_updated": "2025-08-19", + "modalities": { + "input": ["text", "image"], + "output": ["image"] + }, + "open_weights": false, + "limit": { + "context": 0, + "output": 0 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "grok-41-fast": { - "id": "grok-41-fast", - "name": "Grok 4.1 Fast", - "family": "grok", + "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, - "knowledge": "2025-07", - "release_date": "2025-12-01", - "last_updated": "2026-03-12", - "modalities": { "input": ["text", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 0.625, "cache_read": 0.0625 }, - "limit": { "context": 1000000, "output": 30000 } - }, - "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 } - }, - "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"] }, + "release_date": "2026-02-23", + "last_updated": "2026-02-23", + "modalities": { + "input": ["text", "image", "video", "audio"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.125, "output": 0.5 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "mistral-small-3-2-24b-instruct": { - "id": "mistral-small-3-2-24b-instruct", - "name": "Mistral Small 3.2 24B Instruct", - "family": "mistral-small", + "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": "2026-01-15", - "last_updated": "2026-03-16", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2024-11-06", + "last_updated": "2024-11-06", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.09375, "output": 0.25 }, - "limit": { "context": 256000, "output": 16384 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "openai-gpt-52-codex": { - "id": "openai-gpt-52-codex", - "name": "GPT-5.2 Codex", - "family": "gpt-codex", + "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-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 } - }, - "minimax-m21": { - "id": "minimax-m21", - "name": "MiniMax M2.1", - "family": "minimax", - "attachment": false, - "reasoning": true, - "tool_call": true, - "interleaved": { "field": "reasoning_content" }, - "structured_output": true, - "temperature": true, - "release_date": "2025-12-01", - "last_updated": "2026-03-16", - "modalities": { "input": ["text"], "output": ["text"] }, + "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.35, "output": 1.5, "cache_read": 0.04 }, - "limit": { "context": 198000, "output": 32768 } - } - } - }, - "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": { - "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 } + "limit": { + "context": 262144, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - "id": "Qwen/Qwen3-235B-A22B-Thinking-2507", - "name": "Qwen3 235B A22B Thinking 2507", + "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, - "release_date": "2025-08-23", - "last_updated": "2025-08-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2024-12", + "release_date": "2024-12-01", + "last_updated": "2025-09-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.2, "output": 0.6 }, - "limit": { "context": 262144, "output": 131072 } + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", - "name": "Qwen3 235B A22B Instruct 2507", + "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, - "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 } + "knowledge": "2024-12", + "release_date": "2024-12-01", + "last_updated": "2025-09-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8": { - "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", + "qwen/qwen-image": { + "id": "qwen/qwen-image", + "name": "Qwen Image", + "family": "qwen", + "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 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, - "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 } - } - } - }, - "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": { - "Kimi-K2.5": { - "id": "Kimi-K2.5", - "name": "Kimi K2 Instruct", - "family": "kimi", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "release_date": "2024-07-18", - "last_updated": "2024-07-18", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.55, "output": 2.75 }, - "limit": { "context": 261000, "output": 32768 } - }, - "MiniMax-M2.5": { - "id": "MiniMax-M2.5", - "name": "MiniMax M2.5", - "family": "minimax", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2024-10", - "release_date": "2025-01-20", - "last_updated": "2025-01-20", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.3, "output": 1.2 }, - "limit": { "context": 196000, "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": "2024-10", - "release_date": "2025-01-20", - "last_updated": "2025-01-20", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.85, "output": 3.1 }, - "limit": { "context": 202000, "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-10", - "release_date": "2025-01-20", - "last_updated": "2025-01-20", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, - "cost": { "input": 0.55, "output": 1.65 }, - "limit": { "context": 163000, "output": 4096 } - } - } - }, - "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": { - "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 } - }, - "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/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-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 } - }, - "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 } - }, - "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-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-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/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/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": { - "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-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 } - }, - "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/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/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-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 } - }, - "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-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-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-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-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-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-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/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 } - }, - "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-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-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-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-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/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-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 } - }, - "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 } - }, - "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-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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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/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/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-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/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-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/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/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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "mercury-coder-small": { - "id": "mercury-coder-small", - "name": "Mercury Coder Small", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, - "release_date": "2025-02-26", - "last_updated": "2025-02-26", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 1 }, - "limit": { "context": 32768, "input": 32768, "output": 16384 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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+(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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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-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 } - }, - "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-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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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/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/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.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/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-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": { - "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/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-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-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-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-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-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/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/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-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-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-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/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.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/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/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-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/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/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 } - }, - "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-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/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": { - "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/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/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/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-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-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-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/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.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-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-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/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-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/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/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/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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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.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-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-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 } - }, - "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 } - }, - "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": { - "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, - "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: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, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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/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: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/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 } - }, - "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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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/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_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 } - }, - "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/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 } - }, - "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: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 } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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/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 } - }, - "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-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/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 } - }, - "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-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/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/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/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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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.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.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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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.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-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.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 } - }, - "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 } - }, - "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 } - }, - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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-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-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 } - }, - "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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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/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/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/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/qwen3-coder": { - "id": "TEE/qwen3-coder", - "name": "Qwen3 Coder 480B TEE", - "family": "qwen", - "attachment": false, - "reasoning": false, - "tool_call": false, - "structured_output": false, + "knowledge": "2025-04", "release_date": "2025-07-23", "last_updated": "2025-07-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.5, "output": 2 }, - "limit": { "context": 128000, "input": 128000, "output": 32768 } + "limit": { + "context": 262144, + "output": 66536 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "TEE/minimax-m2.1": { - "id": "TEE/minimax-m2.1", - "name": "MiniMax M2.1 TEE", - "family": "minimax", + "google/gemma-2-2b-it": { + "id": "google/gemma-2-2b-it", + "name": "Gemma 2 2b It", "attachment": false, - "reasoning": true, + "reasoning": false, "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 } + "temperature": true, + "release_date": "2024-07-16", + "last_updated": "2024-07-16", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "TEE/qwen2.5-vl-72b-instruct": { - "id": "TEE/qwen2.5-vl-72b-instruct", - "name": "Qwen2.5 VL 72B TEE", - "family": "qwen", + "google/gemma-3n-e4b-it": { + "id": "google/gemma-3n-e4b-it", + "name": "Gemma 3n E4b It", "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 } + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "TEE/deepseek-v3.1": { - "id": "TEE/deepseek-v3.1", - "name": "DeepSeek V3.1 TEE", - "family": "deepseek", - "attachment": false, + "google/gemma-3n-e2b-it": { + "id": "google/gemma-3n-e2b-it", + "name": "Gemma 3n E2b It", + "attachment": true, "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 } + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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-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/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-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/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/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/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/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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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, + "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": "2024-12-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "last_updated": "2025-09-05", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.44, "output": 0.44 }, - "limit": { "context": 8192, "input": 8192, "output": 8192 } + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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": { - "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.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 } - }, - "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-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-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", + "google/google-paligemma": { + "id": "google/google-paligemma", + "name": "paligemma", "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 } + "temperature": true, + "release_date": "2024-05-14", + "last_updated": "2024-08-26", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, "moonshotai/kimi-k2-instruct": { "id": "moonshotai/kimi-k2-instruct", "name": "Kimi K2 Instruct", "family": "kimi", "attachment": false, - "reasoning": false, + "reasoning": true, "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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.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-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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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, + "temperature": true, + "knowledge": "2024-01", "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 } - }, - "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 } - }, - "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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.31, "output": 0.31 }, - "limit": { "context": 128000, "input": 128000, "output": 8192 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "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 } - }, - "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/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/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 } - }, - "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/mistral-7b-instruct": { - "id": "mistralai/mistral-7b-instruct", - "name": "Mistral 7B Instruct", - "family": "mistral", + "moonshotai/kimi-k2.6": { + "id": "moonshotai/kimi-k2.6", + "name": "Kimi K2.6", + "family": "kimi-k2.6", "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-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/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-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-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-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/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/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 } - }, - "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/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/mistral-small-creative": { - "id": "mistralai/mistral-small-creative", - "name": "Mistral Small Creative", - "family": "mistral-small", - "attachment": false, - "reasoning": false, + "reasoning": true, "tool_call": true, + "interleaved": { + "field": "reasoning_content" + }, "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/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-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-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-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/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 } - }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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"] }, + "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.045, "output": 0.18 }, - "limit": { "context": 131072, "output": 16384 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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", + "moonshotai/kimi-k2-instruct-0905": { + "id": "moonshotai/kimi-k2-instruct-0905", + "name": "Kimi K2 0905", + "family": "kimi", "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 } - }, - "arcee_ai/AFM/models/trinity-mini": { - "id": "arcee_ai/AFM/models/trinity-mini", - "name": "Trinity Mini", - "family": "trinity-mini", - "attachment": false, - "reasoning": true, + "reasoning": false, "tool_call": true, "temperature": true, "knowledge": "2024-10", - "release_date": "2025-12", - "last_updated": "2026-02-25", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-09-05", + "last_updated": "2025-09-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.045, "output": 0.15 }, - "limit": { "context": 131072, "output": 131072 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "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 } - }, - "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", + "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, - "release_date": "2025-07-31", - "last_updated": "2026-02-25", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-07", + "release_date": "2025-11", + "last_updated": "2025-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.36, "output": 1.3 }, - "limit": { "context": 262144, "output": 131072 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } }, - "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 } - }, - "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 } - } - } - }, - "cerebras": { - "id": "cerebras", - "env": ["CEREBRAS_API_KEY"], - "npm": "@ai-sdk/cerebras", - "name": "Cerebras", - "doc": "https://inference-docs.cerebras.ai/models/overview", - "models": { - "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 } - }, - "llama3.1-8b": { - "id": "llama3.1-8b", - "name": "Llama 3.1 8B", - "family": "llama", + "abacusai/dracarys-llama-3_1-70b-instruct": { + "id": "abacusai/dracarys-llama-3_1-70b-instruct", + "name": "dracarys-llama-3.1-70b-instruct", "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"] }, + "release_date": "2024-09-11", + "last_updated": "2025-05-22", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.1, "output": 0.1 }, - "limit": { "context": 32000, "output": 8000 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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 } - }, - "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 } - } - } - }, - "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": { - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - } - } - }, - "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/openai/gpt-oss-120b": { - "id": "@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 } - }, - "@cf/openai/gpt-oss-20b": { - "id": "@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 } - }, - "@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/myshell-ai/melotts": { - "id": "@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 } - }, - "@cf/google/gemma-3-12b-it": { - "id": "@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 } - }, - "@cf/ibm-granite/granite-4.0-h-micro": { - "id": "@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 } - }, - "@cf/ai4bharat/indictrans2-en-indic-1B": { - "id": "@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 } - }, - "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b": { - "id": "@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 } - }, - "@cf/qwen/qwq-32b": { - "id": "@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 } - }, - "@cf/qwen/qwen3-30b-a3b-fp8": { - "id": "@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 } - }, - "@cf/qwen/qwen3-embedding-0.6b": { - "id": "@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 } - }, - "@cf/qwen/qwen2.5-coder-32b-instruct": { - "id": "@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 } - }, - "@cf/huggingface/distilbert-sst-2-int8": { - "id": "@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 } - }, - "@cf/facebook/bart-large-cnn": { - "id": "@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 } - }, - "@cf/baai/bge-base-en-v1.5": { - "id": "@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 } - }, - "@cf/baai/bge-small-en-v1.5": { - "id": "@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 } - }, - "@cf/baai/bge-large-en-v1.5": { - "id": "@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 } - }, - "@cf/baai/bge-reranker-base": { - "id": "@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 } - }, - "@cf/baai/bge-m3": { - "id": "@cf/baai/bge-m3", + "baai/bge-m3": { + "id": "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 } - }, - "@cf/pipecat-ai/smart-turn-v2": { - "id": "@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 } - }, - "@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"] }, + "temperature": false, + "release_date": "2024-01-30", + "last_updated": "2026-04-30", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.6, "output": 3, "cache_read": 0.1 }, - "limit": { "context": 256000, "output": 256000 } + "limit": { + "context": 8192, + "output": 1024 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "@cf/deepgram/aura-2-en": { - "id": "@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 } - }, - "@cf/deepgram/nova-3": { - "id": "@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 } - }, - "@cf/deepgram/aura-2-es": { - "id": "@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 } - }, - "@cf/mistral/mistral-7b-instruct-v0.1": { - "id": "@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 } - }, - "@cf/aisingapore/gemma-sea-lion-v4-27b-it": { - "id": "@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 } - }, - "@cf/meta/llama-3.3-70b-instruct-fp8-fast": { - "id": "@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 } - }, - "@cf/meta/llama-3-8b-instruct-awq": { - "id": "@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 } - }, - "@cf/meta/llama-3.2-1b-instruct": { - "id": "@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 } - }, - "@cf/meta/m2m100-1.2b": { - "id": "@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 } - }, - "@cf/meta/llama-3.1-8b-instruct": { - "id": "@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 } - }, - "@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": 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 } - }, - "@cf/meta/llama-3.2-11b-vision-instruct": { - "id": "@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 } - }, - "@cf/meta/llama-3-8b-instruct": { - "id": "@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 } - }, - "@cf/meta/llama-guard-3-8b": { - "id": "@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 } - }, - "@cf/meta/llama-3.2-3b-instruct": { - "id": "@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 } - }, - "@cf/meta/llama-3.1-8b-instruct-awq": { - "id": "@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 } - }, - "@cf/meta/llama-3.1-8b-instruct-fp8": { - "id": "@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 } - }, - "@cf/meta/llama-2-7b-chat-fp16": { - "id": "@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 } - }, - "@cf/pfnet/plamo-embedding-1b": { - "id": "@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 } - }, - "@cf/mistralai/mistral-small-3.1-24b-instruct": { - "id": "@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 } - } - } - }, - "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": { - "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-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-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 } - }, - "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 } - }, - "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 } - }, - "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-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-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.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.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-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.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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "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-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.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-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-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-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-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": { - "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": { - "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 } - }, - "ByteDance-Seed/Seed-OSS-36B-Instruct": { - "id": "ByteDance-Seed/Seed-OSS-36B-Instruct", + "bytedance/seed-oss-36b-instruct": { + "id": "bytedance/seed-oss-36b-instruct", "name": "ByteDance-Seed/Seed-OSS-36B-Instruct", "family": "seed", "attachment": false, @@ -62607,822 +82645,314 @@ "temperature": true, "release_date": "2025-09-04", "last_updated": "2025-11-25", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.21, "output": 0.57 }, - "limit": { "context": 262000, "output": 262000 } + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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-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-Next-80B-A3B-Thinking": { - "id": "Qwen/Qwen3-Next-80B-A3B-Thinking", - "name": "Qwen/Qwen3-Next-80B-A3B-Thinking", - "family": "qwen", + "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, - "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 } + "knowledge": "2025-05", + "release_date": "2026-04-24", + "last_updated": "2026-04-24", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 1048576, + "output": 393216 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } }, - "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/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", + "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, - "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/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-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-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-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/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-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-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/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-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/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-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/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-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-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-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/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-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-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-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-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/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-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-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-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-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-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 } - }, - "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/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 } - }, - "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.5": { - "id": "moonshotai/Kimi-K2.5", - "name": "moonshotai/Kimi-K2.5", - "family": "kimi", - "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", "image"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.55, "output": 3 }, - "limit": { "context": 262000, "output": 262000 } - }, - "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 } - }, - "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 } + "knowledge": "2025-05", + "release_date": "2026-04-24", + "last_updated": "2026-04-24", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 1048576, + "output": 393216 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } } } }, - "alibaba-coding-plan": { - "id": "alibaba-coding-plan", - "env": ["ALIBABA_CODING_PLAN_API_KEY"], + "inference": { + "id": "inference", + "env": ["INFERENCE_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", + "api": "https://inference.net/v1", + "name": "Inference", + "doc": "https://inference.net/models", "models": { - "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 } - }, - "qwen3-coder-next": { - "id": "qwen3-coder-next", - "name": "Qwen3 Coder Next", - "family": "qwen", + "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, - "structured_output": true, "temperature": true, - "release_date": "2026-02-03", - "last_updated": "2026-02-03", - "modalities": { "input": ["text"], "output": ["text"] }, + "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, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 262144, "output": 65536 } + "limit": { + "context": 16000, + "output": 4096 + }, + "cost": { + "input": 0.038, + "output": 0.1 + } }, - "kimi-k2.5": { - "id": "kimi-k2.5", - "name": "Kimi K2.5", - "family": "kimi", + "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": true, + "reasoning": false, "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"] }, + "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, "output": 0, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 262144, "output": 32768 } + "limit": { + "context": 16000, + "output": 4096 + }, + "cost": { + "input": 0.055, + "output": 0.055 + } }, - "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 } - }, - "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 } - }, - "qwen3-coder-plus": { - "id": "qwen3-coder-plus", - "name": "Qwen3 Coder Plus", - "family": "qwen", + "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": "2025-04", - "release_date": "2025-07-23", - "last_updated": "2025-07-23", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2023-12", + "release_date": "2025-01-01", + "last_updated": "2025-01-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0, "output": 0, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 1000000, "output": 65536 } + "limit": { + "context": 16000, + "output": 4096 + }, + "cost": { + "input": 0.01, + "output": 0.01 + } }, - "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 } - }, - "qwen3-max-2026-01-23": { - "id": "qwen3-max-2026-01-23", - "name": "Qwen3 Max", - "family": "qwen", + "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": "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 } + "knowledge": "2023-12", + "release_date": "2025-01-01", + "last_updated": "2025-01-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 16000, + "output": 4096 + }, + "cost": { + "input": 0.02, + "output": 0.02 + } + }, + "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, + "limit": { + "context": 16000, + "output": 4096 + }, + "cost": { + "input": 0.025, + "output": 0.025 + } + }, + "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, + "limit": { + "context": 125000, + "output": 4096 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 32000, + "output": 2048 + }, + "cost": { + "input": 0.01, + "output": 0 + } + }, + "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, + "limit": { + "context": 125000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 4000, + "output": 2048 + }, + "cost": { + "input": 0.1, + "output": 0.5 + } } } }, @@ -63434,19 +82964,29 @@ "name": "Inception", "doc": "https://platform.inceptionlabs.ai/docs", "models": { - "mercury-edit": { - "id": "mercury-edit", - "name": "Mercury Edit", + "mercury-edit-2": { + "id": "mercury-edit-2", + "name": "Mercury Edit 2", "attachment": false, "reasoning": true, "tool_call": false, "temperature": true, - "release_date": "2026-02-24", - "last_updated": "2026-02-24", - "modalities": { "input": ["text"], "output": ["text"] }, + "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 } + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.75, + "cache_read": 0.025 + } }, "mercury-2": { "id": "mercury-2", @@ -63460,702 +83000,388 @@ "knowledge": "2025-01-01", "release_date": "2026-02-24", "last_updated": "2026-02-24", - "modalities": { "input": ["text"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.25, "output": 0.75, "cache_read": 0.025 }, - "limit": { "context": 128000, "output": 50000 } - }, - "mercury-coder": { - "id": "mercury-coder", - "name": "Mercury Coder", - "family": "mercury", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2023-10", - "release_date": "2025-02-26", - "last_updated": "2025-07-31", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 1, "cache_read": 0.25, "cache_write": 1 }, - "limit": { "context": 128000, "output": 16384 } - }, - "mercury": { - "id": "mercury", - "name": "Mercury", - "family": "mercury", - "attachment": false, - "reasoning": false, - "tool_call": true, - "temperature": true, - "knowledge": "2023-10", - "release_date": "2025-06-26", - "last_updated": "2025-07-31", - "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, - "cost": { "input": 0.25, "output": 1, "cache_read": 0.25, "cache_write": 1 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 128000, + "output": 50000 + }, + "cost": { + "input": 0.25, + "output": 0.75, + "cache_read": 0.025 + } } } }, - "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", + "openai": { + "id": "openai", + "env": ["OPENAI_API_KEY"], + "npm": "@ai-sdk/openai", + "name": "OpenAI", + "doc": "https://platform.openai.com/docs/models", "models": { - "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.6v-flash": { - "id": "glm-4.6v-flash", - "name": "GLM-4.6V-Flash", - "family": "glm", + "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": 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, "output": 0 }, - "limit": { "context": 128000, "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": 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, "output": 0 }, - "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, "output": 0, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 131072, "output": 98304 } - }, - "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, "output": 0, "cache_read": 0, "cache_write": 0 }, - "limit": { "context": 204800, "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, "output": 0 }, - "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, "output": 0, "cache_read": 0, "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-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, "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-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 } - } - } - }, - "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-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-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-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", - "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 } + "knowledge": "2024-09-30", + "release_date": "2025-11-13", + "last_updated": "2025-11-13", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } }, - "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 } - } - } - }, - "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/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/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/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/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/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-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/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/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/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/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/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/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/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/kimi-k2-instruct": { - "id": "accounts/fireworks/models/kimi-k2-instruct", - "name": "Kimi K2 Instruct", - "family": "kimi", - "attachment": false, + "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": "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 } - } - } - }, - "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": { - "kimi-k2.5": { - "id": "kimi-k2.5", - "name": "Kimi K2.5", - "family": "kimi", + "knowledge": "2023-09", + "release_date": "2024-05-13", + "last_updated": "2024-05-13", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 5, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 65536 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "gpt-5.2-pro": { + "id": "gpt-5.2-pro", + "name": "GPT-5.2 Pro", + "family": "gpt-pro", "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 } + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 21, + "output": 168 + } }, - "minimax-m2.7": { - "id": "minimax-m2.7", - "name": "MiniMax M2.7", - "family": "minimax-m2.7", + "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, + "limit": { + "context": 8191, + "output": 3072 + }, + "cost": { + "input": 0.13, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "gpt-5.5": { + "id": "gpt-5.5", + "name": "GPT-5.5", + "family": "gpt", + "attachment": true, "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" } + "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, + "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" + } + } + } + } + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + } + } }, - "glm-5": { - "id": "glm-5", - "name": "GLM-5", - "family": "glm", - "attachment": false, + "gpt-5-mini": { + "id": "gpt-5-mini", + "name": "GPT-5 Mini", + "family": "gpt-mini", + "attachment": true, "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 } + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } }, - "minimax-m2.5": { - "id": "minimax-m2.5", - "name": "MiniMax M2.5", - "family": "minimax-m2.5", - "attachment": false, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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": "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": 131072 }, - "provider": { "npm": "@ai-sdk/anthropic" } - } - } - }, - "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.2-codex": { - "id": "gpt-5.2-codex", - "name": "GPT-5.2 Codex", + "knowledge": "2023-12", + "release_date": "2023-11-06", + "last_updated": "2024-04-09", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "gpt-5.2": { + "id": "gpt-5.2", + "name": "GPT-5.2", "family": "gpt", "attachment": true, "reasoning": true, @@ -64165,41 +83391,526 @@ "knowledge": "2025-08-31", "release_date": "2025-12-11", "last_updated": "2025-12-11", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.75, "output": 14 }, - "limit": { "context": 400000, "input": 272000, "output": 128000 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } }, - "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 } - }, - "claude-opus-4-5-20251101": { - "id": "claude-opus-4-5-20251101", - "name": "Claude Opus 4.5", - "family": "claude-opus", + "o3-pro": { + "id": "o3-pro", + "name": "o3-pro", + "family": "o-pro", "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"] }, + "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": 5, "output": 25 }, - "limit": { "context": 200000, "output": 64000 } + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 20, + "output": 80 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "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" + } + } + } + } + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "tiers": [ + { + "input": 60, + "output": 270, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 60, + "output": 270 + } + } + }, + "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, + "limit": { + "context": 16385, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 1.5, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 10, + "output": 40, + "cache_read": 2.5 + } }, "o3-mini": { "id": "o3-mini", @@ -64208,304 +83919,130 @@ "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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.1, "output": 4.4 }, - "limit": { "context": 200000, "output": 100000 } + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } }, - "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": { - "id": "gpt-5", - "name": "GPT-5", - "family": "gpt", - "attachment": true, - "reasoning": true, - "tool_call": true, + "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-09-30", - "release_date": "2025-08-07", - "last_updated": "2025-08-07", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "knowledge": "2024-01", + "release_date": "2024-01-25", + "last_updated": "2024-01-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.25, "output": 10 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 8191, + "output": 1536 + }, + "cost": { + "input": 0.02, + "output": 0 + } }, - "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 } - }, - "gemini-3.1-pro-preview": { - "id": "gemini-3.1-pro-preview", - "name": "Gemini 3.1 Pro Preview", - "family": "gemini-pro", + "o1-pro": { + "id": "o1-pro", + "name": "o1-pro", + "family": "o-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"] }, + "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": 2, "output": 12 }, - "limit": { "context": 1048576, "output": 65536 } + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 150, + "output": 600 + } }, - "claude-3-7-sonnet-20250219": { - "id": "claude-3-7-sonnet-20250219", - "name": "Claude Sonnet 3.7", - "family": "claude-sonnet", + "gpt-4": { + "id": "gpt-4", + "name": "GPT-4", + "family": "gpt", "attachment": true, - "reasoning": true, + "reasoning": false, "tool_call": true, + "structured_output": false, "temperature": true, - "knowledge": "2024-10-31", - "release_date": "2025-02-19", - "last_updated": "2025-02-19", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "knowledge": "2023-11", + "release_date": "2023-11-06", + "last_updated": "2024-04-09", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 3, "output": 15 }, - "limit": { "context": 200000, "output": 64000 } + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 30, + "output": 60 + } }, - "kimi-k2.5": { - "id": "kimi-k2.5", - "name": "Kimi K2.5", - "family": "kimi", + "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": 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 } - }, - "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 } - }, - "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.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 } - }, - "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 } - }, - "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", - "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 } - }, - "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 } - }, - "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 } - }, - "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"] }, + "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-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", - "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 } - }, - "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-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 } - }, - "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 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } }, "gpt-5.4": { "id": "gpt-5.4", @@ -64519,10 +84056,156 @@ "knowledge": "2025-08-31", "release_date": "2026-03-05", "last_updated": "2026-03-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 2.5, "output": 15 }, - "limit": { "context": 1050000, "input": 922000, "output": 128000 } + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "experimental": { + "modes": { + "fast": { + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5 + }, + "provider": { + "body": { + "service_tier": "priority" + } + } + } + } + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tiers": [ + { + "input": 5, + "output": 22.5, + "cache_read": 0.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 5, + "output": 22.5, + "cache_read": 0.5 + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 128000, + "input": 100000, + "output": 32000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.03 + } }, "o3": { "id": "o3", @@ -64531,152 +84214,278 @@ "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"] }, + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 2, "output": 8 }, - "limit": { "context": 200000, "output": 100000 } + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } }, - "grok-4-1-fast-non-reasoning": { - "id": "grok-4-1-fast-non-reasoning", - "name": "Grok 4.1 Fast (Non-Reasoning)", - "family": "grok", + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 272000 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "gpt-4o": { + "id": "gpt-4o", + "name": "GPT-4o", + "family": "gpt", "attachment": true, "reasoning": false, "tool_call": true, + "structured_output": true, "temperature": true, - "release_date": "2025-11-17", - "last_updated": "2025-11-17", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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": 0.2, "output": 0.5 }, - "limit": { "context": 2000000, "output": 16384 } + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } }, - "gpt-5.3-chat-latest": { - "id": "gpt-5.3-chat-latest", - "name": "GPT-5.3 Chat Latest", + "gpt-5": { + "id": "gpt-5", + "name": "GPT-5", "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"] }, + "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.75, "output": 14 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } }, - "claude-sonnet-4-20250514": { - "id": "claude-sonnet-4-20250514", - "name": "Claude Sonnet 4", - "family": "claude-sonnet", + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, - "temperature": true, - "release_date": "2025-05-14", - "last_updated": "2025-05-14", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "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": 3, "output": 15 }, - "limit": { "context": 200000, "output": 64000 } + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "tiers": [ + { + "input": 60, + "output": 270, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 60, + "output": 270 + } + } }, - "grok-4-0709": { - "id": "grok-4-0709", - "name": "Grok 4", - "family": "grok", + "gpt-4.1": { + "id": "gpt-4.1", + "name": "GPT-4.1", + "family": "gpt", "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 } - }, - "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 } - }, - "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 } - }, - "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 } - }, - "kimi-k2-turbo-preview": { - "id": "kimi-k2-turbo-preview", - "name": "Kimi K2 Turbo Preview", - "family": "kimi", - "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"] }, + "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.15, "output": 8 }, - "limit": { "context": 256000, "output": 8192 } + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } }, - "gemini-2.5-flash": { - "id": "gemini-2.5-flash", - "name": "Gemini 2.5 Flash", - "family": "gemini-flash", + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "gpt-5.1-codex": { + "id": "gpt-5.1-codex", + "name": "GPT-5.1 Codex", + "family": "gpt-codex", "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"] }, + "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.3, "output": 2.5 }, - "limit": { "context": 1048576, "output": 65536 } + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } }, "gpt-4o-2024-11-20": { "id": "gpt-4o-2024-11-20", @@ -64685,80 +84494,197 @@ "attachment": true, "reasoning": false, "tool_call": true, + "structured_output": true, "temperature": true, - "knowledge": "2024-10", + "knowledge": "2023-09", "release_date": "2024-11-20", "last_updated": "2024-11-20", - "modalities": { "input": ["text", "image", "audio"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 2.5, "output": 10 }, - "limit": { "context": 128000, "output": 16384 } - }, - "gpt-5.2": { - "id": "gpt-5.2", - "name": "GPT-5.2", - "family": "gpt", + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + } + } + }, + "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, + "limit": { + "context": 2000000, + "output": 64000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05, + "cache_write": 0.2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75, + "cache_write": 3 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.75, "output": 14 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 21, + "output": 168 + } }, - "gpt-5.1": { - "id": "gpt-5.1", - "name": "GPT-5.1", - "family": "gpt", + "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-09-30", - "release_date": "2025-11-13", - "last_updated": "2025-11-13", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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": 1.25, "output": 10 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.03 + } }, - "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 } - }, - "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-nano": { - "id": "gpt-5-nano", + "openai/gpt-5-nano": { + "id": "openai/gpt-5-nano", "name": "GPT-5 Nano", "family": "gpt-nano", "attachment": true, @@ -64768,26 +84694,18421 @@ "knowledge": "2024-05-30", "release_date": "2025-08-07", "last_updated": "2025-08-07", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.05, "output": 0.4 }, - "limit": { "context": 400000, "output": 128000 } + "limit": { + "context": 16000, + "output": 4000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.01 + } }, - "gemini-3.1-flash-lite-preview": { - "id": "gemini-3.1-flash-lite-preview", + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "output": 100000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "cache_read": 30 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "cache_write": 4.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.075, + "cache_write": 0.55 + } + }, + "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, + "limit": { + "context": 200000, + "output": 62000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5 + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "context_over_200k": { + "input": 5, + "output": 22.5, + "cache_read": 0.5 + }, + "tiers": [ + { + "input": 5, + "output": 22.5, + "cache_read": 0.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 400000, + "output": 272000 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "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 + }, + "tiers": [ + { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 512, + "output": 768 + }, + "cost": { + "input": 0.009, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 2.7 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.198, + "output": 0.198 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.3, + "cache_write": 3.75, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.3, + "cache_write": 3.75 + } + } + }, + "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, + "limit": { + "context": 100, + "output": 1 + }, + "cost": { + "input": 0.6, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 262144, + "output": 81920 + }, + "cost": { + "input": 0.55, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 512, + "output": 1024 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 21, + "output": 168 + } + }, + "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, + "limit": { + "context": 202752, + "output": 128000 + }, + "cost": { + "input": 1, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.65, + "output": 0.65 + } + }, + "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, + "limit": { + "context": 262144, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.99, + "output": 0.99 + } + }, + "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, + "limit": { + "context": 131000, + "output": 40960 + }, + "cost": { + "input": 0.25, + "output": 0.55 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "status": "deprecated", + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 256, + "output": 1 + }, + "cost": { + "input": 0.08, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 16384 + }, + "cost": { + "input": 0.25, + "output": 0.87 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.3, + "cache_write": 3.75, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.3, + "cache_write": 3.75 + } + } + }, + "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, + "limit": { + "context": 8000, + "output": 1024 + }, + "status": "beta", + "cost": { + "input": 0.04, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1024 + }, + "cost": { + "input": 0.09, + "output": 0 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.5, + "output": 1.6 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.05, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.45, + "output": 1.7 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.1, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.18, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.3, + "cache_write": 3.75, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.3, + "cache_write": 3.75 + } + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 393216 + }, + "cost": { + "input": 1.74, + "output": 3.48 + } + }, + "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, + "limit": { + "context": 204800, + "output": 128000 + }, + "status": "beta", + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 0, + "output": 0 + }, + "cost": { + "input": 5, + "output": 40, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 32768 + }, + "status": "beta", + "cost": { + "input": 0.3, + "output": 0.65 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180 + } + }, + "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, + "limit": { + "context": 256, + "output": 384 + }, + "cost": { + "input": 0.009, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1024 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 0.5, + "cache_write": 6.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 37.5, + "cache_read": 0.5, + "cache_write": 6.25 + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 256000, + "output": 128000 + }, + "status": "beta", + "cost": { + "input": 0.25, + "output": 0.9, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "status": "deprecated", + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1 + }, + "cost": { + "input": 0.01, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "status": "deprecated", + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 0, + "output": 0 + }, + "cost": { + "input": 5, + "output": 10, + "cache_read": 1 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 194000, + "output": 4096 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.85, + "output": 3.1 + } + }, + "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, + "limit": { + "context": 127000, + "output": 4096 + }, + "cost": { + "input": 0.55, + "output": 1.65 + } + }, + "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, + "limit": { + "context": 129000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 254000, + "output": 32768 + }, + "cost": { + "input": 0.55, + "output": 2.75 + } + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 196608, + "output": 24576 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2, + "output": 5 + } + }, + "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, + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.7, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 256000, + "output": 4096 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 8000, + "output": 3072 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.04, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 64000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.5, + "output": 7.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 8000, + "output": 8000 + }, + "cost": { + "input": 0.25, + "output": 0.25 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.5, + "output": 7.5 + } + } + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.74, + "output": 0.74 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.11, + "output": 0.11 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.09, + "output": 0.25 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 1.01, + "output": 1.01 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.07, + "output": 0.26 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.05, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.1, + "output": 0.31 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.1, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.09, + "output": 0.47 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.14, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.11, + "output": 0.11 + } + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.2, + "output": 0.8 + } + }, + "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, + "limit": { + "context": 202752, + "output": 202752 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } + }, + "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, + "limit": { + "context": 202752, + "output": 202752 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8000 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + } + } + }, + "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, + "limit": { + "context": 202752, + "output": 196072 + }, + "cost": { + "input": 0.47, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 1.09, + "output": 5.43 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.062, + "output": 0.408 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.55, + "output": 2.76 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.551, + "output": 1.654 + } + }, + "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, + "limit": { + "context": 198000, + "output": 198000 + }, + "cost": { + "input": 0.45, + "output": 2.23 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5.6, + "output": 27.99, + "cache_read": 0.56, + "cache_write": 6.99 + } + }, + "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, + "limit": { + "context": 202752, + "output": 202752 + }, + "cost": { + "input": 1.08, + "output": 3.44 + } + }, + "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, + "limit": { + "context": 300000, + "output": 5000 + }, + "cost": { + "input": 1.016, + "output": 4.061 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.099, + "output": 0.33 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.3, + "output": 0.9, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 3.259, + "output": 16.296 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.551, + "output": 2.646 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.266, + "output": 0.799 + } + }, + "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, + "limit": { + "context": 400000, + "output": 400000 + }, + "cost": { + "input": 0.39, + "output": 1.57 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65535 + }, + "cost": { + "input": 1.654, + "output": 11.024 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 1000000 + }, + "cost": { + "input": 5.98, + "output": 29.89 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 196000, + "output": 196000 + }, + "cost": { + "input": 0.34, + "output": 1.34 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 1.31, + "output": 4.1, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.67, + "output": 2.46 + } + }, + "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, + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 5.98, + "output": 29.89 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3.307, + "output": 16.536 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.164, + "output": 1.311 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.22, + "output": 1.34 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.81, + "output": 3.54, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 0.158, + "output": 0.84 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 1000000 + }, + "cost": { + "input": 3.59, + "output": 17.92 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.441, + "output": 1.984 + } + }, + "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, + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.438, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.116, + "output": 0.358 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.32, + "output": 1.18 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.266, + "output": 0.444 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.219, + "output": 1.202 + } + }, + "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, + "limit": { + "context": 203000, + "output": 203000 + }, + "cost": { + "input": 0.09, + "output": 0.53 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 33000, + "output": 33000 + }, + "cost": { + "input": 0.062, + "output": 0.231 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.585, + "output": 2.307 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2.354, + "output": 9.417 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.656, + "output": 2.731 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.444, + "output": 3.106 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.089, + "output": 0.275 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.5, + "output": 1.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 250000, + "output": 250000 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 384000 + }, + "cost": { + "input": 0.133, + "output": 0.266, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 384000 + }, + "cost": { + "input": 1.553, + "output": 3.106, + "cache_read": 0.145 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.053, + "output": 0.222 + } + } + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 131000, + "output": 4000 + }, + "cost": { + "input": 0.59, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.2, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 262000, + "output": 131000 + }, + "cost": { + "input": 0.09, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.45, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.05, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.18, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.29, + "output": 1 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.15, + "output": 0.58 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.35, + "output": 1.42 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.18, + "output": 2 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.05, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.14, + "output": 1.4 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.06, + "output": 0.06 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.09, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.09, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 131000, + "output": 4000 + }, + "cost": { + "input": 0.59, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.18, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.13, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.1, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.27, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.3, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.29, + "output": 1 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.18, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.59, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 1.2, + "output": 4, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 205000, + "output": 205000 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 205000, + "output": 205000 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.86 + } + }, + "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, + "limit": { + "context": 205000, + "output": 205000 + }, + "cost": { + "input": 1, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 205000, + "output": 205000 + }, + "cost": { + "input": 0.5, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.14, + "output": 0.86 + } + }, + "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, + "limit": { + "context": 33000, + "output": 4000 + }, + "cost": { + "input": 0.06, + "output": 0.06 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.07, + "output": 0.28 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 33000, + "output": 33000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 4000, + "output": 4000 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.18, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.5, + "output": 2.18 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 0.41 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 0.42 + } + }, + "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, + "limit": { + "context": 164000, + "output": 164000 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 131000, + "output": 8000 + }, + "cost": { + "input": 0.04, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 131000, + "output": 8000 + }, + "cost": { + "input": 0.05, + "output": 0.45 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.28, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.086, + "output": 0.086 + } + }, + "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, + "limit": { + "context": 33000, + "output": 33000 + }, + "cost": { + "input": 0.086, + "output": 0.086 + } + }, + "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, + "limit": { + "context": 33000, + "output": 33000 + }, + "cost": { + "input": 0.27, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.14, + "output": 0.57 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.55, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.58, + "output": 2.29 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.45, + "output": 2.25 + } + }, + "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, + "limit": { + "context": 197000, + "output": 131000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 197000, + "output": 131000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.21, + "output": 0.57 + } + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 1000000 + }, + "cost": { + "input": 1, + "output": 5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.6, + "output": 3.5999999999999996 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0 + } + }, + "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, + "limit": { + "context": 40960, + "output": 16384 + }, + "cost": { + "input": 0.08, + "output": 0.29 + } + }, + "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, + "limit": { + "context": 40960, + "output": 16384 + }, + "cost": { + "input": 0.13, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.001, + "cache_write": 0.125 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.09999999999999999, + "cache_write": 0.625 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 1.2, + "output": 6 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.01, + "output": 0 + } + }, + "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, + "limit": { + "context": 40960, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 240000, + "output": 64000 + }, + "cost": { + "input": 1.3, + "output": 7.8, + "cache_read": 0.26, + "cache_write": 1.625 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 129024 + }, + "cost": { + "input": 0.7, + "output": 8.4 + } + }, + "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, + "limit": { + "context": 262114, + "output": 262114 + }, + "cost": { + "input": 0.3, + "output": 2.9 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.09, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.5, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 65536 + }, + "cost": { + "input": 1.2, + "output": 6, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 131072, + "output": 129024 + }, + "cost": { + "input": 0.39999999999999997, + "output": 1.5999999999999999 + } + }, + "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, + "limit": { + "context": 262144, + "output": 66536 + }, + "cost": { + "input": 0.38, + "output": 1.53 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 1.2, + "output": 6, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0.4, + "output": 2.4, + "cache_read": 0.04, + "cache_write": 0.5 + } + }, + "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, + "limit": { + "context": 40960, + "output": 16384 + }, + "cost": { + "input": 0.06, + "output": 0.24 + } + }, + "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, + "limit": { + "context": 131072, + "output": 129024 + }, + "cost": { + "input": 0.7, + "output": 2.8 + } + }, + "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, + "limit": { + "context": 160000, + "output": 32768 + }, + "cost": { + "input": 0.07, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 127000, + "output": 8000 + }, + "cost": { + "input": 1, + "output": 1 + } + }, + "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, + "limit": { + "context": 127000, + "output": 8000 + }, + "cost": { + "input": 1, + "output": 5 + } + }, + "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, + "limit": { + "context": 127000, + "output": 8000 + }, + "cost": { + "input": 2, + "output": 8 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.28, + "output": 0.42, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 0.27, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 163840, + "output": 128000 + }, + "cost": { + "input": 0.3, + "output": 1 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } + }, + "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, + "limit": { + "context": 163842, + "output": 8000 + }, + "cost": { + "input": 0.27, + "output": 0.4, + "cache_read": 0.22 + } + }, + "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, + "limit": { + "context": 163840, + "output": 16384 + }, + "cost": { + "input": 0.77, + "output": 0.77 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.27, + "output": 1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.05, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 262100, + "output": 80000 + }, + "cost": { + "input": 0.25, + "output": 0.8999999999999999 + } + }, + "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, + "limit": { + "context": 131000, + "output": 131000 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.18, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.18, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.12, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.12, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.12, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.06, + "output": 0 + } + }, + "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, + "limit": { + "context": 32000, + "output": 32000 + }, + "cost": { + "input": 0.9, + "output": 1.9 + } + }, + "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, + "limit": { + "context": 16000, + "output": 16000 + }, + "cost": { + "input": 0.8, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 1.2, + "output": 4, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 202752, + "output": 120000 + }, + "cost": { + "input": 0.43, + "output": 1.75, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 202800, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "cost": { + "input": 0.06, + "output": 0.4, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 202752, + "output": 202752 + }, + "cost": { + "input": 1.4, + "output": 4.4, + "cache_read": 0.26 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 96000 + }, + "cost": { + "input": 0.2, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 202800, + "output": 131100 + }, + "cost": { + "input": 1.2, + "output": 4, + "cache_read": 0.24 + } + }, + "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, + "limit": { + "context": 66000, + "output": 66000 + }, + "cost": { + "input": 0.6, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 200000, + "output": 96000 + }, + "cost": { + "input": 0.45, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 128000, + "output": 24000 + }, + "cost": { + "input": 0.3, + "output": 0.9, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131000 + }, + "cost": { + "input": 0.07, + "output": 0.39999999999999997 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.12, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 1000000 + }, + "cost": { + "input": 1.25, + "output": 2.5, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 256000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "reasoning": 0.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 8192, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 10, + "cache_read": 2 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "reasoning": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 4, + "reasoning": 4, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0.15, + "output": 0.65 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.06, + "output": 0.24 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.04, + "output": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 0.75, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 0.75, + "cache_read": 0.024999999999999998 + } + }, + "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, + "limit": { + "context": 32000, + "output": 16384 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.18 + } + }, + "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, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 200000, + "input": 100000, + "output": 100000 + }, + "cost": { + "input": 1.5, + "output": 6, + "cache_read": 0.38 + } + }, + "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, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 21, + "output": 168 + } + }, + "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, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + }, + "cost": { + "input": 0.13, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 872000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.18 + } + }, + "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, + "limit": { + "context": 200000, + "input": 100000, + "output": 100000 + }, + "cost": { + "input": 20, + "output": 80 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.19999999999999998, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180 + } + }, + "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, + "limit": { + "context": 16385, + "input": 12289, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 200000, + "input": 100000, + "output": 100000 + }, + "cost": { + "input": 10, + "output": 40, + "cache_read": 2.5 + } + }, + "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, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + }, + "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, + "limit": { + "context": 131072, + "input": 98304, + "output": 32768 + }, + "cost": { + "input": 0.07, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 400000, + "input": 128000, + "output": 272000 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "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, + "limit": { + "context": 131072, + "input": 65536, + "output": 65536 + }, + "cost": { + "input": 0.08, + "output": 0.3, + "cache_read": 0.04 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.1, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 1000000, + "input": 872000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180 + } + }, + "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, + "limit": { + "context": 8192, + "input": 4096, + "output": 4096 + }, + "cost": { + "input": 1.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 1000000 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 300000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 3.2, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 300000, + "output": 8192 + }, + "cost": { + "input": 0.06, + "output": 0.24, + "cache_read": 0.015 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.035, + "output": 0.14, + "cache_read": 0.00875 + } + }, + "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, + "limit": { + "context": 60288, + "output": 16000 + }, + "cost": { + "input": 0.04, + "output": 0.17 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.15, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 64000 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2, + "output": 5 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 64000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.04, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 256000, + "output": 4096 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.03, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.72, + "output": 0.72 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.16, + "output": 0.16 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131000 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131100 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 262114, + "output": 262114 + }, + "cost": { + "input": 0.27, + "output": 1.15, + "cache_read": 0.03, + "cache_write": 0.38 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.38 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 2.4, + "cache_read": 0.03, + "cache_write": 0.38 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131000 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 0, + "output": 0 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65000 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 65536, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 120 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.15, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.14, + "output": 0.39999999999999997 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.03, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.03, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65000 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.03, + "cache_write": 0.383 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.13, + "output": 0.39999999999999997 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, - "release_date": "2026-03-01", - "last_updated": "2026-03-01", - "modalities": { "input": ["text", "image", "audio", "video", "pdf"], "output": ["text"] }, + "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.25, "output": 1.5, "cache_read": 0.025, "cache_write": 1 }, - "limit": { "context": 1048576, "output": 65536 } + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.03, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125, + "tiers": [ + { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 2.4, + "output": 10 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262114, + "output": 262114 + }, + "cost": { + "input": 1.15, + "output": 8, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 262000, + "output": 262000 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 216144, + "output": 216144 + }, + "cost": { + "input": 0.47, + "output": 2, + "cache_read": 0.14 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "status": "deprecated", + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32000 + }, + "cost": { + "input": 1.5, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5 + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 0.25, + "output": 1.25, + "cache_read": 0.03, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 131000 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 1050000, + "output": 131100 + }, + "cost": { + "input": 0.39999999999999997, + "output": 2, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.19999999999999998 + } + }, + "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, + "limit": { + "context": 262144, + "output": 32000 + }, + "cost": { + "input": 0.1, + "output": 0.29 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 196608, + "output": 128000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.06, + "cache_write": 0.375 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 32768, + "output": 16384 + }, + "status": "beta", + "cost": { + "input": 0.18, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.14, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.5, + "output": 1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16000 + }, + "cost": { + "input": 0.04, + "output": 0.4, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 16384 + }, + "cost": { + "input": 0.08, + "output": 0.08 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 16384 + }, + "cost": { + "input": 0.08, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.07, + "output": 0.3, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 1.6, + "output": 6.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16000 + }, + "status": "beta", + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 1.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0.17, + "output": 0.66 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.03, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 262144, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.27, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 128000, + "output": 2048 + }, + "status": "beta", + "cost": { + "input": 0.72, + "output": 0.72 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "status": "beta", + "cost": { + "input": 2.2, + "output": 8.9, + "cache_read": 0.45 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.56, + "output": 1.68, + "cache_read": 0.11 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.6, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0.24, + "output": 0.97 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 196608, + "output": 131072 + }, + "cost": { + "input": 0.12, + "output": 0.48 + } + }, + "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, + "limit": { + "context": 256000, + "output": 32800 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.6 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32000 + }, + "cost": { + "input": 0.03, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.8, + "output": 4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 163840, + "output": 16384 + }, + "cost": { + "input": 0.28, + "output": 0.42, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.5, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32766 + }, + "cost": { + "input": 0.1, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.04, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32766 + }, + "cost": { + "input": 0.15, + "output": 0.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.05, + "output": 0.05 + } + }, + "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, + "limit": { + "context": 128000, + "output": 2048 + }, + "status": "beta", + "cost": { + "input": 0.22, + "output": 0.22 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8000 + }, + "cost": { + "input": 0.51, + "output": 0.74 + } + }, + "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, + "limit": { + "context": 64000, + "output": 16384 + }, + "status": "beta", + "cost": { + "input": 0.8, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.1, + "output": 4.5, + "cache_read": 0.22 + } + }, + "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, + "limit": { + "context": 262144, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.07, + "output": 0.33 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "context_over_200k": { + "input": 4, + "output": 12, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 4, + "output": 12, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1, + "output": 5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 8192, + "output": 2000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 21, + "output": 168 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 2.4 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "input_audio": 0.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.21, + "output": 0.63 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.7, + "output": 2.8, + "reasoning": 8.4 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.07, + "output": 0.4, + "cache_read": 0.01, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 1.6, + "output": 6.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.2, + "reasoning": 4 + } + }, + "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, + "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" + } + } + } + } + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.248, + "output": 1.485 + } + }, + "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, + "limit": { + "context": 32768, + "output": 2048 + }, + "cost": { + "input": 0.07, + "output": 0.27, + "input_audio": 4.44, + "output_audio": 8.89 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 196608, + "output": 128000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 32768 + }, + "cost": { + "input": 0.05, + "output": 0.4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125, + "context_over_200k": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + }, + "tiers": [ + { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08, + "context_over_200k": { + "input": 0.8, + "output": 4, + "cache_read": 0.16 + }, + "tiers": [ + { + "input": 0.8, + "output": 4, + "cache_read": 0.16, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 2, + "output": 6, + "cache_read": 0.2, + "context_over_200k": { + "input": 4, + "output": 12, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 4, + "output": 12, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "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 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.2, + "cache_write": 2.5, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 1.2, + "output": 6 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 6, + "output": 24, + "cache_read": 1.3, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.03, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "input_audio": 0.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 6 + } + }, + "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, + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.15, + "output": 8, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.2, + "output": 1.1, + "cache_read": 0.03, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180 + } + }, + "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, + "limit": { + "context": 16385, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 1.5, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 3.2 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 1, + "output": 1 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 30000 + }, + "cost": { + "input": 1.25, + "output": 2.5, + "cache_read": 0.2, + "context_over_200k": { + "input": 2.5, + "output": 5, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2.5, + "output": 5, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 64000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 0.14, + "output": 0.28, + "cache_read": 0.028 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "reasoning": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 30, + "output": 60 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } }, "claude-haiku-4-5-20251001": { "id": "claude-haiku-4-5-20251001", @@ -64800,74 +103121,5673 @@ "knowledge": "2025-02-28", "release_date": "2025-10-15", "last_updated": "2025-10-15", - "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }, + "modalities": { + "input": ["text", "image", "pdf"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1, "output": 5 }, - "limit": { "context": 200000, "output": 64000 } + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } }, - "qwen3-max": { - "id": "qwen3-max", - "name": "Qwen3 Max", + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "qwen3-vl-plus": { + "id": "qwen3-vl-plus", + "name": "Qwen3-VL Plus", "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"] }, + "knowledge": "2025-04", + "release_date": "2025-09-23", + "last_updated": "2025-09-23", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.2, "output": 6 }, - "limit": { "context": 131072, "output": 16384 } + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0.2, + "output": 1.6, + "reasoning": 4.8 + } }, - "o3-pro": { - "id": "o3-pro", - "name": "o3-pro", - "family": "o-pro", + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 1.5, + "output": 7.5 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 384000 + }, + "cost": { + "input": 1.74, + "output": 3.48, + "cache_read": 0.145 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.45, + "output": 2.25 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ] + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 272000 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 16384 + }, + "cost": { + "input": 0.05, + "output": 0.2, + "reasoning": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.01, + "input_audio": 0.3 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 1.3, + "output": 7.8, + "cache_read": 0.13, + "cache_write": 1.625 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 2.8, + "output": 8.4 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "context_over_200k": { + "input": 60, + "output": 270 + }, + "tiers": [ + { + "input": 60, + "output": 270, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 2, + "output": 8 + } + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.075, + "cache_write": 0.383 + } + }, + "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, + "limit": { + "context": 65536, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.075, + "cache_write": 0.383 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.075, + "cache_write": 0.383 + } + }, + "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, + "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" + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.1 + } + }, + "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, + "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" + }, + "cost": { + "input": 0.6, + "output": 2.2 + } + }, + "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, + "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" + }, + "cost": { + "input": 0.56, + "output": 1.68, + "cache_read": 0.056 + } + }, + "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, + "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" + }, + "cost": { + "input": 0.6, + "output": 1.7 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.09, + "output": 0.36 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.07, + "output": 0.25 + } + }, + "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, + "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" + }, + "cost": { + "input": 0.72, + "output": 0.72 + } + }, + "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, + "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" + }, + "cost": { + "input": 0.35, + "output": 1.15 + } + }, + "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, + "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" + }, + "cost": { + "input": 0.22, + "output": 0.88 + } + }, + "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, + "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" + }, + "cost": { + "input": 0.6, + "output": 2.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "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 + }, + "tiers": [ + { + "input": 6, + "output": 22.5, + "cache_read": 0.6, + "cache_write": 7.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "input_audio": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + }, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.0375 + } + }, + "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, + "limit": { + "context": 2048, + "output": 3072 + }, + "cost": { + "input": 0.15, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125, + "context_over_200k": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + }, + "tiers": [ + { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "input_audio": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.0375 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.01, + "input_audio": 0.3 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "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 + }, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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": "2024-05", - "release_date": "2025-06-10", - "last_updated": "2025-06-10", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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": 20, "output": 40 }, - "limit": { "context": 200000, "output": 100000 } + "limit": { + "context": 1000000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/google-vertex/anthropic" + }, + "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 + }, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ] + } + } + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.06, + "output": 0.4 + } }, - "gpt-4.1-nano": { - "id": "gpt-4.1-nano", - "name": "GPT-4.1 Nano", + "@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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "@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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.2, + "output": 0.3 + } + }, + "@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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.35, + "output": 0.75 + } + }, + "@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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.27, + "output": 0.85 + } + }, + "@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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "@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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "@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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + } + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "status": "deprecated", + "cost": { + "input": 0.79, + "output": 0.79 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 0.75, + "output": 0.99 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.59, + "output": 0.79 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 448, + "output": 448 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.05, + "output": 0.08 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 0.59, + "output": 0.79 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "status": "deprecated", + "cost": { + "input": 0.29, + "output": 0.39 + } + }, + "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, + "limit": { + "context": 448, + "output": 448 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 0.05, + "output": 0.08 + } + }, + "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, + "limit": { + "context": 4000, + "output": 50000 + }, + "cost": { + "input": 40, + "output": 0 + } + }, + "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, + "limit": { + "context": 4000, + "output": 50000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.11, + "output": 0.34 + } + }, + "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, + "limit": { + "context": 512, + "output": 512 + }, + "cost": { + "input": 0.03, + "output": 0.03 + } + }, + "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, + "limit": { + "context": 131072, + "output": 1024 + }, + "status": "deprecated", + "cost": { + "input": 0.2, + "output": 0.2 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "status": "deprecated", + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 512, + "output": 512 + }, + "cost": { + "input": 0.04, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.075, + "output": 0.3, + "cache_read": 0.037 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 40960 + }, + "cost": { + "input": 0.29, + "output": 0.59 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "status": "deprecated", + "cost": { + "input": 1, + "output": 3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 3 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.5, + "output": 6, + "cache_read": 0.375 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.08, + "output": 0.32, + "input_audio": 4 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.13, + "output": 0.52 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.78 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "status": "beta", + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 4096, + "output": 1024 + }, + "cost": { + "input": 0.17, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.04, + "output": 0.04 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.61 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/models", + "shape": "completions" + }, + "cost": { + "input": 0.6, + "output": 3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.71, + "output": 0.71 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 1.14, + "output": 4.56 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.16, + "output": 0.64 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 128000, + "output": 65536 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 8191, + "output": 3072 + }, + "cost": { + "input": 0.13, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.13, + "output": 0.52 + } + }, + "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, + "limit": { + "context": 32000, + "output": 4096 + }, + "cost": { + "input": 0.125, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 2.68, + "output": 3.54 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 8192, + "output": 1536 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 2.04, + "output": 2.04 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "status": "beta", + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.58, + "output": 1.68 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 256000, + "output": 8000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.37, + "output": 0.37 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 5.33, + "output": 16 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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": "2024-04", - "release_date": "2025-04-14", - "last_updated": "2025-04-14", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "knowledge": "2023-11", + "release_date": "2023-11-06", + "last_updated": "2024-04-09", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 0.1, "output": 0.4 }, - "limit": { "context": 1047576, "output": 32768 } + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } }, - "gpt-5-codex": { - "id": "gpt-5-codex", - "name": "GPT-5 Codex", - "family": "gpt", + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.75, + "output": 14, + "cache_read": 0.175 + } + }, + "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, + "limit": { + "context": 128000, + "output": 1536 + }, + "cost": { + "input": 0.12, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.5, + "output": 1.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 16.5, + "output": 66, + "cache_read": 8.25 + } + }, + "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, + "limit": { + "context": 512, + "output": 1024 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 262000, + "output": 8192 + }, + "status": "beta", + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 15, + "output": 60, + "cache_read": 7.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.14, + "output": 0 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 2 + } + }, + "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, + "limit": { + "context": 8191, + "output": 1536 + }, + "cost": { + "input": 0.02, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.56, + "output": 1.68 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 4096, + "output": 1024 + }, + "cost": { + "input": 0.13, + "output": 0.52 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 2.68, + "output": 3.54 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 60, + "output": 120 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0.3, + "output": 0.61 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "provider": { + "npm": "@ai-sdk/openai-compatible", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/models", + "shape": "completions" + }, + "cost": { + "input": 0.95, + "output": 4 + } + }, + "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"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.25, "output": 10 }, - "limit": { "context": 400000, "input": 272000, "output": 128000 } + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + }, + "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, + "limit": { + "context": 262000, + "output": 8192 + }, + "status": "beta", + "cost": { + "input": 2, + "output": 6 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 1.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 200000, + "output": 128000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25, + "tiers": [ + { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 10, + "output": 37.5, + "cache_read": 1, + "cache_write": 12.5 + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.58, + "output": 1.68 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.17, + "output": 0.68 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 3, + "output": 4 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0.125, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 272000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.13 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 60, + "output": 120 + } + }, + "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, + "limit": { + "context": 512, + "output": 1024 + }, + "cost": { + "input": 0.1, + "output": 0 + } + }, + "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, + "limit": { + "context": 32000, + "output": 4096 + }, + "cost": { + "input": 0.125, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0.4, + "output": 2 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 1.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 163840, + "output": 163840 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 256000, + "output": 256000 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.25, + "output": 1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 1.35, + "output": 5.4 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "provider": { + "npm": "@ai-sdk/anthropic", + "api": "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1" + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 5, + "output": 30, + "cache_read": 0.5, + "context_over_200k": { + "input": 10, + "output": 45, + "cache_read": 1 + }, + "tiers": [ + { + "input": 10, + "output": 45, + "cache_read": 1, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 10, + "output": 30 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.75, + "output": 4.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } }, "o4-mini": { "id": "o4-mini", @@ -64880,179 +108800,5024 @@ "knowledge": "2024-05", "release_date": "2025-04-16", "last_updated": "2025-04-16", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 1.1, "output": 4.4 }, - "limit": { "context": 200000, "output": 100000 } + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 + } }, - "route-llm": { - "id": "route-llm", - "name": "Route LLM", - "family": "gpt", + "gpt-5.4-nano": { + "id": "gpt-5.4-nano", + "name": "GPT-5.4 Nano", + "family": "gpt-nano", "attachment": true, - "reasoning": false, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.2, + "output": 1.25, + "cache_read": 0.02 + } + }, + "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": "2024-10", - "release_date": "2024-01-01", - "last_updated": "2024-01-01", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "knowledge": "2023-10", + "release_date": "2025-08-28", + "last_updated": "2025-08-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": false, - "cost": { "input": 3, "output": 15 }, - "limit": { "context": 128000, "output": 16384 } + "limit": { + "context": 256000, + "output": 10000 + }, + "cost": { + "input": 0.2, + "output": 1.5, + "cache_read": 0.02 + } }, - "gpt-5.1-codex": { - "id": "gpt-5.1-codex", - "name": "GPT-5.1 Codex", + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 30, + "output": 180, + "context_over_200k": { + "input": 60, + "output": 270 + }, + "tiers": [ + { + "input": 60, + "output": 270, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 1.1, + "output": 4.4, + "cache_read": 0.55 + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "reasoning": 15, + "cache_read": 0.75 + } + }, + "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": "2024-09-30", - "release_date": "2025-11-13", - "last_updated": "2025-11-13", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "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": 1.25, "output": 10 }, - "limit": { "context": 400000, "input": 272000, "output": 128000 } + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "context_over_200k": { + "input": 5, + "output": 22.5, + "cache_read": 0.5 + }, + "tiers": [ + { + "input": 5, + "output": 22.5, + "cache_read": 0.5, + "tier": { + "type": "context", + "size": 272000 + } + } + ] + } }, - "openai/gpt-oss-120b": { - "id": "openai/gpt-oss-120b", - "name": "GPT-OSS 120B", - "family": "gpt-oss", + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.03 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.3, + "output": 0.5, + "reasoning": 0.5, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 400000, + "output": 272000 + }, + "cost": { + "input": 15, + "output": 120 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 2.5, + "output": 10, + "cache_read": 1.25 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4000 + }, + "cost": { + "input": 2.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 0.4, + "output": 1.6, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75 + } + }, + "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, + "limit": { + "context": 2000000, + "output": 30000 + }, + "cost": { + "input": 0.2, + "output": 0.5, + "cache_read": 0.05 + } + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75, + "cache_write": 15 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.03, + "output": 0.14 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 0.05, + "output": 0.4, + "cache_read": 0.005 + } + }, + "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", "image"], "output": ["text"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.08, "output": 0.44 }, - "limit": { "context": 128000, "output": 32768 } + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.05, + "output": 0.2 + } }, - "deepseek/deepseek-v3.1": { - "id": "deepseek/deepseek-v3.1", - "name": "DeepSeek V3.1", - "family": "deepseek", + "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, + "limit": { + "context": 400000, + "output": 128000 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125 + } + }, + "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-01-20", - "last_updated": "2025-01-20", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2025-08-05", + "last_updated": "2025-08-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.55, "output": 1.66 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } }, - "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 } - }, - "zai-org/glm-5": { - "id": "zai-org/glm-5", + "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"] }, + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 1, "output": 3.2 }, - "limit": { "context": 204800, "output": 131072 } + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.95, + "output": 3.15 + } }, - "zai-org/glm-4.7": { - "id": "zai-org/glm-4.7", - "name": "GLM-4.7", + "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, + "limit": { + "context": 262144, + "output": 66536 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.0375 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.55, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 1047576, + "output": 32768 + }, + "cost": { + "input": 2, + "output": 8, + "cache_read": 0.5 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + } + } + }, + "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, + "limit": { + "context": 32000, + "output": 4096 + }, + "cost": { + "input": 0.09, + "output": 0.09 + } + }, + "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, + "limit": { + "context": 218000, + "output": 8192 + }, + "cost": { + "input": 1.64, + "output": 1.91 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.16, + "output": 0.27 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.49, + "output": 0.71 + } + }, + "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, + "limit": { + "context": 131000, + "output": 8192 + }, + "cost": { + "input": 0.49, + "output": 0.71 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.49, + "output": 0.71 + } + }, + "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, + "limit": { + "context": 37000, + "output": 8192 + }, + "cost": { + "input": 0.49, + "output": 0.71 + } + }, + "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, + "limit": { + "context": 4096, + "output": 4096 + }, + "cost": { + "input": 0.02, + "output": 0.02 + } + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 202752, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 0, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 32000, + "output": 2560 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + } + }, + "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, + "limit": { + "context": 131072, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 2, + "input_audio": 3, + "output_audio": 12 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 8192 + }, + "cost": { + "input": 0.075, + "output": 0.3, + "cache_read": 0.01875 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 8192 + }, + "cost": { + "input": 1.25, + "output": 5, + "cache_read": 0.3125 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "input_audio": 0.5 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.5, + "output": 3, + "cache_read": 0.05, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 8000, + "output": 16000 + }, + "cost": { + "input": 0.5, + "output": 10 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 2, + "output": 12, + "cache_read": 0.2, + "tiers": [ + { + "input": 4, + "output": 18, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 4, + "output": 18, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.0375 + } + }, + "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, + "limit": { + "context": 2048, + "output": 3072 + }, + "cost": { + "input": 0.15, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.125, + "tiers": [ + { + "input": 2.5, + "output": 15, + "cache_read": 0.25, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 2.5, + "output": 15, + "cache_read": 0.25 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.075, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 30, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025, + "input_audio": 0.3 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.03, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 32768 + }, + "cost": { + "input": 0.5, + "output": 60 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.25, + "output": 1.5, + "cache_read": 0.025, + "input_audio": 0.5 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.0375 + } + }, + "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, + "limit": { + "context": 8000, + "output": 16000 + }, + "cost": { + "input": 1, + "output": 20 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.3, + "output": 2.5, + "cache_read": 0.075, + "input_audio": 1 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.01, + "input_audio": 0.3 + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 30, + "cache_read": 0.075 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 8192 + }, + "cost": { + "input": 0.0375, + "output": 0.15, + "cache_read": 0.01 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8000 + }, + "cost": { + "input": 0.5, + "output": 2, + "input_audio": 3, + "output_audio": 12 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 8192 + }, + "cost": { + "input": 0.075, + "output": 0.3 + } + } + } + }, + "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, + "limit": { + "context": 131072, + "output": 32000 + }, + "cost": { + "input": 0.55, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.29, + "output": 1.16 + } + }, + "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, + "limit": { + "context": 131072, + "output": 8192 + }, + "cost": { + "input": 0.28, + "output": 1.1 + } + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 3, + "cache_read": 0.1 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.15, + "output": 8, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4, + "cache_read": 0.16 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 2.4, + "output": 10, + "cache_read": 0.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.6, + "output": 2.5, + "cache_read": 0.15 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.77, + "output": 2.75 + } + }, + "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, + "limit": { + "context": 32000, + "output": 8192 + }, + "cost": { + "input": 0.33, + "output": 0.33 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 1.65, + "output": 5.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.99, + "output": 0.99 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.44, + "output": 0.99 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0.275, + "output": 0.55 + } + } + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 65536, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 65536, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 256000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 4096, + "output": 1024 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 4096, + "output": 1024 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 16000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 65536, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 4096 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 100000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 8192, + "output": 2048 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 32000, + "output": 8192 + }, + "cost": { + "input": 0, + "output": 0 + } + } + } + }, + "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": "2025-06-01", - "last_updated": "2025-06-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-04-07", + "last_updated": "2026-04-07", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.6, "output": 2.2 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 1.1, + "output": 3.6 + } }, - "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 } - }, - "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", + "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, - "knowledge": "2024-08", - "release_date": "2025-04-05", - "last_updated": "2025-04-05", - "modalities": { "input": ["text", "image"], "output": ["text"] }, + "release_date": "2026-04-21", + "last_updated": "2026-04-21", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.14, "output": 0.59 }, - "limit": { "context": 1000000, "output": 32768 } + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.69, + "output": 3.22 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.69, + "output": 4.14 + } + }, + "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, + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 1.1, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.05, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.52, + "output": 2.59 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.69, + "output": 4.14 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.05, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 200000 + }, + "cost": { + "input": 1.1, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.12, + "output": 0.35 + } + }, + "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, + "limit": { + "context": 16384, + "output": 16384 + }, + "cost": { + "input": 0.03, + "output": 0.16 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.69, + "output": 3.22 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.52, + "output": 2.59 + } + }, + "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, + "limit": { + "context": 196608, + "output": 196608 + }, + "cost": { + "input": 0.35, + "output": 1.38 + } + } + } + }, + "sarvam": { + "id": "sarvam", + "env": ["SARVAM_API_KEY"], + "npm": "@ai-sdk/openai-compatible", + "api": "https://api.sarvam.ai/v1", + "name": "Sarvam AI", + "doc": "https://docs.sarvam.ai/api-reference-docs/getting-started/models", + "models": { + "sarvam-105b": { + "id": "sarvam-105b", + "name": "Sarvam-105B", + "family": "sarvam", + "attachment": false, + "reasoning": true, + "tool_call": true, + "interleaved": { + "field": "reasoning_content" + }, + "temperature": true, + "release_date": "2026-02-18", + "last_updated": "2026-03-06", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "sarvam-30b": { + "id": "sarvam-30b", + "name": "Sarvam-30B", + "family": "sarvam", + "attachment": false, + "reasoning": true, + "tool_call": true, + "interleaved": { + "field": "reasoning_content" + }, + "temperature": true, + "release_date": "2026-02-18", + "last_updated": "2026-03-06", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "limit": { + "context": 65536, + "output": 65536 + } + } + } + }, + "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, + "limit": { + "context": 32768, + "output": 32768 + }, + "cost": { + "input": 0.15, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 130000 + }, + "cost": { + "input": 0.6, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 500000 + }, + "cost": { + "input": 0.5, + "output": 3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.5, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.2, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 2, + "output": 2 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 1.4, + "output": 4.4 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.88, + "output": 0.88 + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 1.25, + "output": 1.25 + } }, "deepseek-ai/DeepSeek-R1": { "id": "deepseek-ai/DeepSeek-R1", @@ -65060,119 +113825,3474 @@ "family": "deepseek-thinking", "attachment": false, "reasoning": true, - "tool_call": true, + "tool_call": false, "temperature": true, - "release_date": "2025-01-20", - "last_updated": "2025-01-20", - "modalities": { "input": ["text"], "output": ["text"] }, + "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": 128000, "output": 8192 } + "limit": { + "context": 163839, + "output": 163839 + }, + "cost": { + "input": 3, + "output": 7 + } }, - "deepseek-ai/DeepSeek-V3.1-Terminus": { - "id": "deepseek-ai/DeepSeek-V3.1-Terminus", - "name": "DeepSeek V3.1 Terminus", + "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-06-01", - "last_updated": "2025-06-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-08", + "release_date": "2025-08-21", + "last_updated": "2025-08-21", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.27, "output": 1 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 1.7 + } }, - "deepseek-ai/DeepSeek-V3.2": { - "id": "deepseek-ai/DeepSeek-V3.2", - "name": "DeepSeek V3.2", + "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": "2025-06-15", - "last_updated": "2025-06-15", - "modalities": { "input": ["text"], "output": ["text"] }, + "release_date": "2026-04-24", + "last_updated": "2026-04-24", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.27, "output": 0.4 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 512000, + "output": 384000 + }, + "cost": { + "input": 2.1, + "output": 4.4, + "cache_read": 0.2 + } }, - "Qwen/Qwen3-32B": { - "id": "Qwen/Qwen3-32B", - "name": "Qwen3 32B", + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.2, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131000 + }, + "cost": { + "input": 1.2, + "output": 4.5, + "cache_read": 0.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.5, + "output": 2.8 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + }, + "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, + "limit": { + "context": 202752, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06 + } + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 0.71, + "output": 3.57 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.07, + "output": 0.43, + "tiers": [ + { + "input": 0.07, + "output": 0.43, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 0.07, + "output": 0.43 + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.04, + "output": 0.29 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 65000 + }, + "cost": { + "input": 0.57, + "output": 3.43 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.43, + "output": 2.14 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.25, + "output": 2 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0.14, + "output": 1.14 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 65536 + }, + "cost": { + "input": 0.09, + "output": 0.71, + "tiers": [ + { + "input": 0.09, + "output": 0.71, + "tier": { + "type": "context", + "size": 200000 + } + } + ], + "context_over_200k": { + "input": 0.09, + "output": 0.71 + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0.14, + "output": 0.71 + } + } + } + }, + "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, + "limit": { + "context": 256000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "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" + } + } + } + } + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 4096 + }, + "cost": { + "input": 0.25, + "output": 1.25, + "cache_read": 0.03, + "cache_write": 0.3 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 8192 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 1, + "output": 5, + "cache_read": 0.1, + "cache_write": 1.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "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" + } + } + } + } + }, + "cost": { + "input": 5, + "output": 25, + "cache_read": 0.5, + "cache_write": 6.25 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 + } + }, + "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, + "limit": { + "context": 200000, + "output": 32000 + }, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + } + } + } + }, + "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, - "release_date": "2025-04-29", - "last_updated": "2025-04-29", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-04", + "release_date": "2025-07-30", + "last_updated": "2025-07-30", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.09, "output": 0.29 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 262144, + "output": 32768 + }, + "cost": { + "input": 0, + "output": 0 + } }, - "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/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/Qwen2.5-72B-Instruct": { - "id": "Qwen/Qwen2.5-72B-Instruct", - "name": "Qwen 2.5 72B Instruct", + "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, - "release_date": "2024-09-19", - "last_updated": "2024-09-19", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-04", + "release_date": "2025-07-30", + "last_updated": "2025-07-30", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.11, "output": 0.38 }, - "limit": { "context": 128000, "output": 8192 } + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } }, "Qwen/Qwen3-235B-A22B-Instruct-2507": { "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", - "name": "Qwen3 235B A22B Instruct", + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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-07-01", - "last_updated": "2025-07-01", - "modalities": { "input": ["text"], "output": ["text"] }, + "knowledge": "2025-04", + "release_date": "2025-07-25", + "last_updated": "2025-07-25", + "modalities": { + "input": ["text"], + "output": ["text"] + }, "open_weights": true, - "cost": { "input": 0.13, "output": 0.6 }, - "limit": { "context": 262144, "output": 8192 } + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 202752, + "output": 98304 + }, + "cost": { + "input": 0, + "output": 0 + } + } + } + }, + "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, + "limit": { + "context": 202000, + "output": 202000 + }, + "cost": { + "input": 0.66, + "output": 2, + "cache_read": 0.12 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 131072 + }, + "cost": { + "input": 0.14, + "output": 0.56, + "cache_read": 0.014 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.21, + "output": 1, + "cache_read": 0.03 + } + } + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0.4, + "output": 2, + "cache_read": 0.08, + "tiers": [ + { + "input": 0.8, + "output": 4, + "cache_read": 0.16, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 0.8, + "output": 4, + "cache_read": 0.16 + } + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3, + "cache_read": 0.2, + "tiers": [ + { + "input": 2, + "output": 6, + "cache_read": 0.4, + "tier": { + "type": "context", + "size": 256000 + } + } + ], + "context_over_200k": { + "input": 2, + "output": 6, + "cache_read": 0.4 + } + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.1, + "output": 0.3, + "cache_read": 0.01 + } + } + } + }, + "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, + "limit": { + "context": 131072, + "output": 131072 + }, + "cost": { + "input": 0.045, + "output": 0.15 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 2.5, + "output": 1.7 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 1.039, + "output": 0.54825 + } + }, + "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, + "limit": { + "context": 8192, + "output": 8192 + }, + "cost": { + "input": 0.2, + "output": 0.7 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.045, + "output": 0.18 + } + }, + "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, + "limit": { + "context": 131072, + "output": 16384 + }, + "cost": { + "input": 0.09, + "output": 0.36 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0.11458, + "output": 0.74812 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0.36, + "output": 1.3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.3, + "output": 0.5 + } + }, + "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, + "limit": { + "context": 32768, + "output": 4096 + }, + "cost": { + "input": 0.658, + "output": 1.11 + } + }, + "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, + "limit": { + "context": 262144, + "output": 262144 + }, + "cost": { + "input": 0.95, + "output": 4 + } + } + } + }, + "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, + "limit": { + "context": 196608, + "output": 128000 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.03, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.06, + "cache_write": 0.375 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.4, + "cache_read": 0.06, + "cache_write": 0.375 + } + } + } + }, + "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, + "limit": { + "context": 120000, + "output": 120000 + }, + "cost": { + "input": 0.5, + "output": 2.2 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0.1, + "output": 0.1 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 2.7 + } + }, + "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, + "limit": { + "context": 32768, + "output": 8192 + }, + "cost": { + "input": 0.12, + "output": 0.12 + } + }, + "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, + "limit": { + "context": 256000, + "output": 16384 + }, + "cost": { + "input": 0.75, + "output": 3 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.9, + "output": 3.6 + } + }, + "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, + "limit": { + "context": 8192, + "output": 4096 + }, + "cost": { + "input": 0.5, + "output": 2 + } + }, + "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, + "limit": { + "context": 262144, + "output": 16384 + }, + "cost": { + "input": 0.3, + "output": 1.2 + } + }, + "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, + "limit": { + "context": 190000, + "output": 64000 + }, + "cost": { + "input": 0.8, + "output": 3.5 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 0.4, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 262144, + "output": 8192 + }, + "cost": { + "input": 0.15, + "output": 0.6 + } + }, + "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, + "limit": { + "context": 128000, + "output": 16384 + }, + "cost": { + "input": 1, + "output": 4.2 + } + }, + "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, + "limit": { + "context": 120000, + "output": 120000 + }, + "cost": { + "input": 0.05, + "output": 0.25 + } + } + } + }, + "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, + "limit": { + "context": 8192, + "output": 16384 + }, + "cost": { + "input": 0, + "output": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 65536 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 262144, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + }, + "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, + "limit": { + "context": 1048576, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0 + } + } + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 5, + "output": 22, + "cache_read": 1.2, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 1, + "output": 3.2, + "cache_read": 0.2, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 6, + "output": 24, + "cache_read": 1.3, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0, + "output": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 128000, + "output": 32768 + }, + "cost": { + "input": 0.3, + "output": 0.9 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 64000, + "output": 16384 + }, + "cost": { + "input": 0.6, + "output": 1.8 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.2, + "output": 1.1, + "cache_read": 0.03, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 131072, + "output": 98304 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 200000, + "output": 131072 + }, + "cost": { + "input": 0.07, + "output": 0.4, + "cache_read": 0.01, + "cache_write": 0 + } + }, + "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, + "limit": { + "context": 204800, + "output": 131072 + }, + "cost": { + "input": 0.6, + "output": 2.2, + "cache_read": 0.11, + "cache_write": 0 + } + } + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "reasoning": 0 + } + }, + "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, + "limit": { + "context": 1000000, + "output": 64000 + }, + "cost": { + "input": 0, + "output": 0, + "reasoning": 0 + } } } } diff --git a/packages/opencode/test/tool/read.test.ts b/packages/opencode/test/tool/read.test.ts index 11bb1513f3..fcbd10bb4d 100644 --- a/packages/opencode/test/tool/read.test.ts +++ b/packages/opencode/test/tool/read.test.ts @@ -4,8 +4,10 @@ import path from "path" import { Agent } from "../../src/agent/agent" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { AppFileSystem } from "@opencode-ai/core/filesystem" -import { Flag } from "@opencode-ai/core/flag/flag" import { Global } from "@opencode-ai/core/global" +import { Config } from "@/config/config" +import { RuntimeFlags } from "@/effect/runtime-flags" +import { Git } from "@/git" import { LSP } from "@/lsp/lsp" import { Permission } from "../../src/permission" import { Instance } from "../../src/project/instance" @@ -36,17 +38,27 @@ const ctx = { ask: () => Effect.void, } -const it = testEffect( +const referenceLayer = (flags: Partial = {}) => + Reference.layer.pipe( + Layer.provide(Config.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(Git.defaultLayer), + Layer.provide(RuntimeFlags.layer(flags)), + ) + +const readLayer = (flags: Partial = {}) => Layer.mergeAll( Agent.defaultLayer, AppFileSystem.defaultLayer, CrossSpawnSpawner.defaultLayer, Instruction.defaultLayer, LSP.defaultLayer, - Reference.defaultLayer, + referenceLayer(flags), Truncate.defaultLayer, - ), -) + ) + +const it = testEffect(readLayer()) +const scout = testEffect(readLayer({ experimentalScout: true })) const init = Effect.fn("ReadToolTest.init")(function* () { const info = yield* ReadTool @@ -85,19 +97,6 @@ const fail = Effect.fn("ReadToolTest.fail")(function* ( const full = (p: string) => (process.platform === "win32" ? Filesystem.normalizePath(p) : p) const glob = (p: string) => process.platform === "win32" ? Filesystem.normalizePathPattern(p) : p.replaceAll("\\", "/") -const experimentalScout = (self: Effect.Effect) => - Effect.acquireUseRelease( - Effect.sync(() => { - const previous = Flag.OPENCODE_EXPERIMENTAL_SCOUT - Flag.OPENCODE_EXPERIMENTAL_SCOUT = true - return previous - }), - () => self, - (previous) => - Effect.sync(() => { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = previous - }), - ) const githubBase = (url: string, self: Effect.Effect) => Effect.acquireUseRelease( Effect.sync(() => { @@ -260,44 +259,42 @@ describe("tool.read external_directory permission", () => { }), ) - it.live("does not ask for external_directory permission when reading configured references", () => - experimentalScout( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - const cache = path.join(Global.Path.repos, "github.com", "opencode-read-reference", "repo") - yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) - yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) + scout.live("does not ask for external_directory permission when reading configured references", () => + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const cache = path.join(Global.Path.repos, "github.com", "opencode-read-reference", "repo") + yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) + yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) - const source = yield* tmpdirScoped({ git: true }) - const remoteRoot = yield* tmpdirScoped() - const remoteDir = path.join(remoteRoot, "opencode-read-reference") - const remoteRepo = path.join(remoteDir, "repo.git") - yield* put(path.join(source, "notes.md"), "reference notes") - yield* git(source, ["add", "."]) - yield* git(source, ["commit", "-m", "add notes"]) - yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) - yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) + const source = yield* tmpdirScoped({ git: true }) + const remoteRoot = yield* tmpdirScoped() + const remoteDir = path.join(remoteRoot, "opencode-read-reference") + const remoteRepo = path.join(remoteDir, "repo.git") + yield* put(path.join(source, "notes.md"), "reference notes") + yield* git(source, ["add", "."]) + yield* git(source, ["commit", "-m", "add notes"]) + yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) + yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) - const dir = yield* tmpdirScoped({ - git: true, - config: { - reference: { - docs: "opencode-read-reference/repo", - }, + const dir = yield* tmpdirScoped({ + git: true, + config: { + reference: { + docs: "opencode-read-reference/repo", }, - }) + }, + }) - const { items, next } = asks() - const result = yield* githubBase( - `file://${remoteRoot}/`, - exec(dir, { filePath: path.join(cache, "notes.md") }, next), - ) - const ext = items.find((item) => item.permission === "external_directory") + const { items, next } = asks() + const result = yield* githubBase( + `file://${remoteRoot}/`, + exec(dir, { filePath: path.join(cache, "notes.md") }, next), + ) + const ext = items.find((item) => item.permission === "external_directory") - expect(result.output).toContain("reference notes") - expect(ext).toBeUndefined() - }), - ), + expect(result.output).toContain("reference notes") + expect(ext).toBeUndefined() + }), ) }) diff --git a/packages/opencode/test/tool/registry.test.ts b/packages/opencode/test/tool/registry.test.ts index 5ee56300c4..f00b7f5a08 100644 --- a/packages/opencode/test/tool/registry.test.ts +++ b/packages/opencode/test/tool/registry.test.ts @@ -5,7 +5,7 @@ import { pathToFileURL } from "url" import { Effect, Layer, Result, Schema } from "effect" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { ToolRegistry } from "@/tool/registry" -import { Flag } from "@opencode-ai/core/flag/flag" +import { Tool } from "@/tool/tool" import { disposeAllInstances, TestInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { TestConfig } from "../fixture/config" @@ -29,46 +29,48 @@ import { InstanceState } from "@/effect/instance-state" import { Reference } from "@/reference/reference" import { ProviderID, ModelID } from "@/provider/schema" import { ToolJsonSchema } from "@/tool/json-schema" +import { MessageID, SessionID } from "@/session/schema" +import { RuntimeFlags } from "@/effect/runtime-flags" const node = CrossSpawnSpawner.defaultLayer -const originalExperimentalScout = Flag.OPENCODE_EXPERIMENTAL_SCOUT const configLayer = TestConfig.layer({ directories: () => InstanceState.directory.pipe(Effect.map((dir) => [path.join(dir, ".opencode")])), }) -const registryLayer = ToolRegistry.layer.pipe( - Layer.provide(configLayer), - Layer.provide(Plugin.defaultLayer), - Layer.provide(Question.defaultLayer), - Layer.provide(Todo.defaultLayer), - Layer.provide(Skill.defaultLayer), - Layer.provide(Agent.defaultLayer), - Layer.provide(Session.defaultLayer), - Layer.provide(Provider.defaultLayer), - Layer.provide(Git.defaultLayer), - Layer.provide(Reference.defaultLayer), - Layer.provide(LSP.defaultLayer), - Layer.provide(Instruction.defaultLayer), - Layer.provide(AppFileSystem.defaultLayer), - Layer.provide(Bus.layer), - Layer.provide(FetchHttpClient.layer), - Layer.provide(Format.defaultLayer), - Layer.provide(node), - Layer.provide(Ripgrep.defaultLayer), - Layer.provide(Truncate.defaultLayer), -) +const registryLayer = (flags: Partial = {}) => + ToolRegistry.layer.pipe( + Layer.provide(configLayer), + Layer.provide(Plugin.defaultLayer), + Layer.provide(Question.defaultLayer), + Layer.provide(Todo.defaultLayer), + Layer.provide(Skill.defaultLayer), + Layer.provide(Agent.defaultLayer), + Layer.provide(Session.defaultLayer), + Layer.provide(Provider.defaultLayer), + Layer.provide(Git.defaultLayer), + Layer.provide(Reference.defaultLayer), + Layer.provide(LSP.defaultLayer), + Layer.provide(Instruction.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(Bus.layer), + Layer.provide(FetchHttpClient.layer), + Layer.provide(Format.defaultLayer), + Layer.provide(node), + Layer.provide(Ripgrep.defaultLayer), + Layer.provide(Truncate.defaultLayer), + Layer.provide(RuntimeFlags.layer(flags)), + ) -const it = testEffect(Layer.mergeAll(registryLayer, node, Agent.defaultLayer)) +const it = testEffect(Layer.mergeAll(registryLayer(), node, Agent.defaultLayer)) +const scout = testEffect(Layer.mergeAll(registryLayer({ experimentalScout: true }), node, Agent.defaultLayer)) afterEach(async () => { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = originalExperimentalScout await disposeAllInstances() }) describe("tool.registry", () => { it.instance("hides repo research tools unless experimental", () => Effect.gen(function* () { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = false const registry = yield* ToolRegistry.Service const ids = yield* registry.ids() @@ -77,9 +79,8 @@ describe("tool.registry", () => { }), ) - it.instance("shows repo research tools when experimental scout is enabled", () => + scout.instance("shows repo research tools when experimental scout is enabled", () => Effect.gen(function* () { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = true const registry = yield* ToolRegistry.Service const ids = yield* registry.ids() @@ -180,7 +181,7 @@ describe("tool.registry", () => { const promptTools = yield* registry.tools({ providerID: ProviderID.opencode, modelID: ModelID.make("test"), - agent: yield* agents.get(yield* agents.defaultAgent()), + agent: yield* agents.defaultInfo(), }) const promptTool = promptTools.find((tool) => tool.id === "sql") if (!promptTool) throw new Error("custom sql tool was not returned for prompts") @@ -193,6 +194,51 @@ describe("tool.registry", () => { }), ) + it.instance("preserves attachments from structured custom tool results", () => + Effect.gen(function* () { + const test = yield* TestInstance + const customTools = path.join(test.directory, ".opencode", "tools") + const pluginTool = pathToFileURL(path.resolve(import.meta.dir, "../../../plugin/src/tool.ts")).href + yield* Effect.promise(() => fs.mkdir(customTools, { recursive: true })) + yield* Effect.promise(() => + Bun.write( + path.join(customTools, "image.ts"), + [ + `import { tool } from ${JSON.stringify(pluginTool)}`, + "export default tool({", + " description: 'image tool',", + " args: {},", + " execute: async () => ({", + " output: 'here is an image',", + " attachments: [{ type: 'file', mime: 'image/png', filename: 'picture.png', url: 'data:image/png;base64,AAAA' }],", + " }),", + "})", + "", + ].join("\n"), + ), + ) + + const registry = yield* ToolRegistry.Service + const loaded = (yield* registry.all()).find((tool) => tool.id === "image") + if (!loaded) throw new Error("custom image tool was not loaded") + const agents = yield* Agent.Service + const result = yield* loaded.execute({}, { + sessionID: SessionID.make("ses_test"), + messageID: MessageID.make("msg_test"), + agent: (yield* agents.defaultInfo()).name, + abort: new AbortController().signal, + messages: [], + metadata: () => Effect.void, + ask: () => Effect.void, + } satisfies Tool.Context) + + expect(result.output).toBe("here is an image") + expect(result.attachments).toEqual([ + { type: "file", mime: "image/png", filename: "picture.png", url: "data:image/png;base64,AAAA" }, + ]) + }), + ) + it.instance("loads legacy JSON-schema-shaped custom tools with wire schema", () => Effect.gen(function* () { const test = yield* TestInstance diff --git a/packages/opencode/test/tool/shell.test.ts b/packages/opencode/test/tool/shell.test.ts index 287844141f..6ce0e5c081 100644 --- a/packages/opencode/test/tool/shell.test.ts +++ b/packages/opencode/test/tool/shell.test.ts @@ -1,14 +1,13 @@ -import { describe, expect, test } from "bun:test" -import { Effect, Layer, ManagedRuntime } from "effect" +import { describe, expect } from "bun:test" +import { Cause, Effect, Exit, Layer } from "effect" +import type * as Scope from "effect/Scope" import os from "os" import path from "path" import { Config } from "@/config/config" import { Shell } from "../../src/shell/shell" import { ShellTool } from "../../src/tool/shell" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { Filesystem } from "@/util/filesystem" -import { tmpdir } from "../fixture/fixture" +import { provideInstance, tmpdirScoped } from "../fixture/fixture" import type { Permission } from "../../src/permission" import { Agent } from "../../src/agent/agent" import { Truncate } from "@/tool/truncate" @@ -16,23 +15,50 @@ import { SessionID, MessageID } from "../../src/session/schema" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { Plugin } from "../../src/plugin" +import { testEffect } from "../lib/effect" +import { Tool } from "@/tool/tool" -const runtime = ManagedRuntime.make( - Layer.mergeAll( - CrossSpawnSpawner.defaultLayer, - AppFileSystem.defaultLayer, - Plugin.defaultLayer, - Truncate.defaultLayer, - Config.defaultLayer, - Agent.defaultLayer, - ), +const shellLayer = Layer.mergeAll( + CrossSpawnSpawner.defaultLayer, + AppFileSystem.defaultLayer, + Plugin.defaultLayer, + Truncate.defaultLayer, + Config.defaultLayer, + Agent.defaultLayer, ) +const it = testEffect(shellLayer) +type ShellTestServices = + | (typeof shellLayer extends Layer.Layer ? ROut : never) + | Scope.Scope -function initBash() { - return runtime.runPromise(ShellTool.pipe(Effect.flatMap((info) => info.init()))) -} +const initShell = Effect.fn("ShellToolTest.init")(function* () { + const info = yield* ShellTool + return yield* info.init() +}) -const initShell = initBash +const initBash = initShell + +const run = Effect.fn("ShellToolTest.run")(function* ( + args: Tool.InferParameters, + next: Tool.Context = ctx, +) { + const bash = yield* initShell() + return yield* bash.execute(args, next) +}) + +const runIn = (directory: string, self: Effect.Effect) => self.pipe(provideInstance(directory)) + +const fail = Effect.fn("ShellToolTest.fail")(function* ( + args: Tool.InferParameters, + next: Tool.Context = ctx, +) { + const exit = yield* run(args, next).pipe(Effect.exit) + if (Exit.isFailure(exit)) { + const err = Cause.squash(exit.cause) + return err instanceof Error ? err : new Error(String(err)) + } + throw new Error("expected command to fail") +}) const ctx = { sessionID: SessionID.make("ses_test"), @@ -96,27 +122,31 @@ const forms = (dir: string) => { return Array.from(new Set([full, slash, root, root.toLowerCase()])) } -const withShell = (item: { label: string; shell: string }, fn: () => Promise) => async () => { - const prev = process.env.SHELL - process.env.SHELL = item.shell - Shell.acceptable.reset() - Shell.preferred.reset() - try { - await fn() - } finally { - if (prev === undefined) delete process.env.SHELL - else process.env.SHELL = prev - Shell.acceptable.reset() - Shell.preferred.reset() - } -} +const withShell = (item: { label: string; shell: string }, self: Effect.Effect) => + Effect.acquireUseRelease( + Effect.sync(() => { + const prev = process.env.SHELL + process.env.SHELL = item.shell + Shell.acceptable.reset() + Shell.preferred.reset() + return prev + }), + () => self, + (prev) => + Effect.sync(() => { + if (prev === undefined) delete process.env.SHELL + else process.env.SHELL = prev + Shell.acceptable.reset() + Shell.preferred.reset() + }), + ) -const each = (name: string, fn: (item: { label: string; shell: string }) => Promise) => { +const each = ( + name: string, + fn: (item: { label: string; shell: string }) => Effect.Effect, +) => { for (const item of shells) { - test( - `${name} [${item.label}]`, - withShell(item, () => fn(item)), - ) + it.live(`${name} [${item.label}]`, () => withShell(item, fn(item))) } } @@ -140,277 +170,248 @@ const mustTruncate = (result: { } describe("tool.shell", () => { - each("basic", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() - const result = await Effect.runPromise( - bash.execute( - { - command: "echo test", - description: "Echo test message", - }, - ctx, - ), - ) + each("basic", () => + runIn( + projectRoot, + Effect.gen(function* () { + const result = yield* run({ + command: "echo test", + description: "Echo test message", + }) expect(result.metadata.exit).toBe(0) expect(result.metadata.output).toContain("test") - }, - }) - }) + }), + ), + ) - test("falls back from terminal-only configured shell", async () => { - await using tmp = await tmpdir({ - config: { shell: "fish" }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const fallback = Shell.name(Shell.acceptable("fish")) - expect(fallback).not.toBe("fish") - expect(bash.description).toContain(fallback) + it.live("falls back from terminal-only configured shell", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped({ config: { shell: "fish" } }) + yield* runIn( + tmp, + Effect.gen(function* () { + const bash = yield* initBash() + const fallback = Shell.name(Shell.acceptable("fish")) + expect(fallback).not.toBe("fish") + expect(bash.description).toContain(fallback) - const result = await Effect.runPromise( - bash.execute( + const result = yield* bash.execute( { command: "echo fallback", description: "Echo fallback text", }, ctx, - ), - ) - expect(result.metadata.exit).toBe(0) - expect(result.output).toContain("fallback") - }, - }) - }) + ) + expect(result.metadata.exit).toBe(0) + expect(result.output).toContain("fallback") + }), + ) + }), + ) }) describe("tool.shell permissions", () => { - each("asks for bash permission with correct pattern", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initShell() - const requests: Array> = [] - await Effect.runPromise( - bash.execute( + each("asks for bash permission with correct pattern", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const requests: Array> = [] + yield* run( { command: "echo hello", description: "Echo hello", }, capture(requests), - ), - ) - expect(requests.length).toBe(1) - expect(requests[0].permission).toBe("bash") - expect(requests[0].patterns).toContain("echo hello") - }, - }) - }) + ) + expect(requests.length).toBe(1) + expect(requests[0].permission).toBe("bash") + expect(requests[0].patterns).toContain("echo hello") + }), + ) + }), + ) - each("asks for bash permission with multiple commands", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initShell() - const requests: Array> = [] - await Effect.runPromise( - bash.execute( + each("asks for bash permission with multiple commands", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const requests: Array> = [] + yield* run( { command: "echo foo && echo bar", description: "Echo twice", }, capture(requests), - ), - ) - expect(requests.length).toBe(1) - expect(requests[0].permission).toBe("bash") - expect(requests[0].patterns).toContain("echo foo") - expect(requests[0].patterns).toContain("echo bar") - }, - }) - }) + ) + expect(requests.length).toBe(1) + expect(requests[0].permission).toBe("bash") + expect(requests[0].patterns).toContain("echo foo") + expect(requests[0].patterns).toContain("echo bar") + }), + ) + }), + ) for (const item of ps) { - test( - `parses PowerShell conditionals for permission prompts [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live(`parses PowerShell conditionals for permission prompts [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { const requests: Array> = [] - await Effect.runPromise( - bash.execute( - { - command: "Write-Host foo; if ($?) { Write-Host bar }", - description: "Check PowerShell conditional", - }, - capture(requests), - ), + yield* run( + { + command: "Write-Host foo; if ($?) { Write-Host bar }", + description: "Check PowerShell conditional", + }, + capture(requests), ) const bashReq = requests.find((r) => r.permission === "bash") expect(bashReq).toBeDefined() expect(bashReq!.patterns).toContain("Write-Host foo") expect(bashReq!.patterns).toContain("Write-Host bar") expect(bashReq!.always).toContain("Write-Host *") - }, - }) - }), + }), + ), + ), ) } for (const item of ps) { - test( - `uses PowerShell cmdlet prefixes for always-allow prompts [${item.label}]`, - withShell(item, async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initShell() - const err = new Error("stop after permission") - const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( + it.live(`uses PowerShell cmdlet prefixes for always-allow prompts [${item.label}]`, () => + withShell( + item, + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + expect( + yield* fail( { command: "Remove-Item -Recurse tmp", description: "Remove a temp directory", }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) - const bashReq = requests.find((r) => r.permission === "bash") - expect(bashReq).toBeDefined() - expect(bashReq!.always).toContain("Remove-Item *") - expect(bashReq!.always).not.toContain("Remove-Item -Recurse *") - }, - }) - }), + ).toMatchObject({ message: err.message }) + const bashReq = requests.find((r) => r.permission === "bash") + expect(bashReq).toBeDefined() + expect(bashReq!.always).toContain("Remove-Item *") + expect(bashReq!.always).not.toContain("Remove-Item -Recurse *") + }), + ) + }), + ), ) } - each("asks for external_directory permission for wildcard external paths", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + each("asks for external_directory permission for wildcard external paths", () => + runIn( + projectRoot, + Effect.gen(function* () { const err = new Error("stop after permission") const requests: Array> = [] const file = process.platform === "win32" ? `${process.env.WINDIR!.replaceAll("\\", "/")}/*` : "/etc/*" const want = process.platform === "win32" ? glob(path.join(process.env.WINDIR!, "*")) : "/etc/*" - await expect( - Effect.runPromise( - bash.execute( - { - command: `cat ${file}`, - description: "Read wildcard path", - }, - capture(requests, err), - ), + expect( + yield* fail( + { + command: `cat ${file}`, + description: "Read wildcard path", + }, + capture(requests, err), ), - ).rejects.toThrow(err.message) + ).toMatchObject({ message: err.message }) const extDirReq = requests.find((r) => r.permission === "external_directory") expect(extDirReq).toBeDefined() expect(extDirReq!.patterns).toContain(want) - }, - }) - }) + }), + ), + ) if (process.platform === "win32") { if (bash) { - test( - "asks for nested bash command permissions [bash]", - withShell({ label: "bash", shell: bash }, async () => { - await using outerTmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "outside.txt"), "x") - }, - }) - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() - const file = path.join(outerTmp.path, "outside.txt").replaceAll("\\", "/") - const requests: Array> = [] - await Effect.runPromise( - bash.execute( + it.live("asks for nested bash command permissions [bash]", () => + withShell( + { label: "bash", shell: bash }, + Effect.gen(function* () { + const outerTmp = yield* tmpdirScoped() + yield* Effect.promise(() => Bun.write(path.join(outerTmp, "outside.txt"), "x")) + yield* runIn( + projectRoot, + Effect.gen(function* () { + const file = path.join(outerTmp, "outside.txt").replaceAll("\\", "/") + const requests: Array> = [] + yield* run( { command: `echo $(cat "${file}")`, description: "Read nested bash file", }, capture(requests), - ), - ) - const extDirReq = requests.find((r) => r.permission === "external_directory") - const bashReq = requests.find((r) => r.permission === "bash") - expect(extDirReq).toBeDefined() - expect(extDirReq!.patterns).toContain(glob(path.join(outerTmp.path, "*"))) - expect(bashReq).toBeDefined() - expect(bashReq!.patterns).toContain(`cat "${file}"`) - }, - }) - }), + ) + const extDirReq = requests.find((r) => r.permission === "external_directory") + const bashReq = requests.find((r) => r.permission === "bash") + expect(extDirReq).toBeDefined() + expect(extDirReq!.patterns).toContain(glob(path.join(outerTmp, "*"))) + expect(bashReq).toBeDefined() + expect(bashReq!.patterns).toContain(`cat "${file}"`) + }), + ) + }), + ), ) } - } - if (process.platform === "win32") { for (const item of ps) { - test( - `asks for external_directory permission for PowerShell paths after switches [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live(`asks for external_directory permission for PowerShell paths after switches [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { const err = new Error("stop after permission") const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( - { - command: `Copy-Item -PassThru "${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini" ./out`, - description: "Copy Windows ini", - }, - capture(requests, err), - ), + expect( + yield* fail( + { + command: `Copy-Item -PassThru "${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini" ./out`, + description: "Copy Windows ini", + }, + capture(requests, err), ), - ).rejects.toThrow(err.message) + ).toMatchObject({ message: err.message }) const extDirReq = requests.find((r) => r.permission === "external_directory") expect(extDirReq).toBeDefined() expect(extDirReq!.patterns).toContain(glob(path.join(process.env.WINDIR!, "*"))) - }, - }) - }), + }), + ), + ), ) } for (const item of ps) { - test( - `asks for nested PowerShell command permissions [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live(`asks for nested PowerShell command permissions [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { const requests: Array> = [] const file = `${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini` - await Effect.runPromise( - bash.execute( - { - command: `Write-Output $(Get-Content ${file})`, - description: "Read nested PowerShell file", - }, - capture(requests), - ), + yield* run( + { + command: `Write-Output $(Get-Content ${file})`, + description: "Read nested PowerShell file", + }, + capture(requests), ) const extDirReq = requests.find((r) => r.permission === "external_directory") const bashReq = requests.find((r) => r.permission === "bash") @@ -418,283 +419,266 @@ describe("tool.shell permissions", () => { expect(extDirReq!.patterns).toContain(glob(path.join(process.env.WINDIR!, "*"))) expect(bashReq).toBeDefined() expect(bashReq!.patterns).toContain(`Get-Content ${file}`) - }, - }) - }), + }), + ), + ), ) } for (const item of ps) { - test( - `asks for external_directory permission for drive-relative PowerShell paths [${item.label}]`, - withShell(item, async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initShell() - const err = new Error("stop after permission") - const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( + it.live(`asks for external_directory permission for drive-relative PowerShell paths [${item.label}]`, () => + withShell( + item, + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + expect( + yield* fail( { command: 'Get-Content "C:../outside.txt"', description: "Read drive-relative file", }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) - expect(requests[0]?.permission).toBe("external_directory") - if (requests[0]?.permission !== "external_directory") return - expect(requests[0].patterns).toContain(glob(path.join(path.dirname(tmp.path), "*"))) - }, - }) - }), + ).toMatchObject({ message: err.message }) + expect(requests[0]?.permission).toBe("external_directory") + if (requests[0]?.permission !== "external_directory") return + expect(requests[0].patterns).toContain(glob(path.join(path.dirname(tmp), "*"))) + }), + ) + }), + ), ) } for (const item of ps) { - test( - `asks for external_directory permission for $HOME PowerShell paths [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live(`asks for external_directory permission for $HOME PowerShell paths [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { const err = new Error("stop after permission") const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( - { - command: 'Get-Content "$HOME/.ssh/config"', - description: "Read home config", - }, - capture(requests, err), - ), + expect( + yield* fail( + { + command: 'Get-Content "$HOME/.ssh/config"', + description: "Read home config", + }, + capture(requests, err), ), - ).rejects.toThrow(err.message) + ).toMatchObject({ message: err.message }) expect(requests[0]?.permission).toBe("external_directory") if (requests[0]?.permission !== "external_directory") return expect(requests[0].patterns).toContain(glob(path.join(os.homedir(), ".ssh", "*"))) - }, - }) - }), + }), + ), + ), ) } for (const item of ps) { - test( - `asks for external_directory permission for $PWD PowerShell paths [${item.label}]`, - withShell(item, async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const err = new Error("stop after permission") - const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( + it.live(`asks for external_directory permission for $PWD PowerShell paths [${item.label}]`, () => + withShell( + item, + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + expect( + yield* fail( { command: 'Get-Content "$PWD/../outside.txt"', description: "Read pwd-relative file", }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) - expect(requests[0]?.permission).toBe("external_directory") - if (requests[0]?.permission !== "external_directory") return - expect(requests[0].patterns).toContain(glob(path.join(path.dirname(tmp.path), "*"))) - }, - }) - }), + ).toMatchObject({ message: err.message }) + expect(requests[0]?.permission).toBe("external_directory") + if (requests[0]?.permission !== "external_directory") return + expect(requests[0].patterns).toContain(glob(path.join(path.dirname(tmp), "*"))) + }), + ) + }), + ), ) } for (const item of ps) { - test( - `asks for external_directory permission for $PSHOME PowerShell paths [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initBash() + it.live(`asks for external_directory permission for $PSHOME PowerShell paths [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { const err = new Error("stop after permission") const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( - { - command: 'Get-Content "$PSHOME/outside.txt"', - description: "Read pshome file", - }, - capture(requests, err), - ), + expect( + yield* fail( + { + command: 'Get-Content "$PSHOME/outside.txt"', + description: "Read pshome file", + }, + capture(requests, err), ), - ).rejects.toThrow(err.message) + ).toMatchObject({ message: err.message }) expect(requests[0]?.permission).toBe("external_directory") if (requests[0]?.permission !== "external_directory") return expect(requests[0].patterns).toContain(glob(path.join(path.dirname(item.shell), "*"))) - }, - }) - }), + }), + ), + ), ) } for (const item of ps) { - test( - `asks for external_directory permission for missing PowerShell env paths [${item.label}]`, - withShell(item, async () => { - const key = "OPENCODE_TEST_MISSING" - const prev = process.env[key] - delete process.env[key] - try { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() - const err = new Error("stop after permission") - const requests: Array> = [] - const root = path.parse(process.env.WINDIR!).root.replace(/[\\/]+$/, "") - await expect( - Effect.runPromise( - bash.execute( + it.live(`asks for external_directory permission for missing PowerShell env paths [${item.label}]`, () => + withShell( + item, + Effect.acquireUseRelease( + Effect.sync(() => { + const key = "OPENCODE_TEST_MISSING" + const prev = process.env[key] + delete process.env[key] + return { key, prev } + }), + ({ key }) => + runIn( + projectRoot, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + const root = path.parse(process.env.WINDIR!).root.replace(/[\\/]+$/, "") + expect( + yield* fail( { command: `Get-Content -Path "${root}$env:${key}\\Windows\\win.ini"`, description: "Read Windows ini with missing env", }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) - const extDirReq = requests.find((r) => r.permission === "external_directory") - expect(extDirReq).toBeDefined() - expect(extDirReq!.patterns).toContain(glob(path.join(process.env.WINDIR!, "*"))) - }, - }) - } finally { - if (prev === undefined) delete process.env[key] - else process.env[key] = prev - } - }), + ).toMatchObject({ message: err.message }) + const extDirReq = requests.find((r) => r.permission === "external_directory") + expect(extDirReq).toBeDefined() + expect(extDirReq!.patterns).toContain(glob(path.join(process.env.WINDIR!, "*"))) + }), + ), + ({ key, prev }) => + Effect.sync(() => { + if (prev === undefined) delete process.env[key] + else process.env[key] = prev + }), + ), + ), ) } for (const item of ps) { - test( - `asks for external_directory permission for PowerShell env paths [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initBash() + it.live(`asks for external_directory permission for PowerShell env paths [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { const requests: Array> = [] - await Effect.runPromise( - bash.execute( - { - command: "Get-Content $env:WINDIR/win.ini", - description: "Read Windows ini from env", - }, - capture(requests), - ), + yield* run( + { + command: "Get-Content $env:WINDIR/win.ini", + description: "Read Windows ini from env", + }, + capture(requests), ) const extDirReq = requests.find((r) => r.permission === "external_directory") expect(extDirReq).toBeDefined() expect(extDirReq!.patterns).toContain( Filesystem.normalizePathPattern(path.join(process.env.WINDIR!, "*")), ) - }, - }) - }), + }), + ), + ), ) } for (const item of ps) { - test( - `asks for external_directory permission for PowerShell FileSystem paths [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initBash() + it.live(`asks for external_directory permission for PowerShell FileSystem paths [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { const err = new Error("stop after permission") const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( - { - command: `Get-Content -Path FileSystem::${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini`, - description: "Read Windows ini from FileSystem provider", - }, - capture(requests, err), - ), - ), - ).rejects.toThrow(err.message) - expect(requests[0]?.permission).toBe("external_directory") - if (requests[0]?.permission !== "external_directory") return - expect(requests[0].patterns).toContain( - Filesystem.normalizePathPattern(path.join(process.env.WINDIR!, "*")), - ) - }, - }) - }), - ) - } - - for (const item of ps) { - test( - `asks for external_directory permission for braced PowerShell env paths [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initBash() - const err = new Error("stop after permission") - const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( - { - command: "Get-Content ${env:WINDIR}/win.ini", - description: "Read Windows ini from braced env", - }, - capture(requests, err), - ), - ), - ).rejects.toThrow(err.message) - expect(requests[0]?.permission).toBe("external_directory") - if (requests[0]?.permission !== "external_directory") return - expect(requests[0].patterns).toContain( - Filesystem.normalizePathPattern(path.join(process.env.WINDIR!, "*")), - ) - }, - }) - }), - ) - } - - for (const item of ps) { - test( - `treats Set-Location like cd for permissions [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initBash() - const requests: Array> = [] - await Effect.runPromise( - bash.execute( + expect( + yield* fail( { - command: "Set-Location C:/Windows", - description: "Change location", + command: `Get-Content -Path FileSystem::${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini`, + description: "Read Windows ini from FileSystem provider", }, - capture(requests), + capture(requests, err), ), + ).toMatchObject({ message: err.message }) + expect(requests[0]?.permission).toBe("external_directory") + if (requests[0]?.permission !== "external_directory") return + expect(requests[0].patterns).toContain( + Filesystem.normalizePathPattern(path.join(process.env.WINDIR!, "*")), + ) + }), + ), + ), + ) + } + + for (const item of ps) { + it.live(`asks for external_directory permission for braced PowerShell env paths [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + expect( + yield* fail( + { + command: "Get-Content ${env:WINDIR}/win.ini", + description: "Read Windows ini from braced env", + }, + capture(requests, err), + ), + ).toMatchObject({ message: err.message }) + expect(requests[0]?.permission).toBe("external_directory") + if (requests[0]?.permission !== "external_directory") return + expect(requests[0].patterns).toContain( + Filesystem.normalizePathPattern(path.join(process.env.WINDIR!, "*")), + ) + }), + ), + ), + ) + } + + for (const item of ps) { + it.live(`treats Set-Location like cd for permissions [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { + const requests: Array> = [] + yield* run( + { + command: "Set-Location C:/Windows", + description: "Change location", + }, + capture(requests), ) const extDirReq = requests.find((r) => r.permission === "external_directory") const bashReq = requests.find((r) => r.permission === "bash") @@ -703,104 +687,96 @@ describe("tool.shell permissions", () => { Filesystem.normalizePathPattern(path.join(process.env.WINDIR!, "*")), ) expect(bashReq).toBeUndefined() - }, - }) - }), + }), + ), + ), ) } for (const item of ps) { - test( - `does not add nested PowerShell expressions to permission prompts [${item.label}]`, - withShell(item, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live(`does not add nested PowerShell expressions to permission prompts [${item.label}]`, () => + withShell( + item, + runIn( + projectRoot, + Effect.gen(function* () { const requests: Array> = [] - await Effect.runPromise( - bash.execute( - { - command: "Write-Output ('a' * 3)", - description: "Write repeated text", - }, - capture(requests), - ), + yield* run( + { + command: "Write-Output ('a' * 3)", + description: "Write repeated text", + }, + capture(requests), ) const bashReq = requests.find((r) => r.permission === "bash") expect(bashReq).toBeDefined() expect(bashReq!.patterns).not.toContain("a * 3") expect(bashReq!.always).not.toContain("a *") - }, - }) - }), + }), + ), + ), ) } } if (process.platform === "win32" && cmdShell) { - test( - "asks for external_directory permission for cmd file commands [cmd]", - withShell(cmdShell, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live("asks for external_directory permission for cmd file commands [cmd]", () => + withShell( + cmdShell, + runIn( + projectRoot, + Effect.gen(function* () { const requests: Array> = [] - await Effect.runPromise( - bash.execute( - { - command: `TYPE "${path.join(process.env.WINDIR!, "win.ini")}"`, - description: "Read Windows ini with cmd", - }, - capture(requests), - ), + yield* run( + { + command: `TYPE "${path.join(process.env.WINDIR!, "win.ini")}"`, + description: "Read Windows ini with cmd", + }, + capture(requests), ) const extDirReq = requests.find((r) => r.permission === "external_directory") expect(extDirReq).toBeDefined() expect(extDirReq!.patterns).toContain(Filesystem.normalizePathPattern(path.join(process.env.WINDIR!, "*"))) - }, - }) - }), + }), + ), + ), ) } - each("asks for external_directory permission when cd to parent", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const err = new Error("stop after permission") - const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( + each("asks for external_directory permission when cd to parent", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + expect( + yield* fail( { command: "cd ../", description: "Change to parent directory", }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) - const extDirReq = requests.find((r) => r.permission === "external_directory") - expect(extDirReq).toBeDefined() - }, - }) - }) + ).toMatchObject({ message: err.message }) + const extDirReq = requests.find((r) => r.permission === "external_directory") + expect(extDirReq).toBeDefined() + }), + ) + }), + ) - each("asks for external_directory permission when workdir is outside project", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const err = new Error("stop after permission") - const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( + each("asks for external_directory permission when workdir is outside project", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + expect( + yield* fail( { command: "echo ok", workdir: os.tmpdir(), @@ -808,31 +784,30 @@ describe("tool.shell permissions", () => { }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) - const extDirReq = requests.find((r) => r.permission === "external_directory") - expect(extDirReq).toBeDefined() - expect(extDirReq!.patterns).toContain(glob(path.join(os.tmpdir(), "*"))) - }, - }) - }) + ).toMatchObject({ message: err.message }) + const extDirReq = requests.find((r) => r.permission === "external_directory") + expect(extDirReq).toBeDefined() + expect(extDirReq!.patterns).toContain(glob(path.join(os.tmpdir(), "*"))) + }), + ) + }), + ) if (process.platform === "win32") { - test("normalizes external_directory workdir variants on Windows", async () => { - const err = new Error("stop after permission") - await using outerTmp = await tmpdir() - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const want = Filesystem.normalizePathPattern(path.join(outerTmp.path, "*")) + it.live("normalizes external_directory workdir variants on Windows", () => + Effect.gen(function* () { + const err = new Error("stop after permission") + const outerTmp = yield* tmpdirScoped() + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const want = Filesystem.normalizePathPattern(path.join(outerTmp, "*")) - for (const dir of forms(outerTmp.path)) { - const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( + for (const dir of forms(outerTmp)) { + const requests: Array> = [] + expect( + yield* fail( { command: "echo ok", workdir: dir, @@ -840,240 +815,224 @@ describe("tool.shell permissions", () => { }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) + ).toMatchObject({ message: err.message }) - const extDirReq = requests.find((r) => r.permission === "external_directory") - expect({ dir, patterns: extDirReq?.patterns, always: extDirReq?.always }).toEqual({ - dir, - patterns: [want], - always: [want], - }) - } - }, - }) - }) + const extDirReq = requests.find((r) => r.permission === "external_directory") + expect({ dir, patterns: extDirReq?.patterns, always: extDirReq?.always }).toEqual({ + dir, + patterns: [want], + always: [want], + }) + } + }), + ) + }), + ) if (bash) { - test( - "uses Git Bash /tmp semantics for external workdir", - withShell({ label: "bash", shell: bash }, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initBash() + it.live("uses Git Bash /tmp semantics for external workdir", () => + withShell( + { label: "bash", shell: bash }, + runIn( + projectRoot, + Effect.gen(function* () { const err = new Error("stop after permission") const requests: Array> = [] const want = glob(path.join(os.tmpdir(), "*")) - await expect( - Effect.runPromise( - bash.execute( - { - command: "echo ok", - workdir: "/tmp", - description: "Echo from Git Bash tmp", - }, - capture(requests, err), - ), + expect( + yield* fail( + { + command: "echo ok", + workdir: "/tmp", + description: "Echo from Git Bash tmp", + }, + capture(requests, err), ), - ).rejects.toThrow(err.message) + ).toMatchObject({ message: err.message }) expect(requests[0]).toMatchObject({ permission: "external_directory", patterns: [want], always: [want], }) - }, - }) - }), + }), + ), + ), ) - test( - "uses Git Bash /tmp semantics for external file paths", - withShell({ label: "bash", shell: bash }, async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initBash() + it.live("uses Git Bash /tmp semantics for external file paths", () => + withShell( + { label: "bash", shell: bash }, + runIn( + projectRoot, + Effect.gen(function* () { const err = new Error("stop after permission") const requests: Array> = [] const want = glob(path.join(os.tmpdir(), "*")) - await expect( - Effect.runPromise( - bash.execute( - { - command: "cat /tmp/opencode-does-not-exist", - description: "Read Git Bash tmp file", - }, - capture(requests, err), - ), + expect( + yield* fail( + { + command: "cat /tmp/opencode-does-not-exist", + description: "Read Git Bash tmp file", + }, + capture(requests, err), ), - ).rejects.toThrow(err.message) + ).toMatchObject({ message: err.message }) expect(requests[0]).toMatchObject({ permission: "external_directory", patterns: [want], always: [want], }) - }, - }) - }), + }), + ), + ), ) } } - each("asks for external_directory permission when file arg is outside project", async () => { - await using outerTmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "outside.txt"), "x") - }, - }) - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const err = new Error("stop after permission") - const requests: Array> = [] - const filepath = path.join(outerTmp.path, "outside.txt") - await expect( - Effect.runPromise( - bash.execute( + each("asks for external_directory permission when file arg is outside project", () => + Effect.gen(function* () { + const outerTmp = yield* tmpdirScoped() + yield* Effect.promise(() => Bun.write(path.join(outerTmp, "outside.txt"), "x")) + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + const filepath = path.join(outerTmp, "outside.txt") + expect( + yield* fail( { command: `cat ${filepath}`, description: "Read external file", }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) - const extDirReq = requests.find((r) => r.permission === "external_directory") - const expected = glob(path.join(outerTmp.path, "*")) - expect(extDirReq).toBeDefined() - expect(extDirReq!.patterns).toContain(expected) - expect(extDirReq!.always).toContain(expected) - }, - }) - }) + ).toMatchObject({ message: err.message }) + const extDirReq = requests.find((r) => r.permission === "external_directory") + const expected = glob(path.join(outerTmp, "*")) + expect(extDirReq).toBeDefined() + expect(extDirReq!.patterns).toContain(expected) + expect(extDirReq!.always).toContain(expected) + }), + ) + }), + ) - each("does not ask for external_directory permission when rm inside project", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write(path.join(dir, "tmpfile"), "x") - }, - }) - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const requests: Array> = [] - await Effect.runPromise( - bash.execute( + each("does not ask for external_directory permission when rm inside project", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* Effect.promise(() => Bun.write(path.join(tmp, "tmpfile"), "x")) + yield* runIn( + tmp, + Effect.gen(function* () { + const requests: Array> = [] + yield* run( { - command: `rm -rf ${path.join(tmp.path, "nested")}`, + command: `rm -rf ${path.join(tmp, "nested")}`, description: "Remove nested dir", }, capture(requests), - ), - ) - const extDirReq = requests.find((r) => r.permission === "external_directory") - expect(extDirReq).toBeUndefined() - }, - }) - }) + ) + const extDirReq = requests.find((r) => r.permission === "external_directory") + expect(extDirReq).toBeUndefined() + }), + ) + }), + ) - each("includes always patterns for auto-approval", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const requests: Array> = [] - await Effect.runPromise( - bash.execute( + each("includes always patterns for auto-approval", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const requests: Array> = [] + yield* run( { command: "git log --oneline -5", description: "Git log", }, capture(requests), - ), - ) - expect(requests.length).toBe(1) - expect(requests[0].always.length).toBeGreaterThan(0) - expect(requests[0].always.some((item) => item.endsWith("*"))).toBe(true) - }, - }) - }) + ) + expect(requests.length).toBe(1) + expect(requests[0].always.length).toBeGreaterThan(0) + expect(requests[0].always.some((item) => item.endsWith("*"))).toBe(true) + }), + ) + }), + ) - each("does not ask for bash permission when command is cd only", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initShell() - const requests: Array> = [] - await Effect.runPromise( - bash.execute( + each("does not ask for bash permission when command is cd only", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const requests: Array> = [] + yield* run( { command: "cd .", description: "Stay in current directory", }, capture(requests), - ), - ) - const bashReq = requests.find((r) => r.permission === "bash") - expect(bashReq).toBeUndefined() - }, - }) - }) + ) + const bashReq = requests.find((r) => r.permission === "bash") + expect(bashReq).toBeUndefined() + }), + ) + }), + ) - each("matches redirects in permission pattern", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initShell() - const err = new Error("stop after permission") - const requests: Array> = [] - await expect( - Effect.runPromise( - bash.execute( + each("matches redirects in permission pattern", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const err = new Error("stop after permission") + const requests: Array> = [] + expect( + yield* fail( { command: "echo test > output.txt", description: "Redirect test output" }, capture(requests, err), ), - ), - ).rejects.toThrow(err.message) - const bashReq = requests.find((r) => r.permission === "bash") - expect(bashReq).toBeDefined() - expect(bashReq!.patterns).toContain("echo test > output.txt") - }, - }) - }) + ).toMatchObject({ message: err.message }) + const bashReq = requests.find((r) => r.permission === "bash") + expect(bashReq).toBeDefined() + expect(bashReq!.patterns).toContain("echo test > output.txt") + }), + ) + }), + ) - each("always pattern has space before wildcard to not include different commands", async () => { - await using tmp = await tmpdir() - await WithInstance.provide({ - directory: tmp.path, - fn: async () => { - const bash = await initBash() - const requests: Array> = [] - await Effect.runPromise(bash.execute({ command: "ls -la", description: "List" }, capture(requests))) - const bashReq = requests.find((r) => r.permission === "bash") - expect(bashReq).toBeDefined() - expect(bashReq!.always[0]).toBe("ls *") - }, - }) - }) + each("always pattern has space before wildcard to not include different commands", () => + Effect.gen(function* () { + const tmp = yield* tmpdirScoped() + yield* runIn( + tmp, + Effect.gen(function* () { + const requests: Array> = [] + yield* run({ command: "ls -la", description: "List" }, capture(requests)) + const bashReq = requests.find((r) => r.permission === "bash") + expect(bashReq).toBeDefined() + expect(bashReq!.always[0]).toBe("ls *") + }), + ) + }), + ) }) describe("tool.shell abort", () => { - test("preserves output when aborted", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() - const controller = new AbortController() - const collected: string[] = [] - const res = await Effect.runPromise( - bash.execute( + it.live( + "preserves output when aborted", + () => + runIn( + projectRoot, + Effect.gen(function* () { + const controller = new AbortController() + const collected: string[] = [] + const res = yield* run( { command: `echo before && sleep 30`, description: "Long running command", @@ -1090,198 +1049,158 @@ describe("tool.shell abort", () => { } }), }, - ), - ) - expect(res.output).toContain("before") - expect(res.output).toContain("User aborted the command") - expect(collected.length).toBeGreaterThan(0) - }, - }) - }, 15_000) + ) + expect(res.output).toContain("before") + expect(res.output).toContain("User aborted the command") + expect(collected.length).toBeGreaterThan(0) + }), + ), + 15_000, + ) - test("terminates command on timeout", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() - const result = await Effect.runPromise( - bash.execute( - { - command: `echo started && sleep 60`, - description: "Timeout test", - timeout: 500, - }, - ctx, - ), - ) - expect(result.output).toContain("started") - expect(result.output).toContain("shell tool terminated command after exceeding timeout") - expect(result.output).toContain("retry with a larger timeout value in milliseconds") - }, - }) - }, 15_000) + it.live( + "terminates command on timeout", + () => + runIn( + projectRoot, + Effect.gen(function* () { + const result = yield* run({ + command: `echo started && sleep 60`, + description: "Timeout test", + timeout: 500, + }) + expect(result.output).toContain("started") + expect(result.output).toContain("shell tool terminated command after exceeding timeout") + expect(result.output).toContain("retry with a larger timeout value in milliseconds") + }), + ), + 15_000, + ) - test.skipIf(process.platform === "win32")("captures stderr in output", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() - const result = await Effect.runPromise( - bash.execute( - { - command: `echo stdout_msg && echo stderr_msg >&2`, - description: "Stderr test", - }, - ctx, - ), - ) - expect(result.output).toContain("stdout_msg") - expect(result.output).toContain("stderr_msg") - expect(result.metadata.exit).toBe(0) - }, - }) - }) + if (process.platform !== "win32") { + it.live("captures stderr in output", () => + runIn( + projectRoot, + Effect.gen(function* () { + const result = yield* run({ + command: `echo stdout_msg && echo stderr_msg >&2`, + description: "Stderr test", + }) + expect(result.output).toContain("stdout_msg") + expect(result.output).toContain("stderr_msg") + expect(result.metadata.exit).toBe(0) + }), + ), + ) + } - test("returns non-zero exit code", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() - const result = await Effect.runPromise( - bash.execute( - { - command: `exit 42`, - description: "Non-zero exit", - }, - ctx, - ), - ) + it.live("returns non-zero exit code", () => + runIn( + projectRoot, + Effect.gen(function* () { + const result = yield* run({ + command: `exit 42`, + description: "Non-zero exit", + }) expect(result.metadata.exit).toBe(42) - }, - }) - }) + }), + ), + ) - test("streams metadata updates progressively", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initBash() + it.live("streams metadata updates progressively", () => + runIn( + projectRoot, + Effect.gen(function* () { const updates: string[] = [] - const result = await Effect.runPromise( - bash.execute( - { - command: `echo first && sleep 0.1 && echo second`, - description: "Streaming test", - }, - { - ...ctx, - metadata: (input) => - Effect.sync(() => { - const output = (input.metadata as { output?: string })?.output - if (output) updates.push(output) - }), - }, - ), + const result = yield* run( + { + command: `echo first && sleep 0.1 && echo second`, + description: "Streaming test", + }, + { + ...ctx, + metadata: (input) => + Effect.sync(() => { + const output = (input.metadata as { output?: string })?.output + if (output) updates.push(output) + }), + }, ) expect(result.output).toContain("first") expect(result.output).toContain("second") expect(updates.length).toBeGreaterThan(1) - }, - }) - }) + }), + ), + ) }) describe("tool.shell truncation", () => { - test("truncates output exceeding line limit", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live("truncates output exceeding line limit", () => + runIn( + projectRoot, + Effect.gen(function* () { const lineCount = Truncate.MAX_LINES + 500 - const result = await Effect.runPromise( - bash.execute( - { - command: fill("lines", lineCount), - description: "Generate lines exceeding limit", - }, - ctx, - ), - ) + const result = yield* run({ + command: fill("lines", lineCount), + description: "Generate lines exceeding limit", + }) mustTruncate(result) expect(result.output).toMatch(/\.\.\.output truncated\.\.\./) expect(result.output).toMatch(/Full output saved to:\s+\S+/) - }, - }) - }) + }), + ), + ) - test("truncates output exceeding byte limit", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live("truncates output exceeding byte limit", () => + runIn( + projectRoot, + Effect.gen(function* () { const byteCount = Truncate.MAX_BYTES + 10000 - const result = await Effect.runPromise( - bash.execute( - { - command: fill("bytes", byteCount), - description: "Generate bytes exceeding limit", - }, - ctx, - ), - ) + const result = yield* run({ + command: fill("bytes", byteCount), + description: "Generate bytes exceeding limit", + }) mustTruncate(result) expect(result.output).toMatch(/\.\.\.output truncated\.\.\./) expect(result.output).toMatch(/Full output saved to:\s+\S+/) - }, - }) - }) + }), + ), + ) - test("does not truncate small output", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() - const result = await Effect.runPromise( - bash.execute( - { - command: "echo hello", - description: "Echo hello", - }, - ctx, - ), - ) + it.live("does not truncate small output", () => + runIn( + projectRoot, + Effect.gen(function* () { + const result = yield* run({ + command: fill("lines", 1), + description: "Generate one line", + }) expect((result.metadata as { truncated?: boolean }).truncated).toBe(false) - expect(result.output).toContain("hello") - }, - }) - }) + expect(result.output).toContain("1") + }), + ), + ) - test("full output is saved to file when truncated", async () => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const bash = await initShell() + it.live("full output is saved to file when truncated", () => + runIn( + projectRoot, + Effect.gen(function* () { const lineCount = Truncate.MAX_LINES + 100 - const result = await Effect.runPromise( - bash.execute( - { - command: fill("lines", lineCount), - description: "Generate lines for file check", - }, - ctx, - ), - ) + const result = yield* run({ + command: fill("lines", lineCount), + description: "Generate lines for file check", + }) mustTruncate(result) const filepath = (result.metadata as { outputPath?: string }).outputPath expect(filepath).toBeTruthy() - const saved = await Filesystem.readText(filepath!) + const saved = yield* Effect.promise(() => Filesystem.readText(filepath!)) const lines = saved.trim().split(/\r?\n/) expect(lines.length).toBe(lineCount) expect(lines[0]).toBe("1") expect(lines[lineCount - 1]).toBe(String(lineCount)) - }, - }) - }) + }), + ), + ) }) diff --git a/packages/opencode/test/tool/tool-define.test.ts b/packages/opencode/test/tool/tool-define.test.ts index a291b9f7f9..ca351cca48 100644 --- a/packages/opencode/test/tool/tool-define.test.ts +++ b/packages/opencode/test/tool/tool-define.test.ts @@ -1,11 +1,12 @@ -import { describe, test, expect } from "bun:test" -import { Effect, Layer, ManagedRuntime, Schema } from "effect" +import { describe, expect } from "bun:test" +import { Effect, Layer, Schema } from "effect" import { Agent } from "../../src/agent/agent" import { MessageID, SessionID } from "../../src/session/schema" import { Tool } from "@/tool/tool" import { Truncate } from "@/tool/truncate" +import { testEffect } from "../lib/effect" -const runtime = ManagedRuntime.make(Layer.mergeAll(Truncate.defaultLayer, Agent.defaultLayer)) +const it = testEffect(Layer.mergeAll(Truncate.defaultLayer, Agent.defaultLayer)) const params = Schema.Struct({ input: Schema.String }) @@ -21,49 +22,53 @@ function makeTool(id: string, executeFn?: () => void) { } describe("Tool.define", () => { - test("object-defined tool does not mutate the original init object", async () => { - const original = makeTool("test") - const originalExecute = original.execute + it.effect("object-defined tool does not mutate the original init object", () => + Effect.gen(function* () { + const original = makeTool("test") + const originalExecute = original.execute - const info = await runtime.runPromise(Tool.define("test-tool", Effect.succeed(original))) + const info = yield* Tool.define("test-tool", Effect.succeed(original)) - await Effect.runPromise(info.init()) - await Effect.runPromise(info.init()) - await Effect.runPromise(info.init()) + yield* info.init() + yield* info.init() + yield* info.init() - expect(original.execute).toBe(originalExecute) - }) + expect(original.execute).toBe(originalExecute) + }), + ) - test("effect-defined tool returns fresh objects and is unaffected", async () => { - const info = await runtime.runPromise( - Tool.define( + it.effect("effect-defined tool returns fresh objects and is unaffected", () => + Effect.gen(function* () { + const info = yield* Tool.define( "test-fn-tool", Effect.succeed(() => Effect.succeed(makeTool("test"))), - ), - ) + ) - const first = await Effect.runPromise(info.init()) - const second = await Effect.runPromise(info.init()) + const first = yield* info.init() + const second = yield* info.init() - expect(first).not.toBe(second) - }) + expect(first).not.toBe(second) + }), + ) - test("object-defined tool returns distinct objects per init() call", async () => { - const info = await runtime.runPromise(Tool.define("test-copy", Effect.succeed(makeTool("test")))) + it.effect("object-defined tool returns distinct objects per init() call", () => + Effect.gen(function* () { + const info = yield* Tool.define("test-copy", Effect.succeed(makeTool("test"))) - const first = await Effect.runPromise(info.init()) - const second = await Effect.runPromise(info.init()) + const first = yield* info.init() + const second = yield* info.init() - expect(first).not.toBe(second) - }) + expect(first).not.toBe(second) + }), + ) - test("execute receives decoded parameters", async () => { - const parameters = Schema.Struct({ - count: Schema.NumberFromString.pipe(Schema.optional, Schema.withDecodingDefaultType(Effect.succeed(5))), - }) - const calls: Array> = [] - const info = await runtime.runPromise( - Tool.define( + it.effect("execute receives decoded parameters", () => + Effect.gen(function* () { + const parameters = Schema.Struct({ + count: Schema.NumberFromString.pipe(Schema.optional, Schema.withDecodingDefaultType(Effect.succeed(5))), + }) + const calls: Array> = [] + const info = yield* Tool.define( "test-decoded", Effect.succeed({ description: "test tool", @@ -73,27 +78,27 @@ describe("Tool.define", () => { return Effect.succeed({ title: "test", output: "ok", metadata: { truncated: false } }) }, }), - ), - ) - const ctx: Tool.Context = { - sessionID: SessionID.descending(), - messageID: MessageID.ascending(), - agent: "build", - abort: new AbortController().signal, - messages: [], - metadata() { - return Effect.void - }, - ask() { - return Effect.void - }, - } - const tool = await Effect.runPromise(info.init()) - const execute = tool.execute as unknown as (args: unknown, ctx: Tool.Context) => ReturnType + ) + const ctx: Tool.Context = { + sessionID: SessionID.descending(), + messageID: MessageID.ascending(), + agent: "build", + abort: new AbortController().signal, + messages: [], + metadata() { + return Effect.void + }, + ask() { + return Effect.void + }, + } + const tool = yield* info.init() + const execute = tool.execute as unknown as (args: unknown, ctx: Tool.Context) => ReturnType - await Effect.runPromise(execute({}, ctx)) - await Effect.runPromise(execute({ count: "7" }, ctx)) + yield* execute({}, ctx) + yield* execute({ count: "7" }, ctx) - expect(calls).toEqual([{ count: 5 }, { count: 7 }]) - }) + expect(calls).toEqual([{ count: 5 }, { count: 7 }]) + }), + ) }) diff --git a/packages/opencode/test/tool/webfetch.test.ts b/packages/opencode/test/tool/webfetch.test.ts index f3890c0161..fdf5210b9c 100644 --- a/packages/opencode/test/tool/webfetch.test.ts +++ b/packages/opencode/test/tool/webfetch.test.ts @@ -1,15 +1,14 @@ -import { describe, expect, test } from "bun:test" -import path from "path" +import { describe, expect } from "bun:test" import { Effect, Layer } from "effect" import { FetchHttpClient } from "effect/unstable/http" import { Agent } from "../../src/agent/agent" import { Truncate } from "@/tool/truncate" -import { Instance } from "../../src/project/instance" -import { WithInstance } from "../../src/project/with-instance" import { WebFetchTool } from "../../src/tool/webfetch" import { SessionID, MessageID } from "../../src/session/schema" +import { Tool } from "@/tool/tool" +import { testEffect } from "../lib/effect" -const projectRoot = path.join(import.meta.dir, "../..") +const it = testEffect(Layer.mergeAll(FetchHttpClient.layer, Truncate.defaultLayer, Agent.defaultLayer)) const ctx = { sessionID: SessionID.make("ses_test"), @@ -22,30 +21,31 @@ const ctx = { ask: () => Effect.void, } -async function withFetch(fetch: (req: Request) => Response | Promise, fn: (url: URL) => Promise) { - using server = Bun.serve({ port: 0, fetch }) - await fn(server.url) -} - -function exec(args: { url: string; format: "text" | "markdown" | "html" }) { - return WebFetchTool.pipe( - Effect.flatMap((info) => info.init()), - Effect.flatMap((tool) => tool.execute(args, ctx)), - Effect.provide(Layer.mergeAll(FetchHttpClient.layer, Truncate.defaultLayer, Agent.defaultLayer)), - Effect.runPromise, +const withFetch = ( + fetch: (req: Request) => Response | Promise, + fn: (url: URL) => Effect.Effect, +) => + Effect.acquireUseRelease( + Effect.sync(() => Bun.serve({ port: 0, fetch })), + (server) => fn(server.url), + (server) => Effect.sync(() => server.stop(true)), ) -} + +const exec = Effect.fn("WebFetchToolTest.exec")(function* (args: Tool.InferParameters) { + const info = yield* WebFetchTool + const tool = yield* info.init() + return yield* tool.execute(args, ctx) +}) describe("tool.webfetch", () => { - test("returns image responses as file attachments", async () => { - const bytes = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]) - await withFetch( - () => new Response(bytes, { status: 200, headers: { "content-type": "IMAGE/PNG; charset=binary" } }), - async (url) => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const result = await exec({ url: new URL("/image.png", url).toString(), format: "markdown" }) + it.instance("returns image responses as file attachments", () => + Effect.gen(function* () { + const bytes = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]) + yield* withFetch( + () => new Response(bytes, { status: 200, headers: { "content-type": "IMAGE/PNG; charset=binary" } }), + (url) => + Effect.gen(function* () { + const result = yield* exec({ url: new URL("/image.png", url).toString(), format: "markdown" }) expect(result.output).toBe("Image fetched successfully") expect(result.attachments).toBeDefined() expect(result.attachments?.length).toBe(1) @@ -55,50 +55,59 @@ describe("tool.webfetch", () => { expect(result.attachments?.[0]).not.toHaveProperty("id") expect(result.attachments?.[0]).not.toHaveProperty("sessionID") expect(result.attachments?.[0]).not.toHaveProperty("messageID") - }, - }) - }, - ) - }) + }), + ) + }), + ) - test("keeps svg as text output", async () => { - const svg = 'hello' - await withFetch( + it.instance("keeps svg as text output", () => + withFetch( () => - new Response(svg, { + new Response('hello', { status: 200, headers: { "content-type": "image/svg+xml; charset=UTF-8" }, }), - async (url) => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const result = await exec({ url: new URL("/image.svg", url).toString(), format: "html" }) - expect(result.output).toContain(" + Effect.gen(function* () { + const result = yield* exec({ url: new URL("/image.svg", url).toString(), format: "html" }) + expect(result.output).toContain(" { - await withFetch( + it.instance("keeps text responses as text output", () => + withFetch( () => new Response("hello from webfetch", { status: 200, headers: { "content-type": "text/plain; charset=utf-8" }, }), - async (url) => { - await WithInstance.provide({ - directory: projectRoot, - fn: async () => { - const result = await exec({ url: new URL("/file.txt", url).toString(), format: "text" }) - expect(result.output).toBe("hello from webfetch") - expect(result.attachments).toBeUndefined() + (url) => + Effect.gen(function* () { + const result = yield* exec({ url: new URL("/file.txt", url).toString(), format: "text" }) + expect(result.output).toBe("hello from webfetch") + expect(result.attachments).toBeUndefined() + }), + ), + ) + + it.instance("extracts text from html without scripts or styles", () => + withFetch( + () => + new Response( + "Hello world", + { + status: 200, + headers: { "content-type": "text/html; charset=utf-8" }, }, - }) - }, - ) - }) + ), + (url) => + Effect.gen(function* () { + const result = yield* exec({ url: new URL("/page.html", url).toString(), format: "text" }) + expect(result.output).toBe("Hello world") + expect(result.attachments).toBeUndefined() + }), + ), + ) }) diff --git a/packages/opencode/test/tool/websearch.test.ts b/packages/opencode/test/tool/websearch.test.ts index 591b385fdc..b8edc2dc2f 100644 --- a/packages/opencode/test/tool/websearch.test.ts +++ b/packages/opencode/test/tool/websearch.test.ts @@ -4,6 +4,7 @@ import { parseResponse } from "../../src/tool/mcp-websearch" import { selectWebSearchProvider, webSearchModelName, webSearchProviderLabel } from "../../src/tool/websearch" import { ProviderID } from "../../src/provider/schema" import { webSearchEnabled } from "../../src/tool/registry" +import { it } from "../lib/effect" const SESSION_ID = "ses_0196aabbccddeeff001122334455" @@ -74,17 +75,24 @@ describe("websearch MCP response parser", () => { }, }) - test("parses plain JSON-RPC responses", async () => { - await expect(Effect.runPromise(parseResponse(payload))).resolves.toBe("search results") - }) + it.effect("parses plain JSON-RPC responses", () => + Effect.gen(function* () { + const result = yield* parseResponse(payload) + expect(result).toBe("search results") + }), + ) - test("parses SSE JSON-RPC responses", async () => { - await expect(Effect.runPromise(parseResponse(`event: message\ndata: ${payload}\n\n`))).resolves.toBe( - "search results", - ) - }) + it.effect("parses SSE JSON-RPC responses", () => + Effect.gen(function* () { + const result = yield* parseResponse(`event: message\ndata: ${payload}\n\n`) + expect(result).toBe("search results") + }), + ) - test("ignores non-JSON SSE data frames", async () => { - await expect(Effect.runPromise(parseResponse(`data: [DONE]\ndata: ${payload}\n\n`))).resolves.toBe("search results") - }) + it.effect("ignores non-JSON SSE data frames", () => + Effect.gen(function* () { + const result = yield* parseResponse(`data: [DONE]\ndata: ${payload}\n\n`) + expect(result).toBe("search results") + }), + ) }) diff --git a/packages/opencode/test/util/error.test.ts b/packages/opencode/test/util/error.test.ts index e7a02d6151..fdb559a231 100644 --- a/packages/opencode/test/util/error.test.ts +++ b/packages/opencode/test/util/error.test.ts @@ -1,5 +1,7 @@ import { describe, expect, test } from "bun:test" +import { NamedError } from "@opencode-ai/core/util/error" import { errorData, errorFormat, errorMessage } from "../../src/util/error" +import { MessageError } from "../../src/session/message-error" describe("util.error", () => { test("formats native Error instances", () => { @@ -48,4 +50,15 @@ describe("util.error", () => { expect(data.message).toBe("ResolveMessage: Cannot resolve module") expect(String(data.formatted)).toContain("ResolveMessage") }) + + test("schema-backed named errors are real NamedError instances", () => { + const error = new MessageError.AuthError({ providerID: "anthropic", message: "boom" }) + + expect(error).toBeInstanceOf(NamedError) + expect(error.toObject()).toEqual({ name: "ProviderAuthError", data: { providerID: "anthropic", message: "boom" } }) + }) + + test("named errors without fields serialize data", () => { + expect(new MessageError.OutputLengthError({}).toObject()).toEqual({ name: "MessageOutputLengthError", data: {} }) + }) }) diff --git a/packages/opencode/test/util/lock.test.ts b/packages/opencode/test/util/lock.test.ts deleted file mode 100644 index 79fbb58316..0000000000 --- a/packages/opencode/test/util/lock.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { describe, expect, test } from "bun:test" -import { Lock } from "@/util/lock" - -function tick() { - return new Promise((r) => queueMicrotask(r)) -} - -async function flush(n = 5) { - for (let i = 0; i < n; i++) await tick() -} - -describe("util.lock", () => { - test("writer exclusivity: blocks reads and other writes while held", async () => { - const key = "lock:" + Math.random().toString(36).slice(2) - - const state = { - writer2: false, - reader: false, - writers: 0, - } - - // Acquire writer1 - using writer1 = await Lock.write(key) - state.writers++ - expect(state.writers).toBe(1) - - // Start writer2 candidate (should block) - const writer2Task = (async () => { - const w = await Lock.write(key) - state.writers++ - expect(state.writers).toBe(1) - state.writer2 = true - // Hold for a tick so reader cannot slip in - await tick() - return w - })() - - // Start reader candidate (should block) - const readerTask = (async () => { - const r = await Lock.read(key) - state.reader = true - return r - })() - - // Flush microtasks and assert neither acquired - await flush() - expect(state.writer2).toBe(false) - expect(state.reader).toBe(false) - - // Release writer1 - writer1[Symbol.dispose]() - state.writers-- - - // writer2 should acquire next - const writer2 = await writer2Task - expect(state.writer2).toBe(true) - - // Reader still blocked while writer2 held - await flush() - expect(state.reader).toBe(false) - - // Release writer2 - writer2[Symbol.dispose]() - state.writers-- - - // Reader should now acquire - const reader = await readerTask - expect(state.reader).toBe(true) - - reader[Symbol.dispose]() - }) -}) diff --git a/packages/opencode/test/util/log.test.ts b/packages/opencode/test/util/log.test.ts index 486ca0f3b6..defd8c981e 100644 --- a/packages/opencode/test/util/log.test.ts +++ b/packages/opencode/test/util/log.test.ts @@ -1,44 +1,49 @@ -import { afterEach, expect, test } from "bun:test" +import { expect } from "bun:test" +import { Effect } from "effect" import fs from "fs/promises" import path from "path" +import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { Global } from "@opencode-ai/core/global" import * as Log from "@opencode-ai/core/util/log" -import { tmpdir } from "../fixture/fixture" +import { tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" -const log = Global.Path.log +const it = testEffect(CrossSpawnSpawner.defaultLayer) -afterEach(() => { - Global.Path.log = log -}) +function files(dir: string) { + return Effect.gen(function* () { + let last = "" + let same = 0 -async function files(dir: string) { - let last = "" - let same = 0 + for (let i = 0; i < 50; i++) { + const list = yield* Effect.promise(() => fs.readdir(dir).then((files) => files.sort())) + const next = JSON.stringify(list) + same = next === last ? same + 1 : 0 + if (same >= 2 && list.length === 11) return list + last = next + yield* Effect.sleep("10 millis") + } - for (let i = 0; i < 50; i++) { - const list = (await fs.readdir(dir)).sort() - const next = JSON.stringify(list) - same = next === last ? same + 1 : 0 - if (same >= 2 && list.length === 11) return list - last = next - await Bun.sleep(10) - } - - return (await fs.readdir(dir)).sort() + return yield* Effect.promise(() => fs.readdir(dir).then((files) => files.sort())) + }) } -test("init cleanup keeps the newest timestamped logs", async () => { - await using tmp = await tmpdir() - Global.Path.log = tmp.path +it.live("init cleanup keeps the newest timestamped logs", () => + Effect.gen(function* () { + const log = Global.Path.log + yield* Effect.addFinalizer(() => Effect.sync(() => (Global.Path.log = log))) + const dir = yield* tmpdirScoped() + Global.Path.log = dir - const list = Array.from({ length: 12 }, (_, i) => `2000-01-${String(i + 1).padStart(2, "0")}T000000.log`) + const list = Array.from({ length: 12 }, (_, i) => `2000-01-${String(i + 1).padStart(2, "0")}T000000.log`) - await Promise.all(list.map((file) => fs.writeFile(path.join(tmp.path, file), file))) + yield* Effect.all(list.map((file) => Effect.promise(() => fs.writeFile(path.join(dir, file), file)))) - await Log.init({ print: false, dev: false }) + yield* Effect.promise(() => Log.init({ print: false, dev: false })) - const next = await files(tmp.path) + const next = yield* files(dir) - expect(next).not.toContain(list[0]!) - expect(next).toContain(list.at(-1)!) -}) + expect(next).not.toContain(list[0]!) + expect(next).toContain(list.at(-1)!) + }), +) diff --git a/packages/opencode/test/v2/session-message-updater.test.ts b/packages/opencode/test/v2/session-message-updater.test.ts index 44ac031eda..180483937c 100644 --- a/packages/opencode/test/v2/session-message-updater.test.ts +++ b/packages/opencode/test/v2/session-message-updater.test.ts @@ -2,7 +2,8 @@ import { expect, test } from "bun:test" import * as DateTime from "effect/DateTime" import { SessionID } from "../../src/session/schema" import { EventV2 } from "../../src/v2/event" -import { Modelv2 } from "../../src/v2/model" +import { ModelV2 } from "@opencode-ai/core/model" +import { ProviderV2 } from "@opencode-ai/core/provider" import { SessionEvent } from "../../src/v2/session-event" import { SessionMessageUpdater } from "../../src/v2/session-message-updater" @@ -18,9 +19,9 @@ test("step snapshots carry over to assistant messages", () => { timestamp: DateTime.makeUnsafe(1), agent: "build", model: { - id: Modelv2.ID.make("model"), - providerID: Modelv2.ProviderID.make("provider"), - variant: Modelv2.VariantID.make("default"), + id: ModelV2.ID.make("model"), + providerID: ProviderV2.ID.make("provider"), + variant: ModelV2.VariantID.make("default"), }, snapshot: "before", }, @@ -62,9 +63,9 @@ test("text ended populates assistant text content", () => { timestamp: DateTime.makeUnsafe(1), agent: "build", model: { - id: Modelv2.ID.make("model"), - providerID: Modelv2.ProviderID.make("provider"), - variant: Modelv2.VariantID.make("default"), + id: ModelV2.ID.make("model"), + providerID: ProviderV2.ID.make("provider"), + variant: ModelV2.VariantID.make("default"), }, }, } satisfies SessionEvent.Event) @@ -106,9 +107,9 @@ test("tool completion stores completed timestamp", () => { timestamp: DateTime.makeUnsafe(1), agent: "build", model: { - id: Modelv2.ID.make("model"), - providerID: Modelv2.ProviderID.make("provider"), - variant: Modelv2.VariantID.make("default"), + id: ModelV2.ID.make("model"), + providerID: ProviderV2.ID.make("provider"), + variant: ModelV2.VariantID.make("default"), }, }, } satisfies SessionEvent.Event) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index a3ce97368d..baff4cddba 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -22,9 +22,9 @@ "zod": "catalog:" }, "peerDependencies": { - "@opentui/core": ">=0.2.6", - "@opentui/keymap": ">=0.2.6", - "@opentui/solid": ">=0.2.6" + "@opentui/core": ">=0.2.8", + "@opentui/keymap": ">=0.2.8", + "@opentui/solid": ">=0.2.8" }, "peerDependenciesMeta": { "@opentui/core": { diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts index 2e96dd9801..6156477be2 100644 --- a/packages/plugin/src/index.ts +++ b/packages/plugin/src/index.ts @@ -8,10 +8,9 @@ import type { UserMessage, Message, Part, - Auth, Config as SDKConfig, } from "@opencode-ai/sdk" -import type { Provider as ProviderV2, Model as ModelV2 } from "@opencode-ai/sdk/v2" +import type { Provider as ProviderV2, Model as ModelV2, Auth } from "@opencode-ai/sdk/v2" import type { BunShell } from "./shell.js" import { type ToolDefinition } from "./tool.js" @@ -153,6 +152,7 @@ export type AuthHook = { type: "success" key: string provider?: string + metadata?: Record } | { type: "failed" @@ -177,7 +177,7 @@ export type AuthOAuthResult = { url: string; instructions: string } & ( accountId?: string enterpriseUrl?: string } - | { key: string } + | { key: string; metadata?: Record } )) | { type: "failed" @@ -198,7 +198,7 @@ export type AuthOAuthResult = { url: string; instructions: string } & ( accountId?: string enterpriseUrl?: string } - | { key: string } + | { key: string; metadata?: Record } )) | { type: "failed" diff --git a/packages/plugin/src/tool.ts b/packages/plugin/src/tool.ts index 3105bf534b..b8a634c796 100644 --- a/packages/plugin/src/tool.ts +++ b/packages/plugin/src/tool.ts @@ -27,7 +27,21 @@ type AskInput = { metadata: { [key: string]: any } } -export type ToolResult = string | { output: string; metadata?: { [key: string]: any } } +export type ToolAttachment = { + type: "file" + mime: string + url: string + filename?: string +} + +export type ToolResult = + | string + | { + title?: string + output: string + metadata?: { [key: string]: any } + attachments?: ToolAttachment[] + } export function tool(input: { description: string diff --git a/packages/plugin/src/tui.ts b/packages/plugin/src/tui.ts index d4c2261b28..354e44abcd 100644 --- a/packages/plugin/src/tui.ts +++ b/packages/plugin/src/tui.ts @@ -226,6 +226,76 @@ export type TuiToast = { duration?: number } +export type TuiAttentionWhen = "always" | "focused" | "blurred" + +export const TuiAttentionSoundNames = ["default", "question", "permission", "error", "done", "subagent_done"] as const +export type TuiAttentionSoundName = (typeof TuiAttentionSoundNames)[number] + +export type TuiAttentionSound = + | boolean + | { + name?: TuiAttentionSoundName + volume?: number + when?: TuiAttentionWhen + } + +export type TuiAttentionNotification = + | boolean + | { + when?: TuiAttentionWhen + } + +export type TuiAttentionSoundPack = { + id: string + name?: string + sounds: Partial> +} + +export type TuiAttentionSoundPackInfo = { + id: string + name?: string + active: boolean + builtin: boolean +} + +export type TuiAttentionSoundboardActivateOptions = { + persist?: boolean +} + +export type TuiAttentionSoundboard = { + registerPack(pack: TuiAttentionSoundPack): () => void + activate(id: string, options?: TuiAttentionSoundboardActivateOptions): boolean + current(): string + list(): ReadonlyArray +} + +export type TuiAttentionNotifyInput = { + title?: string + message: string + notification?: TuiAttentionNotification + sound?: TuiAttentionSound +} + +export type TuiAttentionNotifySkipReason = + | "attention_disabled" + | "empty_message" + | "blurred" + | "focused" + | "focus_unknown" + | "renderer_destroyed" + +export type TuiAttentionNotifyResult = { + ok: boolean + notification: boolean + sound: boolean + skipped?: TuiAttentionNotifySkipReason +} + +export type TuiAttention = { + notify(input: TuiAttentionNotifyInput): Promise + soundboard: TuiAttentionSoundboard +} + export type TuiThemeCurrent = { readonly primary: RGBA readonly secondary: RGBA @@ -333,9 +403,19 @@ type TuiBindingLookupView = { omit: (name: string, commands: readonly string[]) => Binding[] } +type TuiAttentionConfigView = { + enabled: boolean + notifications: boolean + sound: boolean + volume: number + sound_pack: string + sounds: Partial> +} + type TuiConfigView = Pick & NonNullable & { leader_timeout: number + attention: TuiAttentionConfigView plugin_enabled?: Record keybinds: TuiBindingLookupView } @@ -499,6 +579,7 @@ export type TuiWorkspace = { export type TuiPluginApi = { app: TuiApp + attention: TuiAttention /** * Legacy `api.command` API kept so v1 plugins can initialize. Remove in v2. * diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 8fd2a02b92..5e4fd89061 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -1666,6 +1666,9 @@ export type OAuth = { export type ApiAuth = { type: "api" key: string + metadata?: { + [key: string]: string + } } export type WellKnownAuth = { diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index bf3201a5c0..37b9385743 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -197,6 +197,10 @@ import type { TuiSelectSessionResponses, TuiShowToastResponses, TuiSubmitPromptResponses, + V2ModelListResponses, + V2ProviderGetErrors, + V2ProviderGetResponses, + V2ProviderListResponses, V2SessionCompactResponses, V2SessionContextResponses, V2SessionListErrors, @@ -214,6 +218,7 @@ import type { WorktreeCreateErrors, WorktreeCreateInput, WorktreeCreateResponses, + WorktreeListErrors, WorktreeListResponses, WorktreeRemoveErrors, WorktreeRemoveInput, @@ -1256,7 +1261,7 @@ export class Worktree extends HeyApiClient { }, ], ) - return (options?.client ?? this.client).get({ + return (options?.client ?? this.client).get({ url: "/experimental/worktree", ...options, ...params, @@ -4374,11 +4379,68 @@ export class Session3 extends HeyApiClient { } } +export class Model extends HeyApiClient { + /** + * List v2 models + * + * Retrieve available v2 models ordered by release date. + */ + public list(options?: Options) { + return (options?.client ?? this.client).get({ + url: "/api/model", + ...options, + }) + } +} + +export class Provider2 extends HeyApiClient { + /** + * List v2 providers + * + * Retrieve active v2 AI providers so clients can show provider availability and configuration. + */ + public list(options?: Options) { + return (options?.client ?? this.client).get({ + url: "/api/provider", + ...options, + }) + } + + /** + * Get v2 provider + * + * Retrieve a single v2 AI provider so clients can inspect its availability and endpoint settings. + */ + public get( + parameters: { + providerID: string + }, + options?: Options, + ) { + const params = buildClientParams([parameters], [{ args: [{ in: "path", key: "providerID" }] }]) + return (options?.client ?? this.client).get({ + url: "/api/provider/{providerID}", + ...options, + ...params, + }) + } +} + export class V2 extends HeyApiClient { private _session?: Session3 get session(): Session3 { return (this._session ??= new Session3({ client: this.client })) } + + private _model?: Model + get model(): Model { + return (this._model ??= new Model({ client: this.client })) + } + + private _provider?: Provider2 + get provider(): Provider2 { + return (this._provider ??= new Provider2({ client: this.client })) + } } export class Control extends HeyApiClient { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index f062700b7d..014a5fbabe 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1334,6 +1334,18 @@ export type Model = { read: number write: number } + tiers?: Array<{ + input: number + output: number + cache: { + read: number + write: number + } + tier: { + type: "context" + size: number + } + }> experimentalOver200K?: { input: number output: number @@ -1397,6 +1409,20 @@ export type ToolList = Array export type ToolIds = Array +export type WorktreeError = { + name: + | "WorktreeNotGitError" + | "WorktreeNameGenerationFailedError" + | "WorktreeCreateFailedError" + | "WorktreeStartCommandFailedError" + | "WorktreeRemoveFailedError" + | "WorktreeResetFailedError" + | "WorktreeListFailedError" + data: { + message: string + } +} + export type WorktreeCreateInput = { name?: string /** @@ -1695,6 +1721,21 @@ export type ProviderAuthAuthorization = { instructions: string } +export type ProviderAuthError1 = { + name: + | "BadRequest" + | "ProviderAuthOauthMissing" + | "ProviderAuthOauthCodeMissing" + | "ProviderAuthOauthCallbackFailed" + | "ProviderAuthValidationFailed" + data: { + providerID?: string + field?: string + message?: string + kind?: string + } +} + export type TextPartInput = { id?: string type: "text" @@ -3337,6 +3378,171 @@ export type SessionMessage = | SessionMessageAssistant | SessionMessageCompaction +export type ModelV2Info = { + id: string + apiID: string + providerID: string + family?: string + name: string + endpoint: + | { + type: "unknown" + } + | { + type: "openai/responses" + url: string + websocket?: boolean + } + | { + type: "openai/completions" + url: string + reasoning?: + | { + type: "reasoning_content" + } + | { + type: "reasoning_details" + } + } + | { + type: "anthropic/messages" + url: string + } + | { + type: "aisdk" + package: string + url?: string + } + capabilities: { + tools: boolean + input: Array + output: Array + } + options: { + headers: { + [key: string]: string + } + body: { + [key: string]: unknown + } + aisdk: { + provider: { + [key: string]: unknown + } + request: { + [key: string]: unknown + } + } + variant?: string + } + variants: Array<{ + id: string + headers: { + [key: string]: string + } + body: { + [key: string]: unknown + } + aisdk: { + provider: { + [key: string]: unknown + } + request: { + [key: string]: unknown + } + } + }> + time: { + released: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + } + cost: Array<{ + tier?: { + type: "context" + size: number + } + input: number + output: number + cache: { + read: number + write: number + } + }> + status: "alpha" | "beta" | "deprecated" | "active" + enabled: boolean + limit: { + context: number + input?: number + output: number + } +} + +export type ProviderV2Info = { + id: string + name: string + enabled: + | false + | { + via: "env" + name: string + } + | { + via: "auth" + service: string + } + | { + via: "custom" + data: { + [key: string]: unknown + } + } + env: Array + endpoint: + | { + type: "unknown" + } + | { + type: "openai/responses" + url: string + websocket?: boolean + } + | { + type: "openai/completions" + url: string + reasoning?: + | { + type: "reasoning_content" + } + | { + type: "reasoning_details" + } + } + | { + type: "anthropic/messages" + url: string + } + | { + type: "aisdk" + package: string + url?: string + } + options: { + headers: { + [key: string]: string + } + body: { + [key: string]: unknown + } + aisdk: { + provider: { + [key: string]: unknown + } + request: { + [key: string]: unknown + } + } + } +} + export type EventTuiToastShow1 = { id: string type: "tui.toast.show" @@ -3831,9 +4037,9 @@ export type WorktreeRemoveData = { export type WorktreeRemoveErrors = { /** - * Bad request + * WorktreeError */ - 400: BadRequestError + 400: WorktreeError } export type WorktreeRemoveError = WorktreeRemoveErrors[keyof WorktreeRemoveErrors] @@ -3857,6 +4063,15 @@ export type WorktreeListData = { url: "/experimental/worktree" } +export type WorktreeListErrors = { + /** + * WorktreeError + */ + 400: WorktreeError +} + +export type WorktreeListError = WorktreeListErrors[keyof WorktreeListErrors] + export type WorktreeListResponses = { /** * List of worktree directories @@ -3878,9 +4093,9 @@ export type WorktreeCreateData = { export type WorktreeCreateErrors = { /** - * Bad request + * WorktreeError */ - 400: BadRequestError + 400: WorktreeError } export type WorktreeCreateError = WorktreeCreateErrors[keyof WorktreeCreateErrors] @@ -3906,9 +4121,9 @@ export type WorktreeResetData = { export type WorktreeResetErrors = { /** - * Bad request + * WorktreeError */ - 400: BadRequestError + 400: WorktreeError } export type WorktreeResetError = WorktreeResetErrors[keyof WorktreeResetErrors] @@ -5120,9 +5335,9 @@ export type ProviderOauthAuthorizeData = { export type ProviderOauthAuthorizeErrors = { /** - * Bad request + * ProviderAuthError */ - 400: BadRequestError + 400: ProviderAuthError1 } export type ProviderOauthAuthorizeError = ProviderOauthAuthorizeErrors[keyof ProviderOauthAuthorizeErrors] @@ -5156,9 +5371,9 @@ export type ProviderOauthCallbackData = { export type ProviderOauthCallbackErrors = { /** - * Bad request + * ProviderAuthError */ - 400: BadRequestError + 400: ProviderAuthError1 } export type ProviderOauthCallbackError = ProviderOauthCallbackErrors[keyof ProviderOauthCallbackErrors] @@ -5392,7 +5607,7 @@ export type SessionChildrenErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -5426,7 +5641,7 @@ export type SessionTodoErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -5536,7 +5751,7 @@ export type SessionPromptErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -5574,7 +5789,7 @@ export type SessionDeleteMessageErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -5681,10 +5896,6 @@ export type SessionAbortErrors = { * Bad request */ 400: BadRequestError - /** - * Not found - */ - 404: NotFoundError } export type SessionAbortError = SessionAbortErrors[keyof SessionAbortErrors] @@ -5720,7 +5931,7 @@ export type SessionInitErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -5875,7 +6086,7 @@ export type SessionPromptAsyncErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -5924,7 +6135,7 @@ export type SessionCommandErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -5969,7 +6180,7 @@ export type SessionShellErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -6009,7 +6220,7 @@ export type SessionRevertErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -6043,7 +6254,7 @@ export type SessionUnrevertErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -6080,7 +6291,7 @@ export type PermissionRespondErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -6116,7 +6327,7 @@ export type PartDeleteErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -6152,7 +6363,7 @@ export type PartUpdateErrors = { */ 400: BadRequestError /** - * Not found + * NotFoundError */ 404: NotFoundError } @@ -6459,6 +6670,65 @@ export type V2SessionMessagesResponses = { export type V2SessionMessagesResponse2 = V2SessionMessagesResponses[keyof V2SessionMessagesResponses] +export type V2ModelListData = { + body?: never + path?: never + query?: never + url: "/api/model" +} + +export type V2ModelListResponses = { + /** + * Success + */ + 200: Array +} + +export type V2ModelListResponse = V2ModelListResponses[keyof V2ModelListResponses] + +export type V2ProviderListData = { + body?: never + path?: never + query?: never + url: "/api/provider" +} + +export type V2ProviderListResponses = { + /** + * Success + */ + 200: Array +} + +export type V2ProviderListResponse = V2ProviderListResponses[keyof V2ProviderListResponses] + +export type V2ProviderGetData = { + body?: never + path: { + providerID: string + } + query?: never + url: "/api/provider/{providerID}" +} + +export type V2ProviderGetErrors = { + /** + * NotFoundError + */ + 404: NotFoundError +} + +export type V2ProviderGetError = V2ProviderGetErrors[keyof V2ProviderGetErrors] + +export type V2ProviderGetResponses = { + /** + * ProviderV2.Info + */ + 200: ProviderV2Info +} + +export type V2ProviderGetResponse = V2ProviderGetResponses[keyof V2ProviderGetResponses] + export type TuiAppendPromptData = { body?: { text: string diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 7005382f6b..114db9cd74 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -1013,6 +1013,16 @@ } } } + }, + "400": { + "description": "WorktreeError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorktreeError" + } + } + } } }, "description": "List all sandbox worktrees for the current project.", @@ -1057,11 +1067,11 @@ } }, "400": { - "description": "Bad request", + "description": "WorktreeError", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/BadRequestError" + "$ref": "#/components/schemas/WorktreeError" } } } @@ -1119,11 +1129,11 @@ } }, "400": { - "description": "Bad request", + "description": "WorktreeError", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/BadRequestError" + "$ref": "#/components/schemas/WorktreeError" } } } @@ -1183,11 +1193,11 @@ } }, "400": { - "description": "Bad request", + "description": "WorktreeError", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/BadRequestError" + "$ref": "#/components/schemas/WorktreeError" } } } @@ -4207,11 +4217,11 @@ } }, "400": { - "description": "Bad request", + "description": "ProviderAuthError", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/BadRequestError" + "$ref": "#/components/schemas/ProviderAuthError1" } } } @@ -4293,11 +4303,11 @@ } }, "400": { - "description": "Bad request", + "description": "ProviderAuthError", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/BadRequestError" + "$ref": "#/components/schemas/ProviderAuthError1" } } } @@ -4893,7 +4903,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -4970,7 +4980,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -5227,7 +5237,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -5474,7 +5484,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -5635,16 +5645,6 @@ } } } - }, - "404": { - "description": "Not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundError" - } - } - } } }, "description": "Abort an active session and stop any ongoing AI processing or command execution.", @@ -5711,7 +5711,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -6040,7 +6040,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -6195,7 +6195,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -6344,7 +6344,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -6453,7 +6453,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -6547,7 +6547,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -6630,7 +6630,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -6740,7 +6740,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -6828,7 +6828,7 @@ } }, "404": { - "description": "Not found", + "description": "NotFoundError", "content": { "application/json": { "schema": { @@ -7606,6 +7606,112 @@ ] } }, + "/api/model": { + "get": { + "tags": ["v2 models"], + "operationId": "v2.model.list", + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelV2Info" + } + } + } + } + } + }, + "description": "Retrieve available v2 models ordered by release date.", + "summary": "List v2 models", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.model.list({\n ...\n})" + } + ] + } + }, + "/api/provider": { + "get": { + "tags": ["v2 providers"], + "operationId": "v2.provider.list", + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderV2Info" + } + } + } + } + } + }, + "description": "Retrieve active v2 AI providers so clients can show provider availability and configuration.", + "summary": "List v2 providers", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.provider.list({\n ...\n})" + } + ] + } + }, + "/api/provider/{providerID}": { + "get": { + "tags": ["v2 providers"], + "operationId": "v2.provider.get", + "parameters": [ + { + "name": "providerID", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "ProviderV2.Info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderV2Info" + } + } + } + }, + "404": { + "description": "NotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "description": "Retrieve a single v2 AI provider so clients can inspect its availability and endpoint settings.", + "summary": "Get v2 provider", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.provider.get({\n ...\n})" + } + ] + } + }, "/tui/append-prompt": { "post": { "tags": ["tui"], @@ -12630,6 +12736,49 @@ "required": ["read", "write"], "additionalProperties": false }, + "tiers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "cache": { + "type": "object", + "properties": { + "read": { + "type": "number" + }, + "write": { + "type": "number" + } + }, + "required": ["read", "write"], + "additionalProperties": false + }, + "tier": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["context"] + }, + "size": { + "type": "number" + } + }, + "required": ["type", "size"], + "additionalProperties": false + } + }, + "required": ["input", "output", "cache", "tier"], + "additionalProperties": false + } + }, "experimentalOver200K": { "type": "object", "properties": { @@ -12806,6 +12955,35 @@ "type": "string" } }, + "WorktreeError": { + "type": "object", + "properties": { + "name": { + "type": "string", + "enum": [ + "WorktreeNotGitError", + "WorktreeNameGenerationFailedError", + "WorktreeCreateFailedError", + "WorktreeStartCommandFailedError", + "WorktreeRemoveFailedError", + "WorktreeResetFailedError", + "WorktreeListFailedError" + ] + }, + "data": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"], + "additionalProperties": false + } + }, + "required": ["name", "data"], + "additionalProperties": false + }, "WorktreeCreateInput": { "type": "object", "properties": { @@ -13703,6 +13881,41 @@ "required": ["url", "method", "instructions"], "additionalProperties": false }, + "ProviderAuthError1": { + "type": "object", + "properties": { + "name": { + "type": "string", + "enum": [ + "BadRequest", + "ProviderAuthOauthMissing", + "ProviderAuthOauthCodeMissing", + "ProviderAuthOauthCallbackFailed", + "ProviderAuthValidationFailed" + ] + }, + "data": { + "type": "object", + "properties": { + "providerID": { + "type": "string" + }, + "field": { + "type": "string" + }, + "message": { + "type": "string" + }, + "kind": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "required": ["name", "data"], + "additionalProperties": false + }, "TextPartInput": { "type": "object", "properties": { @@ -18884,6 +19097,531 @@ } ] }, + "ModelV2Info": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "apiID": { + "type": "string" + }, + "providerID": { + "type": "string" + }, + "family": { + "type": "string" + }, + "name": { + "type": "string" + }, + "endpoint": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["unknown"] + } + }, + "required": ["type"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["openai/responses"] + }, + "url": { + "type": "string" + }, + "websocket": { + "type": "boolean" + } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["openai/completions"] + }, + "url": { + "type": "string" + }, + "reasoning": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["reasoning_content"] + } + }, + "required": ["type"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["reasoning_details"] + } + }, + "required": ["type"], + "additionalProperties": false + } + ] + } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["anthropic/messages"] + }, + "url": { + "type": "string" + } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["aisdk"] + }, + "package": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": ["type", "package"], + "additionalProperties": false + } + ] + }, + "capabilities": { + "type": "object", + "properties": { + "tools": { + "type": "boolean" + }, + "input": { + "type": "array", + "items": { + "type": "string" + } + }, + "output": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["tools", "input", "output"], + "additionalProperties": false + }, + "options": { + "type": "object", + "properties": { + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "body": { + "type": "object" + }, + "aisdk": { + "type": "object", + "properties": { + "provider": { + "type": "object" + }, + "request": { + "type": "object" + } + }, + "required": ["provider", "request"], + "additionalProperties": false + }, + "variant": { + "type": "string" + } + }, + "required": ["headers", "body", "aisdk"], + "additionalProperties": false + }, + "variants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "body": { + "type": "object" + }, + "aisdk": { + "type": "object", + "properties": { + "provider": { + "type": "object" + }, + "request": { + "type": "object" + } + }, + "required": ["provider", "request"], + "additionalProperties": false + } + }, + "required": ["id", "headers", "body", "aisdk"], + "additionalProperties": false + } + }, + "time": { + "type": "object", + "properties": { + "released": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string", + "enum": ["NaN"] + }, + { + "type": "string", + "enum": ["Infinity"] + }, + { + "type": "string", + "enum": ["-Infinity"] + }, + { + "type": "string", + "enum": ["Infinity", "-Infinity", "NaN"] + } + ] + } + }, + "required": ["released"], + "additionalProperties": false + }, + "cost": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tier": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["context"] + }, + "size": { + "type": "integer" + } + }, + "required": ["type", "size"], + "additionalProperties": false + }, + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "cache": { + "type": "object", + "properties": { + "read": { + "type": "number" + }, + "write": { + "type": "number" + } + }, + "required": ["read", "write"], + "additionalProperties": false + } + }, + "required": ["input", "output", "cache"], + "additionalProperties": false + } + }, + "status": { + "type": "string", + "enum": ["alpha", "beta", "deprecated", "active"] + }, + "enabled": { + "type": "boolean" + }, + "limit": { + "type": "object", + "properties": { + "context": { + "type": "integer" + }, + "input": { + "type": "integer" + }, + "output": { + "type": "integer" + } + }, + "required": ["context", "output"], + "additionalProperties": false + } + }, + "required": [ + "id", + "apiID", + "providerID", + "name", + "endpoint", + "capabilities", + "options", + "variants", + "time", + "cost", + "status", + "enabled", + "limit" + ], + "additionalProperties": false + }, + "ProviderV2Info": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "enabled": { + "anyOf": [ + { + "type": "boolean", + "enum": [false] + }, + { + "type": "object", + "properties": { + "via": { + "type": "string", + "enum": ["env"] + }, + "name": { + "type": "string" + } + }, + "required": ["via", "name"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "via": { + "type": "string", + "enum": ["auth"] + }, + "service": { + "type": "string" + } + }, + "required": ["via", "service"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "via": { + "type": "string", + "enum": ["custom"] + }, + "data": { + "type": "object" + } + }, + "required": ["via", "data"], + "additionalProperties": false + } + ] + }, + "env": { + "type": "array", + "items": { + "type": "string" + } + }, + "endpoint": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["unknown"] + } + }, + "required": ["type"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["openai/responses"] + }, + "url": { + "type": "string" + }, + "websocket": { + "type": "boolean" + } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["openai/completions"] + }, + "url": { + "type": "string" + }, + "reasoning": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["reasoning_content"] + } + }, + "required": ["type"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["reasoning_details"] + } + }, + "required": ["type"], + "additionalProperties": false + } + ] + } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["anthropic/messages"] + }, + "url": { + "type": "string" + } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["aisdk"] + }, + "package": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": ["type", "package"], + "additionalProperties": false + } + ] + }, + "options": { + "type": "object", + "properties": { + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "body": { + "type": "object" + }, + "aisdk": { + "type": "object", + "properties": { + "provider": { + "type": "object" + }, + "request": { + "type": "object" + } + }, + "required": ["provider", "request"], + "additionalProperties": false + } + }, + "required": ["headers", "body", "aisdk"], + "additionalProperties": false + } + }, + "required": ["id", "name", "enabled", "env", "endpoint", "options"], + "additionalProperties": false + }, "EventTuiToastShow1": { "type": "object", "properties": { @@ -19014,6 +19752,14 @@ "name": "v2 messages", "description": "Experimental v2 message routes." }, + { + "name": "v2 models", + "description": "Experimental v2 model routes." + }, + { + "name": "v2 providers", + "description": "Experimental v2 provider routes." + }, { "name": "tui", "description": "Experimental HttpApi TUI routes." diff --git a/packages/storybook/.storybook/mocks/app/context/global-sync.ts b/packages/storybook/.storybook/mocks/app/context/global-sync.ts index 2eb134d37c..92622c04ac 100644 --- a/packages/storybook/.storybook/mocks/app/context/global-sync.ts +++ b/packages/storybook/.storybook/mocks/app/context/global-sync.ts @@ -40,3 +40,16 @@ export function useGlobalSync() { }, } } + +export function useQueryOptions() { + return { + agents: (directory: string) => ({ + queryKey: [directory, "agents"], + queryFn: async () => [], + }), + providers: (directory: string | null) => ({ + queryKey: [directory, "providers"], + queryFn: async () => provider, + }), + } +} diff --git a/packages/ui/src/assets/audio/alert-01.mp3 b/packages/ui/src/assets/audio/alert-01.mp3 new file mode 100644 index 0000000000..45c3f6afdd Binary files /dev/null and b/packages/ui/src/assets/audio/alert-01.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-02.mp3 b/packages/ui/src/assets/audio/alert-02.mp3 new file mode 100644 index 0000000000..2aa5cda6ac Binary files /dev/null and b/packages/ui/src/assets/audio/alert-02.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-03.mp3 b/packages/ui/src/assets/audio/alert-03.mp3 new file mode 100644 index 0000000000..69ce3c0dbb Binary files /dev/null and b/packages/ui/src/assets/audio/alert-03.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-04.mp3 b/packages/ui/src/assets/audio/alert-04.mp3 new file mode 100644 index 0000000000..f4ed652092 Binary files /dev/null and b/packages/ui/src/assets/audio/alert-04.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-05.mp3 b/packages/ui/src/assets/audio/alert-05.mp3 new file mode 100644 index 0000000000..23be6b0f84 Binary files /dev/null and b/packages/ui/src/assets/audio/alert-05.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-06.mp3 b/packages/ui/src/assets/audio/alert-06.mp3 new file mode 100644 index 0000000000..a0ced67c22 Binary files /dev/null and b/packages/ui/src/assets/audio/alert-06.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-07.mp3 b/packages/ui/src/assets/audio/alert-07.mp3 new file mode 100644 index 0000000000..312a419c57 Binary files /dev/null and b/packages/ui/src/assets/audio/alert-07.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-08.mp3 b/packages/ui/src/assets/audio/alert-08.mp3 new file mode 100644 index 0000000000..6474f935ca Binary files /dev/null and b/packages/ui/src/assets/audio/alert-08.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-09.mp3 b/packages/ui/src/assets/audio/alert-09.mp3 new file mode 100644 index 0000000000..c26fb5bf63 Binary files /dev/null and b/packages/ui/src/assets/audio/alert-09.mp3 differ diff --git a/packages/ui/src/assets/audio/alert-10.mp3 b/packages/ui/src/assets/audio/alert-10.mp3 new file mode 100644 index 0000000000..139689fe37 Binary files /dev/null and b/packages/ui/src/assets/audio/alert-10.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-01.mp3 b/packages/ui/src/assets/audio/bip-bop-01.mp3 new file mode 100644 index 0000000000..f518059c54 Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-01.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-02.mp3 b/packages/ui/src/assets/audio/bip-bop-02.mp3 new file mode 100644 index 0000000000..b25f80ada6 Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-02.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-03.mp3 b/packages/ui/src/assets/audio/bip-bop-03.mp3 new file mode 100644 index 0000000000..adc68c91dc Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-03.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-04.mp3 b/packages/ui/src/assets/audio/bip-bop-04.mp3 new file mode 100644 index 0000000000..4ef895b3be Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-04.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-05.mp3 b/packages/ui/src/assets/audio/bip-bop-05.mp3 new file mode 100644 index 0000000000..d6ec2e5a1f Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-05.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-06.mp3 b/packages/ui/src/assets/audio/bip-bop-06.mp3 new file mode 100644 index 0000000000..77f4ca99e6 Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-06.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-07.mp3 b/packages/ui/src/assets/audio/bip-bop-07.mp3 new file mode 100644 index 0000000000..c41f8c5261 Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-07.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-08.mp3 b/packages/ui/src/assets/audio/bip-bop-08.mp3 new file mode 100644 index 0000000000..24af5b0a23 Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-08.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-09.mp3 b/packages/ui/src/assets/audio/bip-bop-09.mp3 new file mode 100644 index 0000000000..8eca42c0eb Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-09.mp3 differ diff --git a/packages/ui/src/assets/audio/bip-bop-10.mp3 b/packages/ui/src/assets/audio/bip-bop-10.mp3 new file mode 100644 index 0000000000..056730a1f1 Binary files /dev/null and b/packages/ui/src/assets/audio/bip-bop-10.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-01.mp3 b/packages/ui/src/assets/audio/nope-01.mp3 new file mode 100644 index 0000000000..3ec93f1ffc Binary files /dev/null and b/packages/ui/src/assets/audio/nope-01.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-02.mp3 b/packages/ui/src/assets/audio/nope-02.mp3 new file mode 100644 index 0000000000..8cdf890a18 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-02.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-03.mp3 b/packages/ui/src/assets/audio/nope-03.mp3 new file mode 100644 index 0000000000..42442317c3 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-03.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-04.mp3 b/packages/ui/src/assets/audio/nope-04.mp3 new file mode 100644 index 0000000000..8ac496a5c4 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-04.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-05.mp3 b/packages/ui/src/assets/audio/nope-05.mp3 new file mode 100644 index 0000000000..087efb6394 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-05.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-06.mp3 b/packages/ui/src/assets/audio/nope-06.mp3 new file mode 100644 index 0000000000..ed22c1cba2 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-06.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-07.mp3 b/packages/ui/src/assets/audio/nope-07.mp3 new file mode 100644 index 0000000000..4b6dd462c8 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-07.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-08.mp3 b/packages/ui/src/assets/audio/nope-08.mp3 new file mode 100644 index 0000000000..e54577e435 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-08.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-09.mp3 b/packages/ui/src/assets/audio/nope-09.mp3 new file mode 100644 index 0000000000..26a4ac806d Binary files /dev/null and b/packages/ui/src/assets/audio/nope-09.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-10.mp3 b/packages/ui/src/assets/audio/nope-10.mp3 new file mode 100644 index 0000000000..0720993519 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-10.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-11.mp3 b/packages/ui/src/assets/audio/nope-11.mp3 new file mode 100644 index 0000000000..483deefd60 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-11.mp3 differ diff --git a/packages/ui/src/assets/audio/nope-12.mp3 b/packages/ui/src/assets/audio/nope-12.mp3 new file mode 100644 index 0000000000..4b62e62c17 Binary files /dev/null and b/packages/ui/src/assets/audio/nope-12.mp3 differ diff --git a/packages/ui/src/assets/audio/staplebops-01.mp3 b/packages/ui/src/assets/audio/staplebops-01.mp3 new file mode 100644 index 0000000000..b3b34a32fe Binary files /dev/null and b/packages/ui/src/assets/audio/staplebops-01.mp3 differ diff --git a/packages/ui/src/assets/audio/staplebops-02.mp3 b/packages/ui/src/assets/audio/staplebops-02.mp3 new file mode 100644 index 0000000000..276429104e Binary files /dev/null and b/packages/ui/src/assets/audio/staplebops-02.mp3 differ diff --git a/packages/ui/src/assets/audio/staplebops-03.mp3 b/packages/ui/src/assets/audio/staplebops-03.mp3 new file mode 100644 index 0000000000..465017e105 Binary files /dev/null and b/packages/ui/src/assets/audio/staplebops-03.mp3 differ diff --git a/packages/ui/src/assets/audio/staplebops-04.mp3 b/packages/ui/src/assets/audio/staplebops-04.mp3 new file mode 100644 index 0000000000..18181770ff Binary files /dev/null and b/packages/ui/src/assets/audio/staplebops-04.mp3 differ diff --git a/packages/ui/src/assets/audio/staplebops-05.mp3 b/packages/ui/src/assets/audio/staplebops-05.mp3 new file mode 100644 index 0000000000..8046720b0c Binary files /dev/null and b/packages/ui/src/assets/audio/staplebops-05.mp3 differ diff --git a/packages/ui/src/assets/audio/staplebops-06.mp3 b/packages/ui/src/assets/audio/staplebops-06.mp3 new file mode 100644 index 0000000000..93a71695a7 Binary files /dev/null and b/packages/ui/src/assets/audio/staplebops-06.mp3 differ diff --git a/packages/ui/src/assets/audio/staplebops-07.mp3 b/packages/ui/src/assets/audio/staplebops-07.mp3 new file mode 100644 index 0000000000..e6be5b5c8a Binary files /dev/null and b/packages/ui/src/assets/audio/staplebops-07.mp3 differ diff --git a/packages/ui/src/assets/audio/yup-01.mp3 b/packages/ui/src/assets/audio/yup-01.mp3 new file mode 100644 index 0000000000..d4c8dcbee5 Binary files /dev/null and b/packages/ui/src/assets/audio/yup-01.mp3 differ diff --git a/packages/ui/src/assets/audio/yup-02.mp3 b/packages/ui/src/assets/audio/yup-02.mp3 new file mode 100644 index 0000000000..09d4dc6c8b Binary files /dev/null and b/packages/ui/src/assets/audio/yup-02.mp3 differ diff --git a/packages/ui/src/assets/audio/yup-03.mp3 b/packages/ui/src/assets/audio/yup-03.mp3 new file mode 100644 index 0000000000..0406e15eda Binary files /dev/null and b/packages/ui/src/assets/audio/yup-03.mp3 differ diff --git a/packages/ui/src/assets/audio/yup-04.mp3 b/packages/ui/src/assets/audio/yup-04.mp3 new file mode 100644 index 0000000000..533ead9136 Binary files /dev/null and b/packages/ui/src/assets/audio/yup-04.mp3 differ diff --git a/packages/ui/src/assets/audio/yup-05.mp3 b/packages/ui/src/assets/audio/yup-05.mp3 new file mode 100644 index 0000000000..ec7c13d005 Binary files /dev/null and b/packages/ui/src/assets/audio/yup-05.mp3 differ diff --git a/packages/ui/src/assets/audio/yup-06.mp3 b/packages/ui/src/assets/audio/yup-06.mp3 new file mode 100644 index 0000000000..f611da8e82 Binary files /dev/null and b/packages/ui/src/assets/audio/yup-06.mp3 differ diff --git a/packages/ui/src/assets/icons/provider/digitalocean.svg b/packages/ui/src/assets/icons/provider/digitalocean.svg new file mode 100644 index 0000000000..5be390b9d3 --- /dev/null +++ b/packages/ui/src/assets/icons/provider/digitalocean.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 2e4d1f53b7..7bd461f110 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -1,4 +1,4 @@ -import { splitProps, type ComponentProps } from "solid-js" +import { onMount, splitProps, type ComponentProps } from "solid-js" const icons = { "align-right": ``, @@ -105,6 +105,41 @@ const icons = { "arrow-undo-down": ``, } +const spriteID = "opencode-icon-sprite" +const symbol = (name: keyof typeof icons) => `opencode-icon-${name}` +let spriteInserted = false + +function viewBox(name: keyof typeof icons) { + return name === "magnifying-glass" || name === "arrow-undo-down" ? "0 0 16 16" : "0 0 20 20" +} + +function ensureSprite() { + if (spriteInserted) return + if (typeof document === "undefined") return + if (document.getElementById(spriteID)) { + spriteInserted = true + return + } + const body = document.body as HTMLElement | null + if (!body) return + + const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg") + svg.id = spriteID + svg.setAttribute("aria-hidden", "true") + svg.setAttribute("width", "0") + svg.setAttribute("height", "0") + svg.style.position = "absolute" + svg.style.overflow = "hidden" + svg.innerHTML = Object.entries(icons) + .map(([name, path]) => { + const key = name as keyof typeof icons + return `${path}` + }) + .join("") + body.insertBefore(svg, body.firstChild) + spriteInserted = true +} + export interface IconProps extends ComponentProps<"svg"> { name: keyof typeof icons size?: "small" | "normal" | "medium" | "large" @@ -112,8 +147,8 @@ export interface IconProps extends ComponentProps<"svg"> { export function Icon(props: IconProps) { const [local, others] = splitProps(props, ["name", "size", "class", "classList"]) - const viewBox = () => - local.name === "magnifying-glass" || local.name === "arrow-undo-down" ? "0 0 16 16" : "0 0 20 20" + onMount(ensureSprite) + return (
+ > + +
) } diff --git a/packages/ui/src/components/provider-icons/sprite.svg b/packages/ui/src/components/provider-icons/sprite.svg index a0214b40d0..68b99ce56d 100644 --- a/packages/ui/src/components/provider-icons/sprite.svg +++ b/packages/ui/src/components/provider-icons/sprite.svg @@ -854,6 +854,20 @@ d="M79.01 5.863c-4.066 0-6.511 2.92-6.511 6.535 0 3.635 2.445 6.555 6.511 6.555 4.046 0 6.512-2.92 6.512-6.555s-2.466-6.535-6.512-6.535Zm0 10.968c-2.633 0-4.172-1.933-4.172-4.433s1.539-4.455 4.172-4.455c2.635 0 4.151 1.933 4.151 4.434 0 2.521-1.516 4.454-4.15 4.454Zm14.393 2.096c3.393 0 5.542-1.808 5.837-4.539h-2.36c-.316 1.555-1.517 2.437-3.477 2.437-2.423 0-3.878-1.68-3.878-4.433 0-2.774 1.476-4.434 3.878-4.434 1.96 0 3.14.862 3.477 2.5h2.36c-.295-2.773-2.444-4.622-5.837-4.622-3.856 0-6.217 2.669-6.217 6.535 0 3.887 2.36 6.556 6.217 6.556Zm-29.543-.311h2.36v-6.01c0-2.752 1.348-4.244 3.772-4.244h2.276V6.177h-2.255c-2.128 0-3.288.735-3.898 2.605l-.443-.063.527-2.542h-2.36v12.439h.02Zm-24.445-7.332c.106-2.101 1.517-3.53 3.793-3.53 2.276 0 3.646 1.345 3.646 3.53h-7.439Zm9.778.4c0-3.426-2.381-5.821-5.943-5.821-3.73 0-6.174 2.563-6.174 6.535 0 4.013 2.423 6.555 6.28 6.555 2.929 0 5.247-1.597 5.669-3.887h-2.36c-.507 1.156-1.666 1.828-3.31 1.828-2.38 0-3.877-1.408-3.94-3.803h9.694c.042-.588.084-.861.084-1.408Zm5.69 6.932h1.939l5.5-12.44h-2.529L56 15.99l-.316.021-3.793-9.833h-2.508l5.5 12.439ZM32.23 12.35c0-.882-.359-1.701-.99-2.437a8.594 8.594 0 0 1-1.497 1.093c.337.42.527.861.527 1.345 0 2.731-5.837 4.811-14.14 4.811-8.281.021-14.118-2.059-14.118-4.811 0-.463.168-.925.505-1.345a8.13 8.13 0 0 1-1.475-1.093c-.632.736-.99 1.555-.99 2.438 0 4.034 7.207 6.534 16.1 6.534 8.87.021 16.078-2.5 16.078-6.535Zm-3.351 1.534c-.906-.462-1.96-.861-3.16-1.197-1.37.378-2.909.672-4.553.861 2.318.294 4.341.778 5.9 1.408.76-.336 1.37-.693 1.813-1.072Zm-17.849-.357a31.902 31.902 0 0 1-4.467-.84c-1.18.336-2.255.735-3.16 1.197.42.379 1.01.715 1.748 1.05 1.539-.63 3.52-1.113 5.88-1.407Zm21.2-6.808c0-4.013-7.207-6.534-16.079-6.534C7.26.185.051 2.706.051 6.719c0 4.035 7.208 6.535 16.1 6.535 8.872.021 16.079-2.5 16.079-6.535Zm-1.94 0c0 2.732-5.836 4.812-14.139 4.812-8.302.021-14.14-2.06-14.14-4.812 0-2.731 5.838-4.811 14.14-4.811 7.86 0 14.14 2.08 14.14 4.811Zm-3.223 2.564c.758-.336 1.37-.694 1.812-1.072-2.95-1.513-7.544-2.353-12.728-2.353s-9.799.84-12.728 2.353c.422.378 1.012.715 1.75 1.05 2.507-1.05 6.363-1.68 10.978-1.68 4.404 0 8.324.651 10.916 1.702ZM1.042 15.628c-.632.736-.99 1.534-.99 2.438 0 4.034 7.207 6.534 16.1 6.534 8.892 0 16.099-2.521 16.099-6.534 0-.883-.359-1.702-.99-2.438-.422.4-.907.757-1.497 1.093.337.42.527.861.527 1.345 0 2.731-5.837 4.811-14.14 4.811-8.302 0-14.14-2.08-14.14-4.811 0-.463.17-.925.506-1.345a10.73 10.73 0 0 1-1.475-1.093Z" >
+ + + + + + ` in your DigitalOcean account. You can rotate or revoke it from the **Model Access Keys** page in the "Manage" section of the DigitalOcean console under Inference. + ::: + +4. Run the `/models` command. Your Inference Routers appear as the format `router:` in the model selection. + + ```txt + /models + ``` + +5. To pick up newly created Inference Routers, re-run `/connect` and select **DigitalOcean** again. + +#### Using a Model Access Key + +If you'd rather paste a key directly: + +1. Head over to the **Manage** page in the Inference section of the [DigitalOcean console](https://cloud.digitalocean.com/) and create a new key. + +2. Run the `/connect` command and select **DigitalOcean**, then **Paste Model Access Key**. + + ```txt + ┌ Enter your DigitalOcean Model Access Key + │ + │ + └ enter + ``` + + :::note + Inference Routers are not auto-discovered with this method. To surface them in the model picker, sign in via OAuth instead. + ::: + +3. Run the `/models` command to select a model. + + ```txt + /models + ``` + +#### Environment Variable + +Alternatively, set your Model Access Key as an environment variable. + +```bash frame="none" +export DIGITALOCEAN_ACCESS_TOKEN=your-model-access-key +``` + +#### Inference Routers + +Inference Routers let you define a routing policy across multiple models — picking the cheapest, fastest, or most appropriate model per request based on the task. After OAuth, OpenCode surfaces each router as `router:` in the model picker. + +Selecting a router model is a drop-in replacement for any other model — OpenCode forwards your request and DigitalOcean picks the underlying model based on your router's policy. Learn more about [Inference Routers](https://docs.digitalocean.com/products/inference/how-to/use-inference-router/) + +--- + ### FrogBot 1. Head over to the [FrogBot dashboard](https://app.frogbot.ai/signup), create an account, and generate an API key. diff --git a/specs/v2/api.html b/specs/v2/api.html new file mode 100644 index 0000000000..147d24f58b --- /dev/null +++ b/specs/v2/api.html @@ -0,0 +1,1161 @@ + + + + + + opencode v2 API + + + +
+
+
+
opencode v2
+

API map

+
+
+

+ A single /api route surface for simple clients and multi-directory frontends. The important + design question is not route nesting; it is where runtime context comes from. +

+
+ Server scoped + Request context + Session pinned +
+
+
+ +
+
+ Everything has one canonical route. Some routes are server-scoped; runtime routes use context; session item + routes use the session. +

+ Server-scoped routes manage the whole server: projects, workspace lifecycle, and auth accounts. Runtime + context is for anything resolved from an active directory, including config, provider capabilities, tools, + files, and VCS. +

+
+
+
+ +
+
+

Context Model

+ + API context resolution + + Non-session routes resolve from request context, session item routes resolve from session storage. + + + + + + + + + Non-session route + /api/file, /api/vcs/status + + + Request context + query params or default runtime + + + Runtime context + directory + workspaceID? + + + Session item route + /api/session/:id/prompt + + + Session row + contains pinned context + + + Runtime context + directory + workspaceID? + +
+ +
+

Request-context calls

+

+ These calls operate against a directory, optionally through a workspace. Simple clients omit context and use + the default runtime. +

+
GET /api/fs/tree?path=.&directory=/repo/app&workspace=ws_123
+
+ +
+

Session-pinned calls

+

+ These calls never take request context. The session is already pinned to the directory and workspace it was + created in. +

+
POST /api/session/ses_123/prompt
+
+// server resolves
+sessionID -> { directory, workspaceID? }
+
+
+ +
+
+

Operation Inventory

+

+ The SDK is the source of truth. HTTP routes are mounts for RPC-style operations. + server operations do not use runtime context. + request operations use request/default runtime context from + directory and workspace query parameters. + session operations use pinned session context and should not accept + context input. +

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperationInputContextHTTP mountPurpose
agent.list{}requestGET /api/agentAvailable agents.
auth.activate{ accountID: AccountID }serverPOST /api/auth/:accountID/activateSet the account as active for its service.
auth.create + { serviceID: ServiceID credential: | { type: "oauth", refresh: string, access: string, expires: + number } | { type: "api", key: string, metadata?: Record<string, string> } description?: + string active?: boolean } + serverPOST /api/authCreate an auth account.
auth.delete{ accountID: AccountID }serverDELETE /api/auth/:accountIDRemove an auth account.
auth.get{ accountID: AccountID }serverGET /api/auth/:accountIDGet one auth account.
auth.list{ serviceID?: ServiceID }serverGET /api/authList saved auth accounts. Response includes active account mapping.
auth.update + { accountID: AccountID description?: string credential?: | { type: "oauth", refresh: string, + access: string, expires: number } | { type: "api", key: string, metadata?: Record<string, + string> } } + serverPATCH /api/auth/:accountIDUpdate account description or credential.
catalog.model.get{ providerID: ProviderID modelID: ModelID }serverGET /api/catalog/model/:providerID/:modelIDGet one catalog model.
catalog.model.list{}serverGET /api/catalog/modelList flattened catalog models.
command.list{}requestGET /api/commandAvailable commands.
config.get{}requestGET /api/configResolved config.
config.update{ config: Config }requestPATCH /api/configUpdate config.
event.subscribe{}requestGET /api/eventServer-sent events for the resolved runtime context.
formatter.status{}requestGET /api/formatterFormatter status.
fs.file{ path: string }requestGET /api/fs/fileRead one file.
fs.grep{ pattern: string include?: string limit?: number }requestPOST /api/fs/grepSearch file contents.
fs.search{ query: string type?: "file" | "directory" limit?: number }requestPOST /api/fs/searchSearch paths by name.
fs.tree{ path: string }requestGET /api/fs/treeBrowse a directory.
lsp.status{}requestGET /api/lspLSP status.
mcp.prompt.list{}requestGET /api/mcp/promptList MCP prompts.
mcp.prompt.render + { server: string name: string arguments?: Record<string, string> } + requestPOST /api/mcp/prompt/renderRender one MCP prompt.
mcp.resource.list{}requestGET /api/mcp/resourceList MCP resources.
mcp.resource.read{ server: string uri: string }requestGET /api/mcp/resource/readRead one MCP resource.
mcp.server.create + { name: string config: | { type: "local", command: string, arguments?: string[], environment?: + Record<string, string> } | { type: "remote", url: string, headers?: Record<string, + string>, oauth?: boolean | object } } + requestPOST /api/mcp/serverAdd an MCP server to runtime config.
mcp.server.list{}requestGET /api/mcp/serverList MCP servers with status and auth state.
mcp.server.oauth.callback{ name: string code: string }requestPOST /api/mcp/server/:name/oauth/callbackComplete MCP OAuth.
mcp.server.oauth.delete{ name: string }requestDELETE /api/mcp/server/:name/oauthRemove MCP OAuth credentials.
mcp.server.oauth.start{ name: string }requestPOST /api/mcp/server/:name/oauthStart MCP OAuth.
permission.list{}requestGET /api/permissionPending permission requests.
permission.reply{ permissionID: PermissionID response: PermissionReply }requestPOST /api/permission/:permissionID/replyReply to a permission request.
project.get{ projectID: ProjectID }serverGET /api/project/:projectIDGet project metadata.
project.list{}serverGET /api/projectList projects known to this server.
project.update + { projectID: ProjectID name?: string icon?: string commands?: Array<{ name: string command: + string }> } + serverPATCH /api/project/:projectIDUpdate project metadata.
provider.list{}requestGET /api/providerProvider inventory for the runtime context.
pty.create{ command?: string cwd?: string shell?: string }requestPOST /api/ptyCreate PTY in the runtime context.
pty.delete{ ptyID: PtyID }requestDELETE /api/pty/:ptyIDDelete PTY.
pty.get{ ptyID: PtyID }requestGET /api/pty/:ptyIDGet PTY info.
pty.list{}requestGET /api/ptyList PTYs for the runtime.
pty.update + { ptyID: PtyID title?: string size?: { columns: number, rows: number } } + requestPATCH /api/pty/:ptyIDUpdate PTY.
question.list{}requestGET /api/questionPending user questions.
question.reject{ questionID: QuestionID }requestPOST /api/question/:questionID/rejectReject a question.
question.reply{ questionID: QuestionID response: QuestionResponse }requestPOST /api/question/:questionID/replyReply to a question.
session.compact{ sessionID: SessionID }sessionPOST /api/session/:sessionID/compactCompact the session conversation.
session.context{ sessionID: SessionID }sessionGET /api/session/:sessionID/contextReturn active context messages after the last compaction.
session.create + { title?: string agent?: string model?: { providerID: ProviderID, modelID: ModelID } permission?: + PermissionRule[] } + requestPOST /api/sessionCreate a session pinned to resolved runtime context.
session.delete{ sessionID: SessionID }sessionDELETE /api/session/:sessionIDDelete a session.
session.diff{ sessionID: SessionID }sessionGET /api/session/:sessionID/diffReturn session diff summary.
session.get{ sessionID: SessionID }sessionGET /api/session/:sessionIDGet one session.
session.list + { limit?: number order?: "asc" | "desc" path?: string roots?: boolean start?: number search?: + string cursor?: string } + requestGET /api/sessionList sessions for the current runtime context by default.
session.message.list + { sessionID: SessionID limit?: number order?: "asc" | "desc" cursor?: string } + sessionGET /api/session/:sessionID/messagePage through session messages.
session.prompt + { sessionID: SessionID prompt: Prompt delivery?: "immediate" | "deferred" } + sessionPOST /api/session/:sessionID/promptCreate a user message and queue the agent loop.
session.todo{ sessionID: SessionID }sessionGET /api/session/:sessionID/todoReturn todos associated with the session.
session.update + { sessionID: SessionID title?: string archived?: number permission?: PermissionRule[] } + sessionPATCH /api/session/:sessionIDUpdate title, archival state, or session metadata.
session.wait{ sessionID: SessionID }sessionPOST /api/session/:sessionID/waitWait until the session is idle.
skill.list{}requestGET /api/skillAvailable skills.
vcs.diff{ format?: "json" | "patch" mode?: "worktree" | "default" }requestGET /api/vcs/diffDiff for the runtime directory.
vcs.get{}requestGET /api/vcsVCS metadata.
vcs.patch{ patch: string }requestPOST /api/vcs/patchApply a patch to the runtime directory.
vcs.status{}requestGET /api/vcs/statusChanged files.
workspace.create + { projectID?: ProjectID name?: string directory?: string type: string metadata?: Record<string, + unknown> } + serverPOST /api/workspaceCreate or register a workspace.
workspace.delete{ workspaceID: WorkspaceID }serverDELETE /api/workspace/:workspaceIDRemove a workspace registration.
workspace.get{ workspaceID: WorkspaceID }serverGET /api/workspace/:workspaceIDGet workspace metadata.
workspace.list{ projectID?: ProjectID }serverGET /api/workspaceList workspaces, optionally filtered by project.
workspace.status{}serverGET /api/workspace/statusConnection/lifecycle status for all workspaces. Needs team discussion.
workspace.sync{}serverPOST /api/workspace/syncSync workspace metadata from adapters. Needs team discussion.
workspace.update + { workspaceID: WorkspaceID name?: string metadata?: Record<string, unknown> archived?: + boolean } + serverPATCH /api/workspace/:workspaceIDUpdate workspace metadata or lifecycle state.
workspace.warp + { workspaceID?: WorkspaceID sessionID: SessionID copyChanges: boolean } + serverPOST /api/workspace/warpMove a session into or out of a workspace. Needs team discussion.
+
+
+ +
+
+

Event Envelope

+

+ Every event uses the same envelope. Resource identity belongs in payload. Runtime identity + belongs in context. +

+
+
type ApiEvent<Payload> = {
+  id: string
+  type: string
+  time: number
+  context: {
+    directory: string
+    workspaceID?: string
+  }
+  payload: Payload
+}
+
{
+  "id": "evt_01",
+  "type": "message.part.delta",
+  "time": 1760000000000,
+  "context": {
+    "directory": "/repo/app",
+    "workspaceID": "ws_123"
+  },
+  "payload": {
+    "sessionID": "ses_123",
+    "messageID": "msg_456",
+    "partID": "part_789",
+    "field": "text",
+    "delta": "hello"
+  }
+}
+
+
+
+ +
+
+

Frontend Sync Store

+

+ A frontend can keep one giant store like the current TUI. Runtime data is partitioned by + contextKey. Durable entities such as sessions and messages are keyed by their own IDs. +

+
type RuntimeContext = {
+  directory: string
+  workspaceID?: string
+}
+
+type ContextKey = string
+type SessionID = string
+type MessageID = string
+
+type SyncStore = {
+  status: "loading" | "partial" | "complete"
+
+  shared: {
+    provider: Provider[]
+    provider_default: Record<string, string>
+    provider_next: ProviderListResponse
+    provider_auth: Record<string, ProviderAuthMethod[]>
+    console_state: ConsoleState
+  }
+
+  contexts: Record<
+    ContextKey,
+    {
+      context: RuntimeContext
+
+      config: Config
+      agent: Agent[]
+      command: Command[]
+      lsp: LspStatus[]
+      formatter: FormatterStatus[]
+      vcs: VcsInfo | undefined
+      mcp: Record<string, McpStatus>
+      mcp_resource: Record<string, McpResource>
+
+      session: SessionID[]
+      session_status: Record<SessionID, SessionStatus>
+    }
+  >
+
+  session: Record<SessionID, Session & { context: RuntimeContext }>
+  session_diff: Record<SessionID, Snapshot.FileDiff[]>
+  todo: Record<SessionID, Todo[]>
+  permission: Record<SessionID, PermissionRequest[]>
+  question: Record<SessionID, QuestionRequest[]>
+
+  message: Record<SessionID, Message[]>
+  part: Record<MessageID, Part[]>
+}
+
+function contextKey(context: RuntimeContext) {
+  return `${context.workspaceID ?? "local"}:${context.directory}`
+}
+
+
+
+ + diff --git a/specs/v2/provider-model.md b/specs/v2/provider-model.md new file mode 100644 index 0000000000..fb4598b58f --- /dev/null +++ b/specs/v2/provider-model.md @@ -0,0 +1,330 @@ +# Provider and Model Catalog + +## Provider Schema + +```ts +export const ID = Schema.String.pipe( + Schema.brand("ProviderV2.ID"), + withStatics((schema) => ({ + opencode: schema.make("opencode"), + anthropic: schema.make("anthropic"), + openai: schema.make("openai"), + google: schema.make("google"), + googleVertex: schema.make("google-vertex"), + githubCopilot: schema.make("github-copilot"), + amazonBedrock: schema.make("amazon-bedrock"), + azure: schema.make("azure"), + openrouter: schema.make("openrouter"), + mistral: schema.make("mistral"), + gitlab: schema.make("gitlab"), + })), +) +export type ID = typeof ID.Type + +const OpenAIResponses = Schema.Struct({ + type: Schema.Literal("openai/responses"), + url: Schema.String, + websocket: Schema.optional(Schema.Boolean), +}) + +const OpenAICompletions = Schema.Struct({ + type: Schema.Literal("openai/completions"), + url: Schema.String, + reasoning: Schema.Union([ + Schema.Struct({ + type: Schema.Literal("reasoning_content"), + }), + Schema.Struct({ + type: Schema.Literal("reasoning_details"), + }), + ]).pipe(Schema.optional), +}) +export type OpenAICompletions = typeof OpenAICompletions.Type + +const AISDK = Schema.Struct({ + type: Schema.Literal("aisdk"), + package: Schema.String, +}) + +const AnthropicMessages = Schema.Struct({ + type: Schema.Literal("anthropic/messages"), + url: Schema.String, +}) + +const UnknownEndpoint = Schema.Struct({ + type: Schema.Literal("unknown"), +}) + +export const Endpoint = Schema.Union([ + UnknownEndpoint, + OpenAIResponses, + OpenAICompletions, + AnthropicMessages, + AISDK, +]).pipe(Schema.toTaggedUnion("type")) +export type Endpoint = typeof Endpoint.Type + +export const Options = Schema.Struct({ + headers: Schema.Record(Schema.String, Schema.String), + body: Schema.Record(Schema.String, Schema.Any), +}) +export type Options = typeof Options.Type + +export class Info extends Schema.Class("ProviderV2.Info")({ + id: ID, + name: Schema.String, + enabled: Schema.Boolean, + env: Schema.String.pipe(Schema.Array), + endpoint: Endpoint, + options: Options, +}) { + static empty(providerID: ID) { + return new Info({ + id: providerID, + name: providerID, + enabled: false, + env: [], + endpoint: { + type: "unknown", + }, + options: { + headers: {}, + body: {}, + }, + }) + } +} + +export class NotFound extends Schema.TaggedErrorClass("ProviderV2.NotFound")("ProviderV2.NotFound", { + providerID: ID, +}) {} +``` + +## Model Schema + +```ts +export const ID = Schema.String.pipe(Schema.brand("ModelV2.ID")) +export type ID = typeof ID.Type + +export const VariantID = Schema.String.pipe(Schema.brand("VariantID")) +export type VariantID = typeof VariantID.Type + +export const Family = Schema.String.pipe(Schema.brand("Family")) +export type Family = typeof Family.Type + +export const Capabilities = Schema.Struct({ + tools: Schema.Boolean, + input: Schema.String.pipe(Schema.Array), + output: Schema.String.pipe(Schema.Array), +}) +export type Capabilities = typeof Capabilities.Type + +export const Variant = Schema.Struct({ + id: VariantID, + ...ProviderV2.Options.fields, +}) +export type Variant = typeof Variant.Type + +export const Cost = Schema.Struct({ + tier: Schema.Struct({ + type: Schema.Literal("context"), + size: Schema.Int, + }).pipe(Schema.optional), + input: Schema.Finite, + output: Schema.Finite, + cache: Schema.Struct({ + read: Schema.Finite, + write: Schema.Finite, + }), +}) +export type Cost = typeof Cost.Type + +export const Limit = Schema.Struct({ + context: Schema.Int, + input: Schema.Int.pipe(Schema.optional), + output: Schema.Int, +}) +export type Limit = typeof Limit.Type + +export const Ref = Schema.Struct({ + id: ID, + providerID: ProviderV2.ID, + variant: VariantID, +}) +export type Ref = typeof Ref.Type + +export class Info extends Schema.Class("ModelV2.Info")({ + id: ID, + providerID: ProviderV2.ID, + family: Family.pipe(Schema.optional), + name: Schema.String, + endpoint: ProviderV2.Endpoint, + options: Schema.Struct({ + ...ProviderV2.Options.fields, + variant: Schema.String.pipe(Schema.optional), + }), + capabilities: Capabilities, + variants: Variant.pipe(Schema.Array), + time: Schema.Struct({ + released: DateTimeUtcFromMillis, + }), + cost: Cost.pipe(Schema.Array), + status: Schema.Literals(["alpha", "beta", "deprecated", "active"]), + limit: Limit, +}) { + static empty(providerID: ProviderV2.ID, modelID: ID) { + return new Info({ + id: modelID, + providerID, + name: modelID, + endpoint: { + type: "unknown", + }, + capabilities: { + tools: false, + input: [], + output: [], + }, + options: { + headers: {}, + body: {}, + }, + variants: [], + time: { + released: DateTime.makeUnsafe(0), + }, + cost: [], + status: "active", + limit: { + context: 0, + output: 0, + }, + }) + } +} +``` + +## Catalog Interface + +```ts +export interface Interface { + readonly provider: { + readonly get: (providerID: ProviderV2.ID) => Effect.Effect> + readonly update: (providerID: ProviderV2.ID, fn: (provider: Draft) => void) => Effect.Effect + readonly remove: (providerID: ProviderV2.ID) => Effect.Effect + readonly all: () => Effect.Effect + readonly available: () => Effect.Effect + } + + readonly model: { + readonly get: (providerID: ProviderV2.ID, modelID: ModelV2.ID) => Effect.Effect> + readonly update: ( + providerID: ProviderV2.ID, + modelID: ModelV2.ID, + fn: (model: Draft) => void, + ) => Effect.Effect + readonly remove: (providerID: ProviderV2.ID, modelID: ModelV2.ID) => Effect.Effect + readonly all: () => Effect.Effect + readonly available: () => Effect.Effect + readonly default: () => Effect.Effect> + readonly small: (providerID: ProviderV2.ID) => Effect.Effect> + } +} +``` + +`ProviderV2.Info.enabled` is stored provider state. Provider plugins set this field after checking env, auth, config, or provider-specific availability. + +`ProviderV2.Endpoint` includes `{ type: "unknown" }`. `CatalogV2.model.get()` and `CatalogV2.model.all()` resolve `unknown` endpoints from the provider before returning models. + +Model storage is nested by provider because model ids are only unique within a provider. + +```ts +type ProviderRecord = { + provider: ProviderV2.Info + models: HashMap.HashMap +} + +let records = HashMap.empty() +``` + +`ModelV2.Info` does not have an `enabled` field. Model availability is derived by `CatalogV2.model.available()` from provider state and model status. + +```ts +const available = provider.enabled && model.status !== "deprecated" +``` + +## Plugin Interface + +```ts +export type Definition = Effect.Effect< + { + readonly order: number + readonly hooks: HookFunctions + }, + never, + R +> + +export interface Interface { + readonly add: (input: { id: ID; definition: Definition }) => Effect.Effect + + readonly remove: (id: ID) => Effect.Effect + + readonly trigger: (name: Name, input: HookInput) => Effect.Effect> +} +``` + +## Plugin Order + +```ts +export const Order = { + modelsDev: 0, + env: 10, + auth: 20, + provider: 30, + config: 40, + discovery: 50, +} as const +``` + +## Built-In Plugins + +```ts +export const ModelsDevPlugin: PluginV2.Definition + +export const EnvPlugin: PluginV2.Definition + +export const AuthPlugin: PluginV2.Definition + +export const ConfigPlugin: PluginV2.Definition + +export const AnthropicPlugin: PluginV2.Definition + +export const OpenRouterPlugin: PluginV2.Definition + +export const AmazonBedrockPlugin: PluginV2.Definition + +export const GoogleVertexPlugin: PluginV2.Definition + +export const GitLabPlugin: PluginV2.Definition + +export const GitLabDiscoveryPlugin: PluginV2.Definition +``` + +## Plugin Hooks + +```ts +export type Hooks = { + init: {} + + "provider.update": { + provider: Draft + cancel: boolean + } + + "model.update": { + model: Draft + cancel: boolean + } +} +``` diff --git a/sst-env.d.ts b/sst-env.d.ts index e75c54d056..b75b4bd6e6 100644 --- a/sst-env.d.ts +++ b/sst-env.d.ts @@ -153,6 +153,10 @@ declare module "sst" { "type": "sst.sst.Linkable" "value": string } + "Stat": { + "type": "sst.cloudflare.Worker" + "url": string + } "Teams": { "type": "sst.cloudflare.SolidStart" "url": string diff --git a/sst.config.ts b/sst.config.ts index 696a6fa768..4bf7cc6a8d 100644 --- a/sst.config.ts +++ b/sst.config.ts @@ -19,10 +19,14 @@ export default $config({ }, async run() { await import("./infra/app.js") - await import("./infra/console.js") + const { stat } = await import("./infra/console.js") await import("./infra/enterprise.js") if ($app.stage === "production" || $app.stage === "vimtor") { await import("./infra/monitoring.js") } + + return { + StatWorkerUrl: stat.url, + } }, })