Merge branch 'dev' of github.com:anomalyco/opencode into dev

This commit is contained in:
Frank
2026-09-28 06:11:28 -04:00
139 changed files with 2044 additions and 1364 deletions
+11 -15
View File
@@ -15,12 +15,15 @@ runs:
with:
node-version: "24"
- name: Get baseline download URL
- name: Get Bun version and baseline download URL
id: bun-url
shell: bash
run: |
if [ "$RUNNER_ARCH" = "X64" ]; then
V=$(node -p "require('./package.json').packageManager.split('@')[1]")
# Bun 1.4.2 includes the patched peer-variant fix in oven-sh/bun#33646.
if [ "$RUNNER_OS" = "Windows" ]; then V=1.4.2; fi
echo "version=$V" >> "$GITHUB_OUTPUT"
if [ "$RUNNER_ARCH" = "X64" ]; then
case "$RUNNER_OS" in
macOS) OS=darwin ;;
Linux) OS=linux ;;
@@ -30,9 +33,10 @@ runs:
fi
- name: Setup Bun
id: setup-bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version-file: ${{ !steps.bun-url.outputs.url && 'package.json' || '' }}
bun-version: ${{ !steps.bun-url.outputs.url && steps.bun-url.outputs.version || '' }}
bun-download-url: ${{ steps.bun-url.outputs.url }}
- name: Get cache directory
@@ -45,24 +49,16 @@ runs:
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.cache.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-version }}-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-version }}-
- name: Install setuptools for distutils compatibility
run: python3 -m pip install setuptools || pip install setuptools || true
shell: bash
- name: Install dependencies
run: |
# Workaround for patched peer variants
# e.g. ./patches/ for standard-openapi
# https://github.com/oven-sh/bun/issues/28147
if [ "$RUNNER_OS" = "Windows" ]; then
bun install --linker hoisted ${{ inputs.install-flags }}
else
bun install ${{ inputs.install-flags }}
fi
run: bun install ${{ inputs.install-flags }}
shell: bash
- name: Save Bun dependencies
@@ -70,4 +66,4 @@ runs:
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.cache.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
key: ${{ runner.os }}-bun-${{ steps.setup-bun.outputs.bun-version }}-${{ hashFiles('**/bun.lock') }}
+2 -2
View File
@@ -54,7 +54,7 @@ jobs:
"webfetch": "deny"
}
run: |
opencode run -m opencode/claude-sonnet-4-6 "A new issue has been created:
opencode run -m opencode/gpt-6-luna --variant high "A new issue has been created:
Issue number: ${{ github.event.issue.number }}
Issue author association: ${{ github.event.issue.author_association }}
@@ -188,7 +188,7 @@ jobs:
"webfetch": "deny"
}
run: |
opencode run -m opencode/claude-sonnet-4-6 "Issue #${{ github.event.issue.number }} was previously flagged as non-compliant and has been edited.
opencode run -m opencode/gpt-6-luna --variant high "Issue #${{ github.event.issue.number }} was previously flagged as non-compliant and has been edited.
Issue author association: ${{ github.event.issue.author_association }}
Lookup this issue with gh issue view ${{ github.event.issue.number }}.
+1 -1
View File
@@ -49,7 +49,7 @@ jobs:
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
run: |
opencode run --agent triage "The following issue was just opened, triage it:
opencode run --agent triage --variant high "The following issue was just opened, triage it:
Title: $ISSUE_TITLE
+1 -1
View File
@@ -1,7 +1,7 @@
---
mode: primary
hidden: true
model: opencode/gpt-5.4-mini
model: opencode/gpt-6-luna
color: "#44BA81"
tools:
"*": false
+1 -1
View File
@@ -1,5 +1,5 @@
---
model: opencode/gpt-5.4
model: opencode/gpt-6-luna
---
Create `UPCOMING_CHANGELOG.md` from the structured changelog input below.
+36 -44
View File
@@ -29,7 +29,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@corvu/drawer": "catalog:",
"@dnd-kit/abstract": "0.5.0",
@@ -96,7 +96,7 @@
},
"packages/cli": {
"name": "@opencode-ai/cli",
"version": "1.18.32",
"version": "1.18.33",
"bin": {
"lildax": "./bin/lildax.cjs",
},
@@ -144,7 +144,7 @@
},
"packages/codemode": {
"name": "@opencode-ai/codemode",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"acorn": "8.15.0",
"effect": "catalog:",
@@ -158,7 +158,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -195,7 +195,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -222,7 +222,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/openai": "3.0.48",
@@ -245,7 +245,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -269,7 +269,7 @@
},
"packages/console/support": {
"name": "@opencode-ai/console-support",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@opencode-ai/console-core": "workspace:*",
@@ -289,7 +289,7 @@
},
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.18.32",
"version": "1.18.33",
"bin": {
"opencode": "./bin/opencode",
},
@@ -352,6 +352,7 @@
"mime-types": "3.0.2",
"minimatch": "10.2.5",
"npm-package-arg": "13.0.2",
"open": "11.0.4",
"semver": "^7.6.3",
"turndown": "7.2.0",
"venice-ai-sdk-provider": "2.1.1",
@@ -383,7 +384,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@zip.js/zip.js": "2.7.62",
"drizzle-orm": "catalog:",
@@ -437,7 +438,7 @@
},
"packages/effect-drizzle-sqlite": {
"name": "@opencode-ai/effect-drizzle-sqlite",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
@@ -451,7 +452,7 @@
},
"packages/effect-sqlite-node": {
"name": "@opencode-ai/effect-sqlite-node",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"effect": "catalog:",
},
@@ -463,7 +464,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@hono/standard-validator": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -495,7 +496,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -511,7 +512,7 @@
},
"packages/http-recorder": {
"name": "@opencode-ai/http-recorder",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@effect/platform-node": "4.0.0-beta.83",
"@effect/platform-node-shared": "4.0.0-beta.83",
@@ -542,7 +543,7 @@
},
"packages/llm": {
"name": "@opencode-ai/llm",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@opencode-ai/schema": "workspace:*",
"@smithy/eventstream-codec": "4.2.14",
@@ -561,7 +562,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.18.32",
"version": "1.18.33",
"bin": {
"opencode": "./bin/opencode",
},
@@ -645,7 +646,6 @@
"mime-types": "3.0.2",
"minimatch": "10.0.3",
"npm-package-arg": "13.0.2",
"open": "10.1.2",
"opencode-gitlab-auth": "2.1.0",
"opencode-poe-auth": "0.0.1",
"opentui-spinner": "catalog:",
@@ -692,7 +692,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@ai-sdk/provider": "3.0.8",
"@opencode-ai/sdk": "workspace:*",
@@ -768,7 +768,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"cross-spawn": "catalog:",
},
@@ -783,7 +783,7 @@
},
"packages/server": {
"name": "@opencode-ai/server",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/protocol": "workspace:*",
@@ -798,7 +798,7 @@
},
"packages/session-ui": {
"name": "@opencode-ai/session-ui",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz",
@@ -838,7 +838,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -851,7 +851,7 @@
},
"packages/stats/app": {
"name": "@opencode-ai/stats-app",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@ibm/plex": "6.4.1",
"@kobalte/core": "catalog:",
@@ -878,7 +878,7 @@
},
"packages/stats/core": {
"name": "@opencode-ai/stats-core",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@aws-sdk/client-athena": "3.933.0",
"@planetscale/database": "1.19.0",
@@ -897,7 +897,7 @@
},
"packages/stats/server": {
"name": "@opencode-ai/stats-server",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@aws-sdk/client-firehose": "3.933.0",
"@effect/platform-node": "catalog:",
@@ -939,7 +939,7 @@
},
"packages/tui": {
"name": "@opencode-ai/tui",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/plugin": "workspace:*",
@@ -952,7 +952,6 @@
"diff": "catalog:",
"effect": "catalog:",
"fuzzysort": "catalog:",
"open": "10.1.2",
"opentui-spinner": "catalog:",
"remeda": "catalog:",
"solid-js": "catalog:",
@@ -966,7 +965,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@kobalte/core": "catalog:",
"@pierre/diffs": "catalog:",
@@ -1017,7 +1016,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -1086,6 +1085,7 @@
"@opentui/solid": "catalog:",
"@types/bun": "catalog:",
"@types/node": "catalog:",
"open": "11.0.4",
},
"catalog": {
"@cloudflare/workers-types": "4.20251008.0",
@@ -3456,7 +3456,7 @@
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"default-browser": ["default-browser@5.5.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="],
"default-browser": ["default-browser@5.5.1", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw=="],
"default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="],
@@ -4592,7 +4592,7 @@
"oniguruma-to-es": ["oniguruma-to-es@4.3.6", "", { "dependencies": { "oniguruma-parser": "^0.12.2", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA=="],
"open": ["open@10.1.2", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^3.1.0" } }, "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw=="],
"open": ["open@11.0.4", "", { "dependencies": { "default-browser": "^5.5.1", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.2.1", "wsl-utils": "^1.0.0" } }, "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg=="],
"openai": ["openai@5.11.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-+AuTc5pVjlnTuA9zvn8rA/k+1RluPIx9AD4eDcnutv6JNwHHZxIhkFy+tmMKCvmMFDQzfA/r1ujvPWB19DQkYg=="],
@@ -4758,7 +4758,7 @@
"postject": ["postject@1.0.0-alpha.6", "", { "dependencies": { "commander": "^9.4.0" }, "bin": { "postject": "dist/cli.js" } }, "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A=="],
"powershell-utils": ["powershell-utils@0.1.0", "", {}, "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A=="],
"powershell-utils": ["powershell-utils@0.2.1", "", {}, "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A=="],
"preact": ["preact@11.0.0-beta.0", "", {}, "sha512-IcODoASASYwJ9kxz7+MJeiJhvLriwSb4y4mHIyxdgaRZp6kPUud7xytrk/6GZw8U3y6EFJaRb5wi9SrEK+8+lg=="],
@@ -5550,7 +5550,7 @@
"ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="],
"wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="],
"wsl-utils": ["wsl-utils@1.0.0", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA=="],
"xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="],
@@ -5928,8 +5928,6 @@
"@hey-api/json-schema-ref-parser/js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
"@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=="],
"@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
@@ -6414,8 +6412,6 @@
"opencode/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
"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=="],
"openid-client/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="],
"openid-client/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
@@ -6488,8 +6484,6 @@
"sst/jose": ["jose@5.2.3", "", {}, "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA=="],
"storybook/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=="],
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
@@ -6560,6 +6554,8 @@
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"wsl-utils/powershell-utils": ["powershell-utils@0.1.0", "", {}, "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A=="],
"yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="],
"yaml-language-server/yaml": ["yaml@2.7.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="],
@@ -7172,8 +7168,6 @@
"motion/framer-motion/motion-utils": ["motion-utils@12.39.0", "", {}, "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ=="],
"opencode-gitlab-auth/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
"opencode/@ai-sdk/cerebras/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.54", "", { "dependencies": { "@ai-sdk/provider": "3.0.12", "@ai-sdk/provider-utils": "4.0.33" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-OyXt0zK8y2/ZIyWlbxTv2r1M7AK227S+Gl4BYOEF42q0wz1n5m4fwR8L4Fy/MQ4Ho6xje47MPsFcRdIqIyP6Rw=="],
"opencode/@ai-sdk/cerebras/@ai-sdk/provider": ["@ai-sdk/provider@3.0.12", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-sj9DWTJ2Ze0WR9qsiOPqoqzNx3OxL6iMxHImbhvoe9qOspekbzxNDMiJ4TIGfYHYh9w4OmBjz3prvqhzTi96+Q=="],
@@ -7200,8 +7194,6 @@
"send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"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=="],
"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=="],
+4 -4
View File
@@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-yKqw4YLXSzPOxPxXVWEK2W11YpwXQtFR1533Z8/s2rI=",
"aarch64-linux": "sha256-xbrn9P8be2XHOVKhH4EM2fiao2kppgJouXcoQSBRfnk=",
"aarch64-darwin": "sha256-bs0ulK/Ny3JWVcGF4CRVr2/RsLAK5bglkrshVmGrBrc=",
"x86_64-darwin": "sha256-s0j5DImmcA/tCP2kNTaYd6QugG+k8WtcDWVt7Yi2cxU="
"x86_64-linux": "sha256-RIzpvDBR6GOfU2vjrtgP3LJ/j+gLxkMnJ9VE5Y65Pfo=",
"aarch64-linux": "sha256-seE7v8AqxWCiyxNARMiLJNB1MZv15OwEf6r21k68xqg=",
"aarch64-darwin": "sha256-rbyK+3qz9bGOxg3HlGW6yh3qeazCaxFcuPfdGbXHsIY=",
"x86_64-darwin": "sha256-chSE5WtSQ+qdbj5vTvGmr4rn9gk8eVp3pVeow4gVqYI="
}
}
+2 -1
View File
@@ -142,7 +142,8 @@
"@opentui/keymap": "catalog:",
"@opentui/solid": "catalog:",
"@types/bun": "catalog:",
"@types/node": "catalog:"
"@types/node": "catalog:",
"open": "11.0.4"
},
"patchedDependencies": {
"@dnd-kit/dom@0.5.0": "patches/@dnd-kit%2Fdom@0.5.0.patch",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.18.32",
"version": "1.18.33",
"description": "",
"type": "module",
"exports": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/cli",
"version": "1.18.32",
"version": "1.18.33",
"type": "module",
"license": "MIT",
"bin": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/codemode",
"version": "1.18.32",
"version": "1.18.33",
"description": "Effect-native confined code execution over schema-described tools",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.18.32",
"version": "1.18.33",
"type": "module",
"license": "MIT",
"scripts": {
@@ -28,14 +28,12 @@ export const goModels = [
id: "deepseek-flash",
name: "DeepSeek V4.1 Flash",
requests: 26000,
baseRequests: 6500,
allowance: 60,
baseAllowance: 15,
bonus: 4,
featured: true,
fresh: true,
},
{ id: "longcat-2.0", name: "LongCat-2.0", requests: 11400, allowance: 60 },
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", requests: 13000, allowance: 30 },
{
id: "mimo-v2.6-flash",
name: "MiMo-V2.6-Flash",
@@ -69,4 +67,13 @@ export const goModels = [
fresh: true,
limitedTime: true,
},
{
id: "longcat-2.5-preview-free",
name: "LongCat 2.5 Preview Free",
requests: Infinity,
allowance: Infinity,
featured: true,
fresh: true,
limitedTime: true,
},
].sort((a, b) => a.requests - b.requests)
@@ -88,9 +88,6 @@ export function LimitsGraph(props: { href: string }) {
<Show when={model.fresh}>
<span data-slot="badge">{i18n.t("go.graph.new")}</span>
</Show>
<Show when={model.bonus}>
<span data-slot="badge">{i18n.t("go.graph.bonus", { count: model.bonus! })}</span>
</Show>
<Show when={model.limitedTime}>
<span data-slot="badge">{i18n.t("go.graph.limitedTime")}</span>
</Show>
@@ -117,16 +114,10 @@ export function LimitsGraph(props: { href: string }) {
<div data-slot="bar" style={{ "--width": `${position(model.requests)}%` }} />
</div>
<div data-slot="requests">
<Show when={model.baseRequests}>
<s>{format().format(model.baseRequests!)}</s>{" "}
</Show>
<bdi>{format().format(model.requests)}</bdi>
</div>
</div>
<div role="cell" data-slot="allowance" data-high={model.allowance >= 60 ? "" : undefined}>
<Show when={model.baseAllowance}>
<s>{currency().format(model.baseAllowance!)}</s>{" "}
</Show>
<bdi>
<Show when={Number.isFinite(model.allowance)} fallback="∞">
<For each={currency().formatToParts(model.allowance)}>
@@ -26,6 +26,7 @@ const checkLoggedIn = query(async () => {
const models = [
{ name: "Space Bunny Free", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention0" },
{ name: "LongCat 2.5 Preview Free", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention0" },
{ name: "Grok 4.7", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention30" },
{ name: "Grok 4.6", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention30" },
{ name: "GPT 6 Luna", training: "go.faq.a5.notUsed", retention: "go.faq.a5.retention30" },
@@ -662,7 +662,7 @@ export function LiteSection(props: { lite: LiteSubscription | undefined }) {
<li>Qwen3.7 Max</li>
<li>Qwen3.7 Plus</li>
<li>Qwen3.6 Plus</li>
<li>DeepSeek V4.1 Flash — {i18n.t("go.graph.bonus", { count: 4 })}</li>
<li>DeepSeek V4.1 Flash</li>
<li>DeepSeek V4 Pro</li>
<li>DeepSeek V4 Flash</li>
<li>DeepSeek V4 Flash Vision Exp</li>
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.18.32",
"version": "1.18.33",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.18.32",
"version": "1.18.33",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.18.32",
"version": "1.18.33",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-support",
"version": "1.18.32",
"version": "1.18.33",
"type": "module",
"license": "MIT",
"scripts": {
+2 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.32",
"version": "1.18.33",
"name": "@opencode-ai/core",
"type": "module",
"license": "MIT",
@@ -119,6 +119,7 @@
"mime-types": "3.0.2",
"minimatch": "10.2.5",
"npm-package-arg": "13.0.2",
"open": "11.0.4",
"semver": "^7.6.3",
"turndown": "7.2.0",
"venice-ai-sdk-provider": "2.1.1",
+8
View File
@@ -0,0 +1,8 @@
import open from "open"
export function openUrl(input: string) {
const url = URL.canParse(input) ? new URL(input) : undefined
if (!url || (url.protocol !== "http:" && url.protocol !== "https:"))
return Promise.reject(new Error(`Only http and https links can be opened in the browser: ${input}`))
return open(url.href)
}
+16
View File
@@ -0,0 +1,16 @@
import { describe, expect, test } from "bun:test"
import { openUrl } from "@opencode-ai/core/open"
describe("openUrl", () => {
test("rejects values that are not URLs", async () => {
await expect(openUrl("not a url")).rejects.toThrow("Only http and https links")
await expect(openUrl("")).rejects.toThrow("Only http and https links")
})
test("rejects non-http schemes", async () => {
await expect(openUrl("file:///etc/hosts")).rejects.toThrow("Only http and https links")
await expect(openUrl("javascript:alert(1)")).rejects.toThrow("Only http and https links")
await expect(openUrl("ms-msdt:/id PCWDiagnostic")).rejects.toThrow("Only http and https links")
await expect(openUrl("\\\\server\\share\\file.html")).rejects.toThrow("Only http and https links")
})
})
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.18.32",
"version": "1.18.33",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.32",
"version": "1.18.33",
"name": "@opencode-ai/effect-drizzle-sqlite",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.32",
"version": "1.18.33",
"name": "@opencode-ai/effect-sqlite-node",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.18.32",
"version": "1.18.33",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.18.32",
"version": "1.18.33",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.32",
"version": "1.18.33",
"name": "@opencode-ai/http-recorder",
"description": "Record and replay Effect HTTP client traffic with deterministic cassettes",
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.32",
"version": "1.18.33",
"name": "@opencode-ai/llm",
"type": "module",
"license": "MIT",
+1 -2
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.32",
"version": "1.18.33",
"name": "opencode",
"type": "module",
"license": "MIT",
@@ -131,7 +131,6 @@
"mime-types": "3.0.2",
"minimatch": "10.0.3",
"npm-package-arg": "13.0.2",
"open": "10.1.2",
"opencode-gitlab-auth": "2.1.0",
"opencode-poe-auth": "0.0.1",
"opentui-spinner": "catalog:",
+2 -2
View File
@@ -5,9 +5,9 @@ import { Account } from "@/account/account"
import { AccountID, OrgID, PollExpired, type PollResult, type AccountError } from "@/account/schema"
import { effectCmd } from "../effect-cmd"
import * as Prompt from "../effect/prompt"
import open from "open"
import { openUrl } from "@opencode-ai/core/open"
const openBrowser = (url: string) => Effect.promise(() => open(url).catch(() => undefined))
const openBrowser = (url: string) => Effect.promise(() => openUrl(url).catch(() => undefined))
const println = (msg: string) => Effect.sync(() => UI.println(msg))
+3 -3
View File
@@ -3,7 +3,7 @@ import { UI } from "../ui"
import { effectCmd } from "../effect-cmd"
import { withNetworkOptions, resolveNetworkOptions } from "../network"
import { Flag } from "@opencode-ai/core/flag/flag"
import open from "open"
import { openUrl } from "@opencode-ai/core/open"
import { networkInterfaces } from "os"
function getNetworkIPs() {
@@ -72,11 +72,11 @@ export const WebCommand = effectCmd({
}
// Open localhost in browser
open(localhostUrl).catch(() => {})
openUrl(localhostUrl).catch(() => {})
} else {
const displayUrl = server.url.toString()
UI.println(UI.Style.TEXT_INFO_BOLD + " Web interface: ", UI.Style.TEXT_NORMAL, displayUrl)
open(displayUrl).catch(() => {})
openUrl(displayUrl).catch(() => {})
}
yield* Effect.never
+7 -4
View File
@@ -1,6 +1,6 @@
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { openUrl } from "@opencode-ai/core/open"
import { Context, Effect, Layer } from "effect"
import open from "open"
export interface Interface {
readonly open: (url: string) => Effect.Effect<void, Error>
@@ -13,7 +13,7 @@ const layer = Layer.succeed(
Service.of({
open: Effect.fn("McpBrowser.open")(function* (url: string) {
const subprocess = yield* Effect.tryPromise({
try: () => open(url),
try: () => openUrl(url),
catch: (error) => (error instanceof Error ? error : new Error(String(error))),
})
yield* Effect.callback<void, Error>((resume) => {
@@ -22,11 +22,14 @@ const layer = Layer.succeed(
clearTimeout(timer)
resume(Effect.fail(error))
})
subprocess.on("exit", (code) => {
const onExit = (code: number | null) => {
if (code === null || code === 0) return
clearTimeout(timer)
resume(Effect.fail(new Error(`Browser open failed with exit code ${code}`)))
})
}
subprocess.on("exit", onExit)
// On Windows and WSL, open() can return only after the launcher has exited.
onExit(subprocess.exitCode)
})
}),
}),
@@ -125,6 +125,10 @@ export class McpOAuthProvider implements OAuthClientProvider {
}
async redirectToAuthorization(authorizationUrl: URL): Promise<void> {
if (authorizationUrl.protocol !== "http:" && authorizationUrl.protocol !== "https:")
throw new Error(
`MCP server "${this.serverUrl}" returned a ${authorizationUrl.protocol} authorization URL; only http and https are supported`,
)
await this.callbacks.onRedirect(authorizationUrl)
}
+2 -2
View File
@@ -3,7 +3,7 @@ import type { Model } from "@opencode-ai/sdk/v2"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { OauthCallbackPage } from "@opencode-ai/core/oauth/page"
import { createServer } from "http"
import open from "open"
import { openUrl } from "@opencode-ai/core/open"
const DO_OAUTH_CLIENT_ID = "b1a6c5158156caac821fd1b30253ca8acb52454a48fa744420e41889cb589f82"
const DO_AUTHORIZE_URL = "https://cloud.digitalocean.com/v1/oauth/authorize"
@@ -279,7 +279,7 @@ export async function DigitalOceanAuthPlugin(input: PluginInput): Promise<Hooks>
const state = generateState()
const callbackPromise = waitForOAuthCallback(state)
const url = buildAuthorizeUrl(state)
await open(url).catch(() => undefined)
await openUrl(url).catch(() => undefined)
return {
url,
instructions:
@@ -3,7 +3,7 @@ import { OAUTH_DUMMY_KEY } from "../auth"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { OauthCallbackPage } from "@opencode-ai/core/oauth/page"
import { createServer } from "http"
import open from "open"
import { openUrl } from "@opencode-ai/core/open"
const OAUTH_CLIENT_ID = "LOCAL_APPLICATION"
const OAUTH_CALLBACK_HOST = "127.0.0.1"
@@ -470,7 +470,7 @@ export async function SnowflakeCortexAuthPlugin(_input: PluginInput): Promise<Ho
const role = (inputs.role || "").trim() || undefined
const url = buildAuthorizeUrl(account, role, state, pkce)
const callbackPromise = waitForOAuthCallback(account, pkce, state)
await open(url).catch(() => undefined)
await openUrl(url).catch(() => undefined)
return {
url,
+60 -38
View File
@@ -91,6 +91,41 @@ function timeoutController(ms: number) {
}
}
// Applies the `headerTimeout`, `chunkTimeout` (SSE idle) and `timeout` provider options at the
// fetch layer, on top of `options.fetch` when a custom fetch is configured.
function timeoutFetch(options: Record<string, any>) {
const customFetch = options["fetch"]
const chunkTimeout = options["chunkTimeout"] ?? 300_000
const headerTimeout = options["headerTimeout"] ?? 300_000
const timeout = options["timeout"]
return async (input: any, init?: BunFetchRequestInit) => {
const fetchFn = customFetch ?? fetch
const opts = init ?? {}
const chunkAbortCtl = typeof chunkTimeout === "number" && chunkTimeout > 0 ? new AbortController() : undefined
const headerTimeoutMs = headerTimeout === false ? undefined : headerTimeout
const headerTimeoutCtl = typeof headerTimeoutMs === "number" ? timeoutController(headerTimeoutMs) : undefined
const signals: AbortSignal[] = []
if (opts.signal) signals.push(opts.signal)
if (chunkAbortCtl) signals.push(chunkAbortCtl.signal)
if (headerTimeoutCtl) signals.push(headerTimeoutCtl.signal)
if (timeout !== undefined && timeout !== null && timeout !== false) signals.push(AbortSignal.timeout(timeout))
const combined = signals.length === 0 ? null : signals.length === 1 ? signals[0] : AbortSignal.any(signals)
if (combined) opts.signal = combined
const res = await fetchFn(input, {
...opts,
// @ts-ignore see here: https://github.com/oven-sh/bun/issues/16682
timeout: false,
}).finally(() => headerTimeoutCtl?.clear())
if (!chunkAbortCtl) return res
return wrapSSE(res, chunkTimeout, chunkAbortCtl)
}
}
function googleVertexAnthropicBaseURL(project: string | undefined, location: string | undefined) {
if (!project) return
if (location !== "eu" && location !== "us") return
@@ -810,7 +845,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
)
}
const { createAiGateway } = yield* Effect.promise(() => import("ai-gateway-provider"))
const { createAiGateway, parseAiGatewayOptions } = yield* Effect.promise(() => import("ai-gateway-provider"))
const { createUnified } = yield* Effect.promise(() => import("ai-gateway-provider/providers/unified"))
const { createOpenAI } = yield* Effect.promise(() => import("ai-gateway-provider/providers/openai"))
const { createAnthropic } = yield* Effect.promise(() => import("ai-gateway-provider/providers/anthropic"))
@@ -835,15 +870,30 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
},
}
const aigateway = createAiGateway({
accountId,
gateway,
apiKey: apiToken,
...(Object.values(opts).some((v) => v !== undefined) ? { options: opts } : {}),
})
return {
autoload: true,
async getModel(_sdk: any, modelID: string, _options?: Record<string, any>) {
async getModel(_sdk: any, modelID: string, options?: Record<string, any>) {
// This loader builds its own clients instead of using the SDK from resolveSDK, so the
// timeout options have to be applied to the requests it makes explicitly.
const gatewayFetch = timeoutFetch(options ?? {})
// ai-gateway-provider's REST path always calls the global fetch. Its binding path hands
// the request to `run`, so send the same request the REST path would (options as
// request-level cf-aig-* headers) through the timeout-aware fetch instead.
const aigateway = createAiGateway({
binding: {
run(body, init) {
const headers = parseAiGatewayOptions(opts)
headers.set("Content-Type", "application/json")
headers.set("cf-aig-authorization", `Bearer ${apiToken}`)
return gatewayFetch(`https://gateway.ai.cloudflare.com/v1/${accountId}/${gateway}`, {
body: JSON.stringify(body),
headers,
method: "POST",
signal: init?.signal,
})
},
},
})
// Model IDs use Unified API format: provider/model (e.g., "anthropic/claude-sonnet-4-5").
// OpenAI and Anthropic ride their native passthrough routes so agents get the Responses
// and Messages APIs; new OpenAI models reject tools+reasoning_effort on chat completions.
@@ -877,6 +927,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
baseURL: `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/v1`,
apiKey: apiToken,
headers: { "cf-aig-gateway-id": gateway },
fetch: gatewayFetch as typeof fetch,
})(modelID)
},
options: {},
@@ -1795,39 +1846,10 @@ const layer = Layer.effect(
const existing = s.sdk.get(key)
if (existing) return existing
const customFetch = options["fetch"]
const chunkTimeout = options["chunkTimeout"] ?? 300_000
const headerTimeout = options["headerTimeout"] ?? 300_000
options["fetch"] = timeoutFetch(options)
delete options["chunkTimeout"]
delete options["headerTimeout"]
options["fetch"] = async (input: any, init?: BunFetchRequestInit) => {
const fetchFn = customFetch ?? fetch
const opts = init ?? {}
const chunkAbortCtl = typeof chunkTimeout === "number" && chunkTimeout > 0 ? new AbortController() : undefined
const headerTimeoutMs = headerTimeout === false ? undefined : headerTimeout
const headerTimeoutCtl = typeof headerTimeoutMs === "number" ? timeoutController(headerTimeoutMs) : undefined
const signals: AbortSignal[] = []
if (opts.signal) signals.push(opts.signal)
if (chunkAbortCtl) signals.push(chunkAbortCtl.signal)
if (headerTimeoutCtl) signals.push(headerTimeoutCtl.signal)
if (options["timeout"] !== undefined && options["timeout"] !== null && options["timeout"] !== false)
signals.push(AbortSignal.timeout(options["timeout"]))
const combined = signals.length === 0 ? null : signals.length === 1 ? signals[0] : AbortSignal.any(signals)
if (combined) opts.signal = combined
const res = await fetchFn(input, {
...opts,
// @ts-ignore see here: https://github.com/oven-sh/bun/issues/16682
timeout: false,
}).finally(() => headerTimeoutCtl?.clear())
if (!chunkAbortCtl) return res
return wrapSSE(res, chunkTimeout, chunkAbortCtl)
}
const bundledLoader = BUNDLED_PROVIDERS[model.api.npm]
if (bundledLoader) {
const factory = await bundledLoader()
@@ -0,0 +1,36 @@
import { expect, mock, test } from "bun:test"
import { spawn } from "node:child_process"
import { once } from "node:events"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Effect } from "effect"
await mock.module("@opencode-ai/core/open", () => ({
openUrl: async (url: string) => {
const code = new URL(url).pathname === "/successful" ? 0 : 23
const subprocess = spawn(process.execPath, ["-e", `process.exit(${code})`], { stdio: "ignore" })
await once(subprocess, "close")
return subprocess
},
}))
const { McpBrowser } = await import("../../src/mcp/browser")
test("reports a browser launcher that exited before openUrl returned", async () => {
const error = await Effect.runPromise(
Effect.gen(function* () {
const browser = yield* McpBrowser.Service
return yield* Effect.flip(browser.open("https://example.com/authorize"))
}).pipe(Effect.provide(LayerNode.compile(McpBrowser.node))),
)
expect(error.message).toBe("Browser open failed with exit code 23")
})
test("accepts a browser launcher that exited successfully before openUrl returned", async () => {
await Effect.runPromise(
Effect.gen(function* () {
const browser = yield* McpBrowser.Service
yield* browser.open("https://example.com/successful")
}).pipe(Effect.provide(LayerNode.compile(McpBrowser.node))),
)
})
@@ -34,6 +34,37 @@ describe("McpOAuthProvider.redirectUrl", () => {
})
})
describe("McpOAuthProvider.redirectToAuthorization", () => {
test("forwards http and https authorization URLs", async () => {
const seen: string[] = []
const provider = new McpOAuthProvider(
"test-server",
"https://mcp.example.com/mcp",
{},
{ onRedirect: (url) => void seen.push(url.href) },
stubAuth,
)
await provider.redirectToAuthorization(new URL("https://auth.example.com/authorize?state=1"))
await provider.redirectToAuthorization(new URL("http://127.0.0.1:8080/authorize"))
expect(seen).toEqual(["https://auth.example.com/authorize?state=1", "http://127.0.0.1:8080/authorize"])
})
test("rejects authorization URLs that are not http or https", async () => {
const seen: string[] = []
const provider = new McpOAuthProvider(
"test-server",
"https://mcp.example.com/mcp",
{},
{ onRedirect: (url) => void seen.push(url.href) },
stubAuth,
)
await expect(provider.redirectToAuthorization(new URL("file:///tmp/authorize"))).rejects.toThrow(
"returned a file: authorization URL",
)
expect(seen).toEqual([])
})
})
describe("McpOAuthProvider.clientMetadata", () => {
test("includes redirect_uris from redirectUrl", () => {
const provider = makeProvider({ callbackPort: 6620 })
@@ -244,6 +244,112 @@ it.live("OpenAI API auth gets default headerTimeout", () =>
}),
)
const gatewayModels = {
"native passthrough": "anthropic/claude-sonnet-4-6",
"REST catalog": "google/gemini-2.5-flash",
}
for (const [route, modelID] of Object.entries(gatewayModels)) {
it.live(`cloudflare-ai-gateway ${route} applies chunkTimeout when the SSE body stalls`, () =>
Effect.gen(function* () {
yield* provideTmpdirInstance(
() =>
Effect.gen(function* () {
const urls = yield* setupGateway(() =>
Promise.resolve(new Response(new ReadableStream(), { headers: { "content-type": "text/event-stream" } })),
)
const provider = yield* Provider.Service
const model = yield* provider.getModel(
ProviderV2.ID.make("cloudflare-ai-gateway"),
ModelV2.ID.make(modelID),
)
const result = streamText({
model: yield* provider.getLanguage(model),
onError() {},
messages: [{ role: "user", content: "hello" }],
})
const error = yield* Effect.promise(() => firstStreamError(result.fullStream))
expect(urls).toHaveLength(1)
expect(error).toBeInstanceOf(ProviderError.ResponseStreamError)
}),
{ config: gatewayConfig({ chunkTimeout: 50 }) },
)
}),
)
}
it.live("cloudflare-ai-gateway applies headerTimeout when response headers do not arrive", () =>
Effect.gen(function* () {
yield* provideTmpdirInstance(
() =>
Effect.gen(function* () {
const urls = yield* setupGateway(
(init) =>
new Promise((_, reject) => init?.signal?.addEventListener("abort", () => reject(init.signal?.reason))),
)
const provider = yield* Provider.Service
const model = yield* provider.getModel(
ProviderV2.ID.make("cloudflare-ai-gateway"),
ModelV2.ID.make(gatewayModels["native passthrough"]),
)
const result = streamText({
model: yield* provider.getLanguage(model),
onError() {},
messages: [{ role: "user", content: "hello" }],
})
const error = yield* Effect.promise(() => firstStreamError(result.fullStream))
expect(urls).toEqual(["https://gateway.ai.cloudflare.com/v1/test-account/test-gateway"])
expect(String(error)).toContain("response headers timed out")
}),
{ config: gatewayConfig({ headerTimeout: 50 }) },
)
}),
)
// Routes the gateway provider's requests to `respond` through the configured custom fetch, which
// the timeout wrapper calls instead of the global fetch. Returns the requested URLs.
function setupGateway(respond: (init?: RequestInit) => Promise<Response>) {
return Effect.gen(function* () {
yield* Env.use.set("CLOUDFLARE_ACCOUNT_ID", "test-account")
yield* Env.use.set("CLOUDFLARE_GATEWAY_ID", "test-gateway")
yield* Env.use.set("CLOUDFLARE_API_TOKEN", "test-token")
const provider = yield* Provider.Service
const configured = yield* provider.getProvider(ProviderV2.ID.make("cloudflare-ai-gateway"))
const urls: string[] = []
configured.options.fetch = (input: string, init?: RequestInit) => {
urls.push(input)
return respond(init)
}
return urls
})
}
function gatewayConfig(options: Record<string, unknown>) {
return {
provider: {
"cloudflare-ai-gateway": {
options,
models: {
// The gateway loader builds its own client; a bundled npm keeps resolveSDK off the network.
[gatewayModels["REST catalog"]]: { name: "Gemini 2.5 Flash", provider: { npm: "@ai-sdk/openai-compatible" } },
},
},
},
}
}
async function firstStreamError(stream: AsyncIterable<{ type: string; error?: unknown }>) {
try {
for await (const part of stream) {
if (part.type === "error") return part.error
}
} catch (error) {
return error
}
}
function providerConfig(url: string, options: Record<string, unknown> = {}) {
const config = testProviderConfig(url)
return {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.18.32",
"version": "1.18.33",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.18.32",
"version": "1.18.33",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/server",
"version": "1.18.32",
"version": "1.18.33",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/session-ui",
"version": "1.18.32",
"version": "1.18.33",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.18.32",
"version": "1.18.33",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-app",
"version": "1.18.32",
"version": "1.18.33",
"private": true,
"type": "module",
"license": "MIT",
+1
View File
@@ -80,6 +80,7 @@ const en = {
"range.2W": "2 Weeks",
"range.1M": "1 Month",
"range.2M": "2 Months",
"chart.weekly": "Weekly",
"chart.daily": "Daily",
"chart.input": "Input",
"chart.output": "Output",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "أسبوعان",
"range.1M": "شهر واحد",
"range.2M": "شهران",
"chart.weekly": "أسبوعي",
"chart.daily": "يومي",
"chart.input": "الإدخال",
"chart.output": "الإخراج",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 semanas",
"range.1M": "1 mês",
"range.2M": "2 meses",
"chart.weekly": "Semanal",
"chart.daily": "Diário",
"chart.input": "Entrada",
"chart.output": "Saída",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 uger",
"range.1M": "1 måned",
"range.2M": "2 måneder",
"chart.weekly": "Ugentligt",
"chart.daily": "Dagligt",
"chart.input": "Input",
"chart.output": "Output",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 Wochen",
"range.1M": "1 Monat",
"range.2M": "2 Monate",
"chart.weekly": "Wöchentlich",
"chart.daily": "Täglich",
"chart.input": "Eingabe",
"chart.output": "Ausgabe",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 semanas",
"range.1M": "1 mes",
"range.2M": "2 meses",
"chart.weekly": "Semanal",
"chart.daily": "Diario",
"chart.input": "Entrada",
"chart.output": "Salida",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 semaines",
"range.1M": "1 mois",
"range.2M": "2 mois",
"chart.weekly": "Hebdomadaire",
"chart.daily": "Quotidien",
"chart.input": "Entrée",
"chart.output": "Sortie",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 settimane",
"range.1M": "1 mese",
"range.2M": "2 mesi",
"chart.weekly": "Settimanale",
"chart.daily": "Giornaliero",
"chart.input": "Input",
"chart.output": "Output",
+1
View File
@@ -63,6 +63,7 @@ export const dict = {
"range.2W": "2週間",
"range.1M": "1か月",
"range.2M": "2か月",
"chart.weekly": "週次",
"chart.daily": "日次",
"chart.input": "入力",
"chart.output": "出力",
+1
View File
@@ -63,6 +63,7 @@ export const dict = {
"range.2W": "2주",
"range.1M": "1개월",
"range.2M": "2개월",
"chart.weekly": "주간",
"chart.daily": "일간",
"chart.input": "입력",
"chart.output": "출력",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 uker",
"range.1M": "1 måned",
"range.2M": "2 måneder",
"chart.weekly": "Ukentlig",
"chart.daily": "Daglig",
"chart.input": "Inndata",
"chart.output": "Utdata",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 tygodnie",
"range.1M": "1 miesiąc",
"range.2M": "2 miesiące",
"chart.weekly": "Tygodniowo",
"chart.daily": "Dziennie",
"chart.input": "Wejście",
"chart.output": "Wyjście",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 недели",
"range.1M": "1 месяц",
"range.2M": "2 месяца",
"chart.weekly": "Еженедельно",
"chart.daily": "Ежедневно",
"chart.input": "Ввод",
"chart.output": "Вывод",
+1
View File
@@ -63,6 +63,7 @@ export const dict = {
"range.2W": "2 สัปดาห์",
"range.1M": "1 เดือน",
"range.2M": "2 เดือน",
"chart.weekly": "รายสัปดาห์",
"chart.daily": "รายวัน",
"chart.input": "อินพุต",
"chart.output": "เอาต์พุต",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 Hafta",
"range.1M": "1 Ay",
"range.2M": "2 Ay",
"chart.weekly": "Haftalık",
"chart.daily": "Günlük",
"chart.input": "Girdi",
"chart.output": "Çıktı",
+1
View File
@@ -61,6 +61,7 @@ export const dict = {
"range.2W": "2 тижні",
"range.1M": "1 місяць",
"range.2M": "2 місяці",
"chart.weekly": "Щотижня",
"chart.daily": "Щоденно",
"chart.input": "Вхід",
"chart.output": "Вихід",
+1
View File
@@ -63,6 +63,7 @@ export const dict = {
"range.2W": "2 周",
"range.1M": "1 个月",
"range.2M": "2 个月",
"chart.weekly": "每周",
"chart.daily": "每日",
"chart.input": "输入",
"chart.output": "输出",
+1
View File
@@ -63,6 +63,7 @@ export const dict = {
"range.2W": "2 週",
"range.1M": "1 個月",
"range.2M": "2 個月",
"chart.weekly": "每週",
"chart.daily": "每日",
"chart.input": "輸入",
"chart.output": "輸出",
+47 -12
View File
@@ -22,6 +22,12 @@ type RadarAxis = {
label: string
description: string
score: (model: ModelCatalogEntry) => number | undefined
capability?: "reasoning" | "toolCall"
}
type RadarScore = {
value: number
fallback?: string
}
type RadarPoint = {
@@ -37,7 +43,7 @@ export function ComparisonRadar(props: ComparisonRadarProps) {
name: model.name,
labName: model.labName,
color: radarColors[index % radarColors.length],
scores: axes().map((axis) => (model.catalog ? axis.score(model.catalog) : undefined)),
scores: axes().map((axis) => resolveRadarScore(axis, model.catalog)),
})),
)
const accessibleDescription = createMemo(() =>
@@ -62,6 +68,9 @@ export function ComparisonRadar(props: ComparisonRadarProps) {
<span>
<strong>{model.name}</strong>
<Show when={model.labName}>{(name) => <small>{name()}</small>}</Show>
<Show when={model.scores.some((score) => score.fallback)}>
<small data-slot="compare-radar-coverage">Hollow points use fallbacks · hover for details</small>
</Show>
</span>
</li>
)}
@@ -89,10 +98,16 @@ export function ComparisonRadar(props: ComparisonRadarProps) {
<polygon data-slot="compare-radar-area" points={radarSeriesPolygon(model.scores)} />
<For each={model.scores}>
{(score, index) => {
const point = () => radarPoint(index(), axes().length, score ?? 0)
const point = () => radarPoint(index(), axes().length, score.value)
return (
<>
<circle data-slot="compare-radar-point" cx={point().x} cy={point().y} r="0.95" />
<circle
data-slot="compare-radar-point"
data-fallback={score.fallback ? "true" : undefined}
cx={point().x}
cy={point().y}
r="0.95"
/>
<circle
data-slot="compare-radar-point-hit"
cx={point().x}
@@ -138,6 +153,13 @@ export function ComparisonRadar(props: ComparisonRadarProps) {
>
<strong>{axes()[activeAxis() ?? 0]?.label}</strong>
<p>{axes()[activeAxis() ?? 0]?.description}</p>
<For each={series()}>
{(model) => (
<p>
{model.name}: {formatRadarScore(model.scores[activeAxis() ?? 0])}
</p>
)}
</For>
</div>
</Show>
</div>
@@ -166,7 +188,7 @@ export function ComparisonRadar(props: ComparisonRadarProps) {
)
}
function buildRadarAxes(catalogModels: readonly ModelCatalogEntry[]): RadarAxis[] {
export function buildRadarAxes(catalogModels: readonly ModelCatalogEntry[]): RadarAxis[] {
const benchmarks = benchmarkScoreGroups(catalogModels)
const toolUseBenchmarks = benchmarkScoreGroups(catalogModels, true)
const costs = catalogModels.flatMap((model) => {
@@ -180,9 +202,10 @@ function buildRadarAxes(catalogModels: readonly ModelCatalogEntry[]): RadarAxis[
return [
{
label: "Reasoning",
description: "Ability to solve complex, multi-step problems. Based on reasoning benchmarks when available.",
score: (model) =>
benchmarkPercentile(model, benchmarks, reasoningBenchmarkPattern) ?? (model.reasoning ? 100 : 0),
capability: "reasoning",
description:
"Ability to solve complex, multi-step problems. Benchmarks take priority; reasoning support defaults to 50/100.",
score: (model) => benchmarkPercentile(model, benchmarks, reasoningBenchmarkPattern),
},
{
label: "Coding",
@@ -218,7 +241,8 @@ function buildRadarAxes(catalogModels: readonly ModelCatalogEntry[]): RadarAxis[
},
{
label: "Tool use",
description: "Performance on agent benchmarks including Terminal-Bench, Tau3, and Claw-Eval.",
capability: "toolCall",
description: "Agent benchmark performance. Benchmarks take priority; tool calling support defaults to 50/100.",
score: (model) =>
benchmarkPercentile(model, toolUseBenchmarks, toolUseBenchmarkPattern, {
aggregate: "average",
@@ -324,9 +348,9 @@ function radarPolygonPoints(count: number, score: number) {
.join(" ")
}
function radarSeriesPolygon(scores: (number | undefined)[]) {
function radarSeriesPolygon(scores: RadarScore[]) {
return scores
.map((score, index) => radarPoint(index, scores.length, score ?? 0))
.map((score, index) => radarPoint(index, scores.length, score.value))
.map((point) => `${point.x},${point.y}`)
.join(" ")
}
@@ -355,6 +379,17 @@ function roundRadarCoordinate(value: number) {
return Math.round(value * 1000) / 1000
}
function formatRadarScore(score: number | undefined) {
return score === undefined ? "No data" : `${Math.round(score)}/100`
function formatRadarScore(score: RadarScore) {
return `${Math.round(score.value)}/100${score.fallback ? ` — ${score.fallback}` : ""}`
}
export function resolveRadarScore(axis: RadarAxis, model: ModelCatalogEntry | null): RadarScore {
const score = model ? axis.score(model) : undefined
if (score !== undefined) return { value: score }
const supported = axis.capability ? model?.[axis.capability] : undefined
if (supported === undefined) return { value: 50, fallback: "No data; neutral placeholder" }
const capability = axis.capability === "toolCall" ? "Tool calling" : "Reasoning"
return supported
? { value: 50, fallback: `${capability} supported; no comparable benchmark` }
: { value: 0, fallback: `${capability} not supported` }
}
+24 -6
View File
@@ -1545,6 +1545,25 @@ body {
background: var(--stats-layer-2);
}
[data-page="stats"] [data-slot="leaderboard-period"] {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
margin-top: 24px;
color: var(--stats-muted);
font-size: 13px;
}
[data-page="stats"] [data-slot="leaderboard-period"] [data-component="usage-filter"] button {
width: auto;
padding: 0 8px;
}
[data-page="stats"] [data-slot="leaderboard-period"] + [data-component="leaderboard"] {
margin-top: 12px;
}
[data-page="stats"] [data-component="chart-tooltip"] {
position: absolute;
right: auto;
@@ -6291,8 +6310,7 @@ body {
vector-effect: non-scaling-stroke;
}
[data-page="stats"] [data-slot="compare-radar-area"],
[data-page="stats"] [data-slot="compare-radar-line"] {
[data-page="stats"] [data-slot="compare-radar-area"] {
stroke: currentColor;
stroke-width: 1.5px;
stroke-linejoin: round;
@@ -6304,10 +6322,6 @@ body {
fill-opacity: 0.09;
}
[data-page="stats"] [data-slot="compare-radar-line"] {
fill: none;
}
[data-page="stats"] [data-slot="compare-radar-point"] {
fill: currentColor;
stroke: currentColor;
@@ -6315,6 +6329,10 @@ body {
vector-effect: non-scaling-stroke;
}
[data-page="stats"] [data-slot="compare-radar-point"][data-fallback="true"] {
fill: var(--stats-bg);
}
[data-page="stats"] [data-slot="compare-radar-point-hit"] {
fill: transparent;
cursor: pointer;
+45 -12
View File
@@ -65,7 +65,7 @@ type StatsHomePageData = {
updatedAt: string | null
usage: UsagePoint[]
users: UsagePoint[]
leaderboard: LeaderboardEntry[]
leaderboard: { daily: LeaderboardEntry[]; weekly: LeaderboardEntry[] }
market: MarketDay[]
tokenCost: TokenCostEntry[]
cacheRatio: CacheRatioEntry[]
@@ -86,7 +86,7 @@ const getData = query(async () => {
updatedAt: stats.updatedAt,
usage: stats.usage.Go["2M"],
users: stats.users.Go["2M"],
leaderboard: stats.leaderboard.Go["2M"],
leaderboard: { daily: stats.leaderboard.Go["1D"], weekly: stats.leaderboard.Go["1W"] },
market: stats.market["2M"],
tokenCost: priceTokenCostFromCatalog(stats.tokenCost.Go, catalog),
cacheRatio: stats.cacheRatio.Go,
@@ -162,7 +162,7 @@ export default function StatsHome() {
<MarketShareSection data={stats().market} />
<GeoBreakdownSection data={stats().country} />
<ComparisonCardsSection
pairs={homeComparisonPairs(stats().leaderboard, stats().catalogLabs)}
pairs={homeComparisonPairs(stats().leaderboard.weekly, stats().catalogLabs)}
title="Model Comparisons"
description="Popular model pairs from the leaderboard."
variant="featured"
@@ -376,11 +376,13 @@ function formatUpdatedAtLabel(value: { date: string; time: string }) {
function TopModelsSection(props: {
data: UsagePoint[]
leaderboard: LeaderboardEntry[]
leaderboard: StatsHomePageData["leaderboard"]
catalogLabs: readonly string[]
}) {
const i18n = useI18n()
const [activeModel, setActiveModel] = createSignal<string>()
const [period, setPeriod] = createSignal<"weekly" | "daily">("weekly")
const leaderboard = createMemo(() => props.leaderboard[period()])
return (
<section id="top-models" data-section="top-models">
@@ -397,14 +399,41 @@ function TopModelsSection(props: {
>
<TopModelsChart data={props.data} range="2M" activeModel={activeModel()} onActiveModelChange={setActiveModel} />
</Show>
<div data-slot="leaderboard-period" role="group" aria-label={i18n.t("nav.leaderboard")}>
<div data-component="usage-filter" data-variant="range">
<button
type="button"
data-active={period() === "weekly" ? "true" : undefined}
aria-pressed={period() === "weekly"}
onClick={() => {
setPeriod("weekly")
setActiveModel(undefined)
}}
>
{i18n.t("chart.weekly")}
</button>
<button
type="button"
data-active={period() === "daily" ? "true" : undefined}
aria-pressed={period() === "daily"}
onClick={() => {
setPeriod("daily")
setActiveModel(undefined)
}}
>
{i18n.t("chart.daily")}
</button>
</div>
</div>
<Show
when={props.leaderboard.length > 0}
when={leaderboard().length > 0}
fallback={
<EmptyState title={i18n.t("home.noLeaderboardTitle")} description={i18n.t("home.noLeaderboardDescription")} />
}
>
<Leaderboard
data={props.leaderboard}
data={leaderboard()}
showChange={period() === "weekly"}
activeModel={activeModel()}
onActiveModelChange={setActiveModel}
catalogLabs={props.catalogLabs}
@@ -819,6 +848,7 @@ function formatUsers(value: number) {
function Leaderboard(props: {
data: LeaderboardEntry[]
showChange: boolean
activeModel: string | undefined
onActiveModelChange: (model: string | undefined) => void
catalogLabs: readonly string[]
@@ -833,6 +863,7 @@ function Leaderboard(props: {
{(entry) => (
<LeaderboardCard
entry={entry}
showChange={props.showChange}
size="featured"
active={props.activeModel === entry.model}
onActiveModelChange={props.onActiveModelChange}
@@ -847,6 +878,7 @@ function Leaderboard(props: {
{(entry) => (
<LeaderboardCard
entry={entry}
showChange={props.showChange}
size="compact"
active={props.activeModel === entry.model}
onActiveModelChange={props.onActiveModelChange}
@@ -860,6 +892,7 @@ function Leaderboard(props: {
{(entry) => (
<LeaderboardCard
entry={entry}
showChange={props.showChange}
size="featured"
active={props.activeModel === entry.model}
onActiveModelChange={props.onActiveModelChange}
@@ -874,6 +907,7 @@ function Leaderboard(props: {
function LeaderboardCard(props: {
entry: LeaderboardEntry
showChange: boolean
size: "featured" | "compact"
active: boolean
onActiveModelChange: (model: string | undefined) => void
@@ -882,6 +916,7 @@ function LeaderboardCard(props: {
const i18n = useI18n()
const language = useLanguage()
const hasProvider = () => isKnownCatalogLab(props.entry.provider, props.catalogLabs)
const icon = () => (hasProvider() ? getProviderIconId(props.entry.author) : "synthetic")
return (
<a
data-component="leader-card"
@@ -900,13 +935,9 @@ function LeaderboardCard(props: {
onClick={() => props.onActiveModelChange(props.entry.model)}
>
<span data-slot="rank">{String(props.entry.rank).padStart(2, "0")}</span>
<Show when={hasProvider()}>
<ProviderIcon data-slot="leader-watermark" aria-hidden="true" id={getProviderIconId(props.entry.author)} />
</Show>
<ProviderIcon data-slot="leader-watermark" aria-hidden="true" id={icon()} />
<div data-slot="leader-body">
<Show when={hasProvider()}>
<ProviderIcon data-slot="leader-avatar" aria-hidden="true" id={getProviderIconId(props.entry.author)} />
</Show>
<ProviderIcon data-slot="leader-avatar" aria-hidden="true" id={icon()} />
<div data-slot="leader-copy">
<div>
<strong>{props.entry.model}</strong>
@@ -916,6 +947,7 @@ function LeaderboardCard(props: {
<Show when={hasProvider()} fallback={<span />}>
<span>{props.entry.author}</span>
</Show>
<Show when={props.showChange || props.entry.change === null}>
<span
data-slot="delta"
data-new={props.entry.change === null ? "true" : undefined}
@@ -923,6 +955,7 @@ function LeaderboardCard(props: {
>
{formatChange(props.entry.change, i18n)}
</span>
</Show>
</div>
</div>
</div>
+27 -6
View File
@@ -25,8 +25,8 @@ export type ModelCatalogEntry = {
limit?: { context?: number; output?: number }
modalities: { input: string[]; output: string[] }
openWeights: boolean
reasoning: boolean
toolCall: boolean
reasoning?: boolean
toolCall?: boolean
attachment: boolean
temperature: boolean
cost?: ModelCatalogCost
@@ -54,6 +54,7 @@ export type ModelCatalogLab = {
export type ModelCatalog = {
models: ModelCatalogEntry[]
aliases?: ModelCatalogEntry[]
labs: ModelCatalogLab[]
}
@@ -80,7 +81,8 @@ export function findModelCatalogEntry(catalog: ModelCatalog, model: string, lab?
return (
catalog.models.find((entry) => entry.id.toLowerCase() === normalizedId) ??
catalog.models.find((entry) => (lab ? entry.lab === catalogLabSlug(lab) : true) && entry.slug === leaf) ??
catalog.models.find((entry) => entry.slug === leaf)
catalog.models.find((entry) => entry.slug === leaf) ??
catalog.aliases?.find((entry) => (lab ? entry.lab === catalogLabSlug(lab) : true) && entry.slug === leaf)
)
}
@@ -133,7 +135,7 @@ export function catalogSlug(value: string) {
.replace(/-{2,}/g, "-")
}
function buildModelCatalog(payload: unknown, pricingPayload?: unknown, labPayload?: unknown): ModelCatalog {
export function buildModelCatalog(payload: unknown, pricingPayload?: unknown, labPayload?: unknown): ModelCatalog {
const costs = readCatalogCosts(pricingPayload)
const labDescriptions = readCatalogLabDescriptions(payload, pricingPayload, labPayload)
const models = readCatalogModels(payload)
@@ -149,6 +151,25 @@ function buildModelCatalog(payload: unknown, pricingPayload?: unknown, labPayloa
.toSorted((a, b) => a.lab.localeCompare(b.lab) || displayDateTime(b.releaseDate) - displayDateTime(a.releaseDate))
return {
models,
// Contributor is a serving tier of these Muse models, with its own pricing.
// Keep aliases out of the model population used to normalize benchmark scores.
aliases: ["meta/muse-spark-1.2", "meta/muse-spark-1.3"].flatMap((id) => {
const model = models.find((entry) => entry.id === id)
if (!model) return []
const alias = `${id}-contributor`
return [
{
...model,
id: alias,
slug: `${model.slug}-contributor`,
name: `${model.name} Contributor`,
cost:
costs.get(catalogIdKey(alias)) ??
costs.get(`${model.lab}/${model.slug}-contributor`) ??
costs.get(`${model.slug}-contributor`),
},
]
}),
labs: Object.values(
models.reduce<Record<string, ModelCatalogLab>>((result, model) => {
result[model.lab] = {
@@ -184,8 +205,8 @@ function readModelCatalogEntry(value: unknown): ModelCatalogEntry[] {
limit: readCatalogLimit(value.limit),
modalities: readCatalogModalities(value.modalities),
openWeights: booleanValue(value.open_weights),
reasoning: booleanValue(value.reasoning),
toolCall: booleanValue(value.tool_call),
reasoning: typeof value.reasoning === "boolean" ? value.reasoning : undefined,
toolCall: typeof value.tool_call === "boolean" ? value.tool_call : undefined,
attachment: booleanValue(value.attachment),
temperature: booleanValue(value.temperature),
cost: readCatalogCost(value.cost),
@@ -0,0 +1,74 @@
import { describe, expect, test } from "bun:test"
import { buildRadarAxes, resolveRadarScore } from "../src/routes/compare-radar"
import type { ModelCatalogEntry } from "../src/routes/model-catalog"
const model: ModelCatalogEntry = {
id: "meta/muse-spark-1.3",
lab: "meta",
slug: "muse-spark-1-3",
name: "Muse Spark 1.3",
modalities: { input: ["text", "image"], output: ["text"] },
reasoning: true,
toolCall: true,
openWeights: false,
attachment: true,
temperature: true,
weights: [],
benchmarks: [],
}
function scores(entry: ModelCatalogEntry | null, catalog = [model]) {
return Object.fromEntries(buildRadarAxes(catalog).map((axis) => [axis.label, resolveRadarScore(axis, entry)]))
}
describe("radar capability fallbacks", () => {
test("supported capabilities have visible baselines without benchmarks", () => {
const result = scores(model)
expect(result["Tool use"]).toEqual({ value: 50, fallback: "Tool calling supported; no comparable benchmark" })
expect(result.Reasoning).toEqual({ value: 50, fallback: "Reasoning supported; no comparable benchmark" })
expect(result.Coding).toEqual({ value: 50, fallback: "No data; neutral placeholder" })
})
test("explicitly unsupported capabilities remain zero", () => {
const result = scores({ ...model, reasoning: false, toolCall: false })
expect(result["Tool use"]).toEqual({ value: 0, fallback: "Tool calling not supported" })
expect(result.Reasoning).toEqual({ value: 0, fallback: "Reasoning not supported" })
})
test("unknown capabilities and unmatched models use neutral placeholders", () => {
const result = scores({ ...model, reasoning: undefined, toolCall: undefined })
expect(result["Tool use"]).toEqual({ value: 50, fallback: "No data; neutral placeholder" })
expect(result.Reasoning).toEqual({ value: 50, fallback: "No data; neutral placeholder" })
expect(Object.values(scores(null))).toEqual(Array(6).fill({ value: 50, fallback: "No data; neutral placeholder" }))
})
test("measured benchmark percentiles override fallbacks, including zero", () => {
const low = {
...model,
benchmarks: [
{ name: "Tau3", score: 20 },
{ name: "GPQA", score: 40 },
],
}
const high = {
...model,
id: "other/model",
benchmarks: [
{ name: "Tau3", score: 80 },
{ name: "GPQA", score: 90 },
],
}
expect(scores(low, [low, high])["Tool use"]).toEqual({ value: 0 })
expect(scores(low, [low, high]).Reasoning).toEqual({ value: 0 })
expect(scores(high, [low, high])["Tool use"]).toEqual({ value: 100 })
expect(scores(high, [low, high]).Reasoning).toEqual({ value: 100 })
})
test("a benchmark without comparison peers retains the capability baseline", () => {
const entry = { ...model, benchmarks: [{ name: "Tau3", score: 90 }] }
expect(scores(entry, [entry])["Tool use"]).toEqual({
value: 50,
fallback: "Tool calling supported; no comparable benchmark",
})
})
})
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-core",
"version": "1.18.32",
"version": "1.18.33",
"private": true,
"type": "module",
"license": "MIT",
+5 -1
View File
@@ -207,7 +207,11 @@ export class GeoStatRepo extends Context.Service<GeoStatRepo, GeoStatRepo.Servic
inArray(geoStat.dataset, scope.datasets),
inArray(geoStat.client, scope.clients),
inArray(geoStat.source, scope.sources),
or(inArray(geoStat.provider, RETIRED_STAT_PROVIDERS), inArray(geoStat.model, RETIRED_STAT_MODELS)),
or(
inArray(geoStat.provider, RETIRED_STAT_PROVIDERS),
inArray(geoStat.model, RETIRED_STAT_MODELS),
and(eq(geoStat.provider, "unknown"), eq(geoStat.model, "hy4-preview")),
),
),
),
catch: (cause) => DatabaseError.make({ cause }),
+41 -1
View File
@@ -1,10 +1,50 @@
import { describe, expect, test } from "bun:test"
import type { ModelStatMetric } from "./model"
import type { RetentionMetricRow } from "./home"
process.env.SST_RESOURCE_App = JSON.stringify({ name: "opencode", stage: "test" })
process.env.SST_RESOURCE_StatsDatabase = JSON.stringify({ url: "mysql://localhost/stats" })
const { buildRetentionEntries } = await import("./home")
const { buildRetentionEntries, buildStatsHomeData } = await import("./home")
test("daily rankings use the latest day while weekly rankings retain seven days and their previous-period change", () => {
const rows = Array.from({ length: 14 }, (_, index) =>
[
{ model: "model-a", totalTokens: index === 13 ? 3_000_000_000 : 1_000_000_000 },
{ model: "model-b", totalTokens: index === 13 ? 2_000_000_000 : 4_000_000_000 },
].map(
(item) =>
({
periodKey: `2026-09-${String(index + 1).padStart(2, "0")}`,
updatedAt: new Date(Date.UTC(2026, 8, index + 1)),
tier: "Go",
provider: "test",
model: item.model,
sessions: 1,
uniqueUsers: 1,
inputTokens: item.totalTokens,
outputTokens: 0,
reasoningTokens: 0,
cacheReadTokens: 0,
totalTokens: item.totalTokens,
inputCostMicrocents: 0,
outputCostMicrocents: 0,
totalCostMicrocents: 0,
}) satisfies ModelStatMetric,
),
).flat()
const rankings = buildStatsHomeData(rows, [], []).leaderboard.Go
expect(rankings["1D"].map((item) => [item.model, item.tokens, item.change])).toEqual([
["model-a", 3, 200],
["model-b", 2, -50],
])
expect(rankings["1W"].map((item) => [item.model, item.tokens])).toEqual([
["model-b", 26],
["model-a", 9],
])
expect(rankings["2M"]).toEqual(rankings["1W"])
})
describe("retention aggregates", () => {
test("pools the latest seven weekly cohorts and ranks models above the sample floor", () => {
+4 -2
View File
@@ -378,7 +378,7 @@ export const getStatsModelComparisonData = (
{ provider: secondProvider, model: secondModel },
])
function buildStatsHomeData(
export function buildStatsHomeData(
modelRows: ModelStatMetric[],
countryRows: CountryTotalRow[],
retentionRows: RetentionMetricRow[],
@@ -416,7 +416,9 @@ function buildStatsHomeData(
),
),
leaderboard: createUsageProductRecord((product) =>
createRangeRecord((_range) => buildLeaderboard(normalized, product, getWindow("1W", earliest, latest))),
createRangeRecord((range) =>
buildLeaderboard(normalized, product, getWindow(range === "1D" ? "1D" : "1W", earliest, latest)),
),
),
market: createRangeRecord((range) => buildMarketShare(normalized, "Go", range, getWindow(range, earliest, latest))),
tokenCost: createTokenProductRecord((product) =>
@@ -57,6 +57,17 @@ describe("inference stat normalization", () => {
expect(statProvider("unknown", "", "custom-provider")).toBe("custom-provider")
})
test("attributes hy4 preview traffic to Tencent instead of the unknown provider", () => {
expect(modelAuthor("hy4-preview")).toBe("tencent")
expect(toModelAggregate(aggregate("hy4-preview", "opencode"))).toMatchObject([
{ model: "hy4-preview", provider: "tencent" },
])
expect(toProviderAggregate(aggregate("hy4-preview", "opencode"))).toMatchObject([{ provider: "tencent" }])
expect(toGeoAggregate({ ...aggregate("hy4-preview", "opencode"), country: "US" })).toMatchObject([
{ model: "hy4-preview", provider: "tencent" },
])
})
test("maps oversized model ids to unknown before aggregation", () => {
expect(statModel("x".repeat(256), "")).toBe("x".repeat(256))
expect(statModel("x".repeat(257), "")).toBe("unknown")
@@ -6,6 +6,7 @@ export const MODEL_AUTHOR_RULES = [
{ match: "gpt", author: "openai" },
{ match: "grok", author: "xai" },
{ match: "hy3", author: "tencent" },
{ match: "hy4", author: "tencent" },
{ match: "kimi", author: "moonshot" },
{ match: "mimo", author: "xiaomi" },
{ match: "minimax", author: "minimax" },
+1
View File
@@ -195,6 +195,7 @@ export class ModelStatRepo extends Context.Service<ModelStatRepo, ModelStatRepo.
or(
inArray(modelStat.provider, RETIRED_STAT_PROVIDERS),
inArray(modelStat.model, RETIRED_STAT_MODELS),
and(eq(modelStat.provider, "unknown"), eq(modelStat.model, "hy4-preview")),
),
),
),
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-server",
"version": "1.18.32",
"version": "1.18.33",
"private": true,
"type": "module",
"license": "MIT",
+1 -2
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/tui",
"version": "1.18.32",
"version": "1.18.33",
"private": true,
"type": "module",
"license": "MIT",
@@ -59,7 +59,6 @@
"diff": "catalog:",
"effect": "catalog:",
"fuzzysort": "catalog:",
"open": "10.1.2",
"opentui-spinner": "catalog:",
"remeda": "catalog:",
"strip-ansi": "7.1.2",
+2 -2
View File
@@ -63,7 +63,7 @@ import { isDefaultTitle } from "./util/session"
import { KVProvider, useKV } from "./context/kv"
import * as Model from "./util/model"
import { ArgsProvider, useArgs, type Args } from "./context/args"
import open from "open"
import { openUrl } from "@opencode-ai/core/open"
import { PromptRefProvider, usePromptRef } from "./context/prompt"
import { TuiConfigProvider, useTuiConfig, type TuiConfig } from "./config"
import { createTuiApiAdapters } from "./plugin/adapters"
@@ -821,7 +821,7 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi
name: "docs.open",
title: "Open docs",
run: () => {
open("https://opencode.ai/docs").catch(() => {})
openUrl("https://opencode.ai/docs").catch(() => {})
dialog.clear()
},
category: "System",
@@ -1,5 +1,5 @@
import { RGBA, TextAttributes } from "@opentui/core"
import open from "open"
import { openUrl } from "@opencode-ai/core/open"
import { createSignal } from "solid-js"
import { selectedForeground, useTheme } from "../context/theme"
import { useDialog, type DialogContext } from "../ui/dialog"
@@ -21,7 +21,7 @@ export type DialogRetryActionProps = {
}
function runAction(props: DialogRetryActionProps, dialog: ReturnType<typeof useDialog>) {
if (props.link) open(props.link).catch(() => {})
if (props.link) openUrl(props.link).catch(() => {})
props.onClose?.()
dialog.clear()
}
+2 -2
View File
@@ -1,6 +1,6 @@
import type { JSX } from "solid-js"
import type { RGBA } from "@opentui/core"
import open from "open"
import { openUrl } from "@opencode-ai/core/open"
export interface LinkProps {
href: string
@@ -25,7 +25,7 @@ export function Link(props: LinkProps) {
width={props.width}
wrapMode={props.wrapMode}
onMouseUp={() => {
open(props.href).catch(() => {})
openUrl(props.href).catch(() => {})
}}
>
{displayText}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.18.32",
"version": "1.18.33",
"type": "module",
"license": "MIT",
"repository": {
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.18.32",
"version": "1.18.33",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
@@ -56,7 +56,7 @@ description: مشاريع وتكاملات مبنية باستخدام OpenCode.
| الاسم | الوصف |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
| [kimaki](https://github.com/remorses/kimaki) | بوت Discord للتحكم في جلسات OpenCode، مبني على SDK |
| [kimaki](https://kimaki.dev) | بوت Discord للتحكم في جلسات OpenCode، مبني على SDK |
| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | إضافة Neovim للمطالبات المدركة للمحرر، مبنية على API |
| [portal](https://github.com/hosenur/portal) | واجهة ويب مخصصة للجوال لـ OpenCode عبر Tailscale/VPN |
| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | قالب لبناء إضافات OpenCode |
+12 -5
View File
@@ -81,6 +81,7 @@ OpenCode Go هو اشتراك منخفض التكلفة بقيمة **$10/شهر
- **Hy4 preview**
- **Hy3**
- **Space Bunny Free** (لفترة محدودة)
- **LongCat 2.5 Preview Free** (لفترة محدودة)
قد تتغير قائمة النماذج مع استمرارنا في اختبار نماذج جديدة وإضافتها.
@@ -142,7 +143,7 @@ OpenCode Go هو اشتراك منخفض التكلفة بقيمة **$10/شهر
أسعار tokens مُدرجة لكل 1M tokens.
| النموذج | الإدخال | الإخراج | القراءة المخزنة | الكتابة المخزنة | الحد الشهري |
| --------------------------------------- | ------- | ------- | --------------- | --------------- | ----------------------------------------------------------- |
| --------------------------------------- | ------- | ------- | --------------- | --------------- | ---------------------------------------------- |
| GLM-5.3-Flash | $0.15 | $0.50 | $0.03 | - | **$60** |
| GLM-5.3 | $1.40 | $4.40 | $0.26 | - | **$15** |
| GLM-5.2 | $1.40 | $4.40 | $0.26 | - | **$60** |
@@ -167,8 +168,8 @@ OpenCode Go هو اشتراك منخفض التكلفة بقيمة **$10/شهر
| Qwen3.7 Plus (> 256K tokens) | $1.20 | $4.80 | $0.12 | $1.50 | **$60** |
| Qwen3.6 Plus (≤ 256K tokens) | $0.50 | $3.00 | $0.05 | $0.625 | **$60** |
| Qwen3.6 Plus (> 256K tokens) | $2.00 | $6.00 | $0.20 | $2.50 | **$60** |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | ~~$15~~ **$60**<br /><small>4x · ينتهي في 27 سبتمبر</small> |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | ~~$15~~ **$60**<br /><small>4x · ينتهي في 27 سبتمبر</small> |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$60** |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | **$60** |
| DeepSeek V4 Pro (Off-Peak) | $0.66 | $1.98 | $0.022 | - | **$15** |
| DeepSeek V4 Pro (Peak) | $1.32 | $3.96 | $0.044 | - | **$15** |
| DeepSeek V4 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$30** |
@@ -178,6 +179,7 @@ OpenCode Go هو اشتراك منخفض التكلفة بقيمة **$10/شهر
| Hy4 preview | $0.834 | $2.501 | $0.042 | - | **$30** |
| Hy3 | $0.14 | $0.58 | $0.035 | - | **$60** |
| Space Bunny Free | Free | Free | Free | - | **غير محدود**<br /><small>لفترة محدودة</small> |
| LongCat 2.5 Preview Free | Free | Free | Free | - | **غير محدود**<br /><small>لفترة محدودة</small> |
| Grok 4.7 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
| Grok 4.7 (> 200K tokens) | $4.00 | $12.00 | $1.00 | - | **$15** |
| Grok 4.6 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
@@ -189,6 +191,8 @@ OpenCode Go هو اشتراك منخفض التكلفة بقيمة **$10/شهر
**Space Bunny Free:** مجاني لفترة محدودة.
**LongCat 2.5 Preview Free:** مجاني لفترة محدودة.
**DeepSeek V4.1 Flash / V4 Pro / V4 Flash / V4 Flash Vision Exp:** ساعات Peak هي 01:00-04:00 و06:00-10:00 UTC من الاثنين إلى الجمعة؛ وجميع الساعات الأخرى، بما في ذلك عطلات نهاية الأسبوع، Off-Peak. [اعرف المزيد](https://api-docs.deepseek.com/quick_start/pricing/).
**DeepSeek V4 Flash Vision Exp:** يتم تحويل الصور إلى رموز بناءً على أبعادها، وتُحتسب كرموز إدخال إلى جانب رموز النص. [اعرف المزيد](https://api-docs.deepseek.com/quick_start/pricing/).
@@ -198,7 +202,7 @@ OpenCode Go هو اشتراك منخفض التكلفة بقيمة **$10/شهر
يوضح الجدول أدناه عددًا تقديريًا للطلبات استنادًا إلى أنماط استخدام Go المعتادة:
| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر |
| --------------------------------------------------------------- | ------------------------- | -------------------------- | --------------------------- |
| ---------------------------- | ------------------- | ------------------ | ---------------- |
| GLM-5.3-Flash | 6,320 | 15,790 | 31,580 |
| GLM-5.3 | 220 | 540 | 1,080 |
| GLM-5.2 | 880 | 2,150 | 4,300 |
@@ -220,13 +224,14 @@ OpenCode Go هو اشتراك منخفض التكلفة بقيمة **$10/شهر
| Qwen3.7 Max | 170 | 420 | 840 |
| Qwen3.7 Plus | 4,300 | 10,800 | 21,600 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| DeepSeek V4.1 Flash<br /><small>4x · ينتهي في 27 سبتمبر</small> | ~~6,500~~<br />**26,000** | ~~16,250~~<br />**65,000** | ~~32,500~~<br />**130,000** |
| DeepSeek V4.1 Flash | 26,000 | 65,000 | 130,000 |
| DeepSeek V4 Pro | 1,050 | 2,600 | 5,200 |
| DeepSeek V4 Flash | 13,000 | 32,500 | 65,000 |
| DeepSeek V4 Flash Vision Exp | 6,500 | 16,250 | 32,500 |
| Hy4 preview | 1,350 | 3,380 | 6,770 |
| Hy3 | 4,300 | 10,750 | 21,500 |
| Space Bunny Free | غير محدود | غير محدود | غير محدود |
| LongCat 2.5 Preview Free | غير محدود | غير محدود | غير محدود |
| Grok 4.7 | 169 | 423 | 845 |
| Grok 4.6 | 169 | 423 | 845 |
| GPT 6 Luna | 4,230 | 10,560 | 21,130 |
@@ -329,6 +334,7 @@ OpenCode Go هو اشتراك منخفض التكلفة بقيمة **$10/شهر
| Hy4 preview | hy4-preview | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
يستخدم [model id](/docs/config/#models) في إعدادات OpenCode لديك التنسيق `opencode-go/<model-id>`. على سبيل المثال، بالنسبة إلى Kimi K3، ستستخدم `opencode-go/kimi-k3` في إعداداتك.
@@ -380,6 +386,7 @@ https://opencode.ai/zen/go/v1/models
| Hy4 preview | غير مستخدَمة | 0 أيام |
| Hy3 | غير مستخدَمة | 0 أيام |
| Space Bunny Free | غير مستخدَمة | 0 أيام |
| LongCat 2.5 Preview Free | غير مستخدَمة | 0 أيام |
- **Grok 4.7/4.6:** تعطّل ZDR ميزات API مهمة تعتمد على البيانات المخزنة، بما في ذلك Responses API ذات الحالة، وFiles and Collections، وBatch API. [اعرف المزيد](https://docs.x.ai/developers/faq/security#what-is-zero-data-retention-zdr).
- **GPT 6 Luna / GPT 5.6 Luna:** تُنشأ سجلات مراقبة إساءة الاستخدام لكل استخدام لميزات API، ويُحتفظ بها لمدة تصل إلى 30 يومًا. [اعرف المزيد](https://developers.openai.com/api/docs/guides/your-data#data-retention-controls-for-abuse-monitoring).
+5
View File
@@ -103,6 +103,7 @@ OpenCode Zen هي بوابة AI تتيح لك الوصول إلى هذه الن
| Grok Build 0.1 | grok-build-0.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.3 | muse-spark-1.3 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.2 | muse-spark-1.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Qwen3.8 Max | qwen3.8-max | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Qwen3.8 Flash | qwen3.8-flash | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Plus | qwen3.7-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
@@ -128,6 +129,7 @@ OpenCode Zen هي بوابة AI تتيح لك الوصول إلى هذه الن
| Jev 1.13 Free | jev-1.13-free | `https://opencode.ai/zen/v1/systemone` | - |
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.6-Flash Free | mimo-v2.6-flash-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5 Free | mimo-v2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Ling 3.0 Flash Fin Free | ling-3.0-flash-fin-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@@ -211,6 +213,7 @@ curl https://opencode.ai/zen/v1/systemone \
| --------------------------------- | ------- | ------- | --------------- | --------------- |
| Big Pickle | Free | Free | Free | - |
| Space Bunny Free | Free | Free | Free | - |
| LongCat 2.5 Preview Free | Free | Free | Free | - |
| MiMo-V2.6-Flash Free | Free | Free | Free | - |
| MiMo-V2.5 Free | Free | Free | Free | - |
| Ling 3.0 Flash Fin Free | Free | Free | Free | - |
@@ -231,6 +234,7 @@ curl https://opencode.ai/zen/v1/systemone \
| Kimi K3 | $3.00 | $15.00 | $0.30 | - |
| Kimi K2.6 | $0.95 | $4.00 | $0.16 | - |
| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - |
| Qwen3.8 Max | $2.00 | $6.00 | $0.25 | $2.50 |
| Qwen3.8 Flash | $0.15 | $0.47 | $0.016 | $0.20 |
| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 |
| Qwen3.7 Plus | $0.40 | $1.60 | $0.04 | $0.50 |
@@ -319,6 +323,7 @@ curl https://opencode.ai/zen/v1/systemone \
- Nemotron 3.5 Lightning Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج.
- Big Pickle نموذج خفي ومتاح مجانا على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج.
- Space Bunny Free نموذج خفي ومتاح مجانا على OpenCode لفترة محدودة. يتبع مزوده سياسة عدم الاحتفاظ بالبيانات ولا يستخدم بياناتك لتدريب النماذج.
- LongCat 2.5 Preview Free متاح مجانا على OpenCode لفترة محدودة. يتبع مزوده سياسة عدم الاحتفاظ بالبيانات ولا يستخدم بياناتك لتدريب النماذج.
- Muse Spark 1.3 Contributor Free متاح على OpenCode لفترة محدودة. يستخدم الفريق هذه الفترة لجمع الملاحظات وتحسين النموذج.
- Jev 1.13 Free متاح على OpenCode لفترة محدودة.
@@ -56,7 +56,7 @@ Također možete pogledati [awesome-opencode](https://github.com/awesome-opencod
| Ime | Opis |
| ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- |
| [kimaki](https://github.com/remorses/kimaki) | Discord bot za kontrolu OpenCode sesija, izgrađen na SDK |
| [kimaki](https://kimaki.dev) | Discord bot za kontrolu OpenCode sesija, izgrađen na SDK |
| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Neovim dodatak za upite svjestan uređivača, izgrađen na API |
| [portal](https://github.com/hosenur/portal) | Mobilni korisnički interfejs za OpenCode preko Tailscale/VPN |
| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Predložak za izgradnju OpenCode dodataka |
+12 -5
View File
@@ -91,6 +91,7 @@ Trenutna lista modela uključuje:
- **Hy4 preview**
- **Hy3**
- **Space Bunny Free** (ograničeno vrijeme)
- **LongCat 2.5 Preview Free** (ograničeno vrijeme)
Lista modela se može mijenjati dok testiramo i dodajemo nove.
@@ -152,7 +153,7 @@ Na primjer, ako model ima mjesečno ograničenje od $60, možete potrošiti do:
Cijene tokena navedene su za 1M tokena.
| Model | Input | Output | Cached Read | Cached Write | Mjesečno ograničenje |
| --------------------------------------- | ------ | ------ | ----------- | ------------ | --------------------------------------------------------- |
| --------------------------------------- | ------ | ------ | ----------- | ------------ | ------------------------------------------------------- |
| GLM-5.3-Flash | $0.15 | $0.50 | $0.03 | - | **$60** |
| GLM-5.3 | $1.40 | $4.40 | $0.26 | - | **$15** |
| GLM-5.2 | $1.40 | $4.40 | $0.26 | - | **$60** |
@@ -177,8 +178,8 @@ Cijene tokena navedene su za 1M tokena.
| Qwen3.7 Plus (> 256K tokens) | $1.20 | $4.80 | $0.12 | $1.50 | **$60** |
| Qwen3.6 Plus (≤ 256K tokens) | $0.50 | $3.00 | $0.05 | $0.625 | **$60** |
| Qwen3.6 Plus (> 256K tokens) | $2.00 | $6.00 | $0.20 | $2.50 | **$60** |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | ~~$15~~ **$60**<br /><small>4x · Do 27. septembra</small> |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | ~~$15~~ **$60**<br /><small>4x · Do 27. septembra</small> |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$60** |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | **$60** |
| DeepSeek V4 Pro (Off-Peak) | $0.66 | $1.98 | $0.022 | - | **$15** |
| DeepSeek V4 Pro (Peak) | $1.32 | $3.96 | $0.044 | - | **$15** |
| DeepSeek V4 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$30** |
@@ -188,6 +189,7 @@ Cijene tokena navedene su za 1M tokena.
| Hy4 preview | $0.834 | $2.501 | $0.042 | - | **$30** |
| Hy3 | $0.14 | $0.58 | $0.035 | - | **$60** |
| Space Bunny Free | Free | Free | Free | - | **Neograničeno**<br /><small>ograničeno vrijeme</small> |
| LongCat 2.5 Preview Free | Free | Free | Free | - | **Neograničeno**<br /><small>ograničeno vrijeme</small> |
| Grok 4.7 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
| Grok 4.7 (> 200K tokens) | $4.00 | $12.00 | $1.00 | - | **$15** |
| Grok 4.6 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
@@ -199,6 +201,8 @@ Cijene tokena navedene su za 1M tokena.
**Space Bunny Free:** Besplatan ograničeno vrijeme.
**LongCat 2.5 Preview Free:** Besplatan ograničeno vrijeme.
**DeepSeek V4.1 Flash / V4 Pro / V4 Flash / V4 Flash Vision Exp:** Peak sati su 01:00-04:00 i 06:00-10:00 UTC od ponedjeljka do petka; svi ostali sati, uključujući vikende, su Off-Peak. [Saznajte više](https://api-docs.deepseek.com/quick_start/pricing/).
**DeepSeek V4 Flash Vision Exp:** Slike se pretvaraju u tokene na osnovu svojih dimenzija i naplaćuju kao ulazni tokeni zajedno s tekstualnim tokenima. [Saznajte više](https://api-docs.deepseek.com/quick_start/pricing/).
@@ -208,7 +212,7 @@ Cijene tokena navedene su za 1M tokena.
Tabela ispod daje procijenjeni broj zahtjeva na osnovu tipičnih obrazaca korištenja Go-a:
| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno |
| ------------------------------------------------------------- | ------------------------- | -------------------------- | --------------------------- |
| ---------------------------- | ------------------ | ----------------- | ----------------- |
| GLM-5.3-Flash | 6,320 | 15,790 | 31,580 |
| GLM-5.3 | 220 | 540 | 1,080 |
| GLM-5.2 | 880 | 2,150 | 4,300 |
@@ -230,13 +234,14 @@ Tabela ispod daje procijenjeni broj zahtjeva na osnovu tipičnih obrazaca koriš
| Qwen3.7 Max | 170 | 420 | 840 |
| Qwen3.7 Plus | 4,300 | 10,800 | 21,600 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| DeepSeek V4.1 Flash<br /><small>4x · Do 27. septembra</small> | ~~6,500~~<br />**26,000** | ~~16,250~~<br />**65,000** | ~~32,500~~<br />**130,000** |
| DeepSeek V4.1 Flash | 26,000 | 65,000 | 130,000 |
| DeepSeek V4 Pro | 1,050 | 2,600 | 5,200 |
| DeepSeek V4 Flash | 13,000 | 32,500 | 65,000 |
| DeepSeek V4 Flash Vision Exp | 6,500 | 16,250 | 32,500 |
| Hy4 preview | 1,350 | 3,380 | 6,770 |
| Hy3 | 4,300 | 10,750 | 21,500 |
| Space Bunny Free | Neograničeno | Neograničeno | Neograničeno |
| LongCat 2.5 Preview Free | Neograničeno | Neograničeno | Neograničeno |
| Grok 4.7 | 169 | 423 | 845 |
| Grok 4.6 | 169 | 423 | 845 |
| GPT 6 Luna | 4,230 | 10,560 | 21,130 |
@@ -341,6 +346,7 @@ Također možete pristupiti Go modelima putem sljedećih API endpointa.
| Hy4 preview | hy4-preview | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
[Model id](/docs/config/#models) u vašoj OpenCode konfiguraciji
koristi format `opencode-go/<model-id>`. Na primjer, za Kimi K3, koristili biste
@@ -394,6 +400,7 @@ https://opencode.ai/zen/go/v1/models
| Hy4 preview | Ne koristi se | 0 dana |
| Hy3 | Ne koristi se | 0 dana |
| Space Bunny Free | Ne koristi se | 0 dana |
| LongCat 2.5 Preview Free | Ne koristi se | 0 dana |
- **Grok 4.7/4.6:** ZDR onemogućava važne API funkcije koje zavise od pohranjenih podataka, uključujući Responses API s očuvanjem stanja, Files and Collections i Batch API. [Saznajte više](https://docs.x.ai/developers/faq/security#what-is-zero-data-retention-zdr).
- **GPT 6 Luna / GPT 5.6 Luna:** Zapisi o nadzoru zloupotrebe generišu se za svako korištenje API funkcija i čuvaju do 30 dana. [Saznajte više](https://developers.openai.com/api/docs/guides/your-data#data-retention-controls-for-abuse-monitoring).
+5
View File
@@ -108,6 +108,7 @@ Našim modelima možete pristupiti i preko sljedećih API endpointa.
| Grok Build 0.1 | grok-build-0.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.3 | muse-spark-1.3 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.2 | muse-spark-1.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Qwen3.8 Max | qwen3.8-max | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Qwen3.8 Flash | qwen3.8-flash | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Plus | qwen3.7-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
@@ -133,6 +134,7 @@ Našim modelima možete pristupiti i preko sljedećih API endpointa.
| Jev 1.13 Free | jev-1.13-free | `https://opencode.ai/zen/v1/systemone` | - |
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.6-Flash Free | mimo-v2.6-flash-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5 Free | mimo-v2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Ling 3.0 Flash Fin Free | ling-3.0-flash-fin-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@@ -218,6 +220,7 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**.
| --------------------------------- | --------- | --------- | ----------- | ------------ |
| Big Pickle | Free | Free | Free | - |
| Space Bunny Free | Free | Free | Free | - |
| LongCat 2.5 Preview Free | Free | Free | Free | - |
| MiMo-V2.6-Flash Free | Free | Free | Free | - |
| MiMo-V2.5 Free | Free | Free | Free | - |
| Ling 3.0 Flash Fin Free | Free | Free | Free | - |
@@ -238,6 +241,7 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**.
| Kimi K3 | $3.00 | $15.00 | $0.30 | - |
| Kimi K2.6 | $0.95 | $4.00 | $0.16 | - |
| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - |
| Qwen3.8 Max | $2.00 | $6.00 | $0.25 | $2.50 |
| Qwen3.8 Flash | $0.15 | $0.47 | $0.016 | $0.20 |
| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 |
| Qwen3.7 Plus | $0.40 | $1.60 | $0.04 | $0.50 |
@@ -326,6 +330,7 @@ Besplatni modeli:
- Nemotron 3.5 Lightning Free je dostupan na OpenCode ograničeno vrijeme. Tim koristi ovo vrijeme da prikupi povratne informacije i poboljša model.
- Big Pickle je stealth model koji je besplatan na OpenCode ograničeno vrijeme. Tim koristi ovo vrijeme da prikupi povratne informacije i poboljša model.
- Space Bunny Free je stealth model koji je besplatan na OpenCode ograničeno vrijeme. Pružalac usluge slijedi politiku nultog zadržavanja i ne koristi vaše podatke za treniranje modela.
- LongCat 2.5 Preview Free je besplatan na OpenCode ograničeno vrijeme. Pružalac usluge slijedi politiku nultog zadržavanja i ne koristi vaše podatke za treniranje modela.
- Muse Spark 1.3 Contributor Free je dostupan na OpenCode ograničeno vrijeme. Tim koristi ovo vrijeme da prikupi povratne informacije i poboljša model.
- Jev 1.13 Free je dostupan na OpenCode ograničeno vrijeme.
@@ -56,7 +56,7 @@ Du kan også tjekke [awesome-opencode](https://github.com/awesome-opencode/aweso
| Navn | Beskrivelse |
| ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| [kimaki](https://github.com/remorses/kimaki) | Discord-bot til at styre OpenCode-sessioner, bygget på SDK |
| [kimaki](https://kimaki.dev) | Discord-bot til at styre OpenCode-sessioner, bygget på SDK |
| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Neovim-plugin til redaktør-bevidste prompter, bygget på API |
| [portal](https://github.com/hosenur/portal) | Mobile-first web UI til OpenCode over Tailscale/VPN |
| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Skabelon til at bygge OpenCode plugins |
+11 -4
View File
@@ -91,6 +91,7 @@ Den nuværende liste over modeller inkluderer:
- **Hy4 preview**
- **Hy3**
- **Space Bunny Free** (i en begrænset periode)
- **LongCat 2.5 Preview Free** (i en begrænset periode)
Listen over modeller kan ændre sig, efterhånden som vi tester og tilføjer nye.
@@ -177,8 +178,8 @@ Tokenpriser er angivet pr. 1M tokens.
| Qwen3.7 Plus (> 256K tokens) | $1.20 | $4.80 | $0.12 | $1.50 | **$60** |
| Qwen3.6 Plus (≤ 256K tokens) | $0.50 | $3.00 | $0.05 | $0.625 | **$60** |
| Qwen3.6 Plus (> 256K tokens) | $2.00 | $6.00 | $0.20 | $2.50 | **$60** |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | ~~$15~~ **$60**<br /><small>4x · Slutter 27. sep.</small> |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | ~~$15~~ **$60**<br /><small>4x · Slutter 27. sep.</small> |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$60** |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | **$60** |
| DeepSeek V4 Pro (Off-Peak) | $0.66 | $1.98 | $0.022 | - | **$15** |
| DeepSeek V4 Pro (Peak) | $1.32 | $3.96 | $0.044 | - | **$15** |
| DeepSeek V4 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$30** |
@@ -188,6 +189,7 @@ Tokenpriser er angivet pr. 1M tokens.
| Hy4 preview | $0.834 | $2.501 | $0.042 | - | **$30** |
| Hy3 | $0.14 | $0.58 | $0.035 | - | **$60** |
| Space Bunny Free | Free | Free | Free | - | **Ubegrænset**<br /><small>i en begrænset periode</small> |
| LongCat 2.5 Preview Free | Free | Free | Free | - | **Ubegrænset**<br /><small>i en begrænset periode</small> |
| Grok 4.7 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
| Grok 4.7 (> 200K tokens) | $4.00 | $12.00 | $1.00 | - | **$15** |
| Grok 4.6 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
@@ -199,6 +201,8 @@ Tokenpriser er angivet pr. 1M tokens.
**Space Bunny Free:** Gratis i en begrænset periode.
**LongCat 2.5 Preview Free:** Gratis i en begrænset periode.
**DeepSeek V4.1 Flash / V4 Pro / V4 Flash / V4 Flash Vision Exp:** Peak-tiderne er 01:00-04:00 og 06:00-10:00 UTC fra mandag til fredag; alle andre tider, herunder weekender, er Off-Peak. [Læs mere](https://api-docs.deepseek.com/quick_start/pricing/).
**DeepSeek V4 Flash Vision Exp:** Billeder konverteres til tokens baseret på deres dimensioner og afregnes som inputtokens sammen med teksttokens. [Læs mere](https://api-docs.deepseek.com/quick_start/pricing/).
@@ -208,7 +212,7 @@ Tokenpriser er angivet pr. 1M tokens.
Tabellen nedenfor viser et estimeret antal anmodninger baseret på typiske Go-forbrugsmønstre:
| Model | anmodninger pr. 5 timer | anmodninger pr. uge | anmodninger pr. måned |
| ------------------------------------------------------------- | ------------------------- | -------------------------- | --------------------------- |
| ---------------------------- | ----------------------- | ------------------- | --------------------- |
| GLM-5.3-Flash | 6,320 | 15,790 | 31,580 |
| GLM-5.3 | 220 | 540 | 1,080 |
| GLM-5.2 | 880 | 2,150 | 4,300 |
@@ -230,13 +234,14 @@ Tabellen nedenfor viser et estimeret antal anmodninger baseret på typiske Go-fo
| Qwen3.7 Max | 170 | 420 | 840 |
| Qwen3.7 Plus | 4,300 | 10,800 | 21,600 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| DeepSeek V4.1 Flash<br /><small>4x · Slutter 27. sep.</small> | ~~6,500~~<br />**26,000** | ~~16,250~~<br />**65,000** | ~~32,500~~<br />**130,000** |
| DeepSeek V4.1 Flash | 26,000 | 65,000 | 130,000 |
| DeepSeek V4 Pro | 1,050 | 2,600 | 5,200 |
| DeepSeek V4 Flash | 13,000 | 32,500 | 65,000 |
| DeepSeek V4 Flash Vision Exp | 6,500 | 16,250 | 32,500 |
| Hy4 preview | 1,350 | 3,380 | 6,770 |
| Hy3 | 4,300 | 10,750 | 21,500 |
| Space Bunny Free | Ubegrænset | Ubegrænset | Ubegrænset |
| LongCat 2.5 Preview Free | Ubegrænset | Ubegrænset | Ubegrænset |
| Grok 4.7 | 169 | 423 | 845 |
| Grok 4.6 | 169 | 423 | 845 |
| GPT 6 Luna | 4,230 | 10,560 | 21,130 |
@@ -341,6 +346,7 @@ Du kan også få adgang til Go-modeller gennem følgende API-endpoints.
| Hy4 preview | hy4-preview | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
Dit [model id](/docs/config/#models) i din OpenCode config
bruger formatet `opencode-go/<model-id>`. For eksempel for Kimi K3, vil du
@@ -394,6 +400,7 @@ https://opencode.ai/zen/go/v1/models
| Hy4 preview | Ikke brugt | 0 dage |
| Hy3 | Ikke brugt | 0 dage |
| Space Bunny Free | Ikke brugt | 0 dage |
| LongCat 2.5 Preview Free | Ikke brugt | 0 dage |
- **Grok 4.7/4.6:** ZDR deaktiverer vigtige API-funktioner, der afhænger af lagrede data, herunder den tilstandsbevarende Responses API, Files and Collections og Batch API. [Læs mere](https://docs.x.ai/developers/faq/security#what-is-zero-data-retention-zdr).
- **GPT 6 Luna / GPT 5.6 Luna:** Logfiler til overvågning af misbrug genereres ved al brug af API-funktioner og opbevares i op til 30 dage. [Læs mere](https://developers.openai.com/api/docs/guides/your-data#data-retention-controls-for-abuse-monitoring).
+5
View File
@@ -108,6 +108,7 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints.
| Grok Build 0.1 | grok-build-0.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.3 | muse-spark-1.3 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.2 | muse-spark-1.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Qwen3.8 Max | qwen3.8-max | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Qwen3.8 Flash | qwen3.8-flash | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Plus | qwen3.7-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
@@ -133,6 +134,7 @@ Du kan også få adgang til vores modeller gennem følgende API-endpoints.
| Jev 1.13 Free | jev-1.13-free | `https://opencode.ai/zen/v1/systemone` | - |
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.6-Flash Free | mimo-v2.6-flash-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5 Free | mimo-v2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Ling 3.0 Flash Fin Free | ling-3.0-flash-fin-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@@ -218,6 +220,7 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**.
| --------------------------------- | ------ | ------- | ----------- | ------------ |
| Big Pickle | Free | Free | Free | - |
| Space Bunny Free | Free | Free | Free | - |
| LongCat 2.5 Preview Free | Free | Free | Free | - |
| MiMo-V2.6-Flash Free | Free | Free | Free | - |
| MiMo-V2.5 Free | Free | Free | Free | - |
| Ling 3.0 Flash Fin Free | Free | Free | Free | - |
@@ -238,6 +241,7 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**.
| Kimi K3 | $3.00 | $15.00 | $0.30 | - |
| Kimi K2.6 | $0.95 | $4.00 | $0.16 | - |
| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - |
| Qwen3.8 Max | $2.00 | $6.00 | $0.25 | $2.50 |
| Qwen3.8 Flash | $0.15 | $0.47 | $0.016 | $0.20 |
| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 |
| Qwen3.7 Plus | $0.40 | $1.60 | $0.04 | $0.50 |
@@ -326,6 +330,7 @@ De gratis modeller:
- Nemotron 3.5 Lightning Free er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at indsamle feedback og forbedre modellen.
- Big Pickle er en stealth-model, som er gratis på OpenCode i en begrænset periode. Teamet bruger denne tid til at indsamle feedback og forbedre modellen.
- Space Bunny Free er en stealth-model, som er gratis på OpenCode i en begrænset periode. Udbyderen følger en nul-opbevaringspolitik og bruger ikke dine data til at træne modeller.
- LongCat 2.5 Preview Free er gratis på OpenCode i en begrænset periode. Udbyderen følger en nul-opbevaringspolitik og bruger ikke dine data til at træne modeller.
- Muse Spark 1.3 Contributor Free er tilgængelig på OpenCode i en begrænset periode. Teamet bruger denne tid til at indsamle feedback og forbedre modellen.
- Jev 1.13 Free er tilgængelig på OpenCode i en begrænset periode.
@@ -56,7 +56,7 @@ Sie können sich auch [awesome-opencode](https://github.com/awesome-opencode/awe
| Name | Beschreibung |
| ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
| [kimaki](https://github.com/remorses/kimaki) | Discord-Bot zur Steuerung von OpenCode-Sitzungen, basierend auf SDK |
| [kimaki](https://kimaki.dev) | Discord-Bot zur Steuerung von OpenCode-Sitzungen, basierend auf SDK |
| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Neovim-Plugin für editorfähige Eingabeaufforderungen, basierend auf API |
| [portal](https://github.com/hosenur/portal) | Mobile-First-Web UI für OpenCode über Tailscale/VPN |
| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Vorlage zum Erstellen von OpenCode-Plugins |
+12 -5
View File
@@ -83,6 +83,7 @@ Die aktuelle Liste der Modelle umfasst:
- **Hy4 preview**
- **Hy3**
- **Space Bunny Free** (für begrenzte Zeit)
- **LongCat 2.5 Preview Free** (für begrenzte Zeit)
Die Liste der Modelle kann sich ändern, während wir neue testen und hinzufügen.
@@ -144,7 +145,7 @@ Wenn ein Modell beispielsweise ein monatliches Limit von $60 hat, kannst du bis
Tokenpreise gelten pro 1M Tokens.
| Model | Input | Output | Cached Read | Cached Write | Monatliches Limit |
| --------------------------------------- | ------ | ------ | ----------- | ------------ | ----------------------------------------------------------- |
| --------------------------------------- | ------ | ------ | ----------- | ------------ | ----------------------------------------------------- |
| GLM-5.3-Flash | $0.15 | $0.50 | $0.03 | - | **$60** |
| GLM-5.3 | $1.40 | $4.40 | $0.26 | - | **$15** |
| GLM-5.2 | $1.40 | $4.40 | $0.26 | - | **$60** |
@@ -169,8 +170,8 @@ Tokenpreise gelten pro 1M Tokens.
| Qwen3.7 Plus (> 256K tokens) | $1.20 | $4.80 | $0.12 | $1.50 | **$60** |
| Qwen3.6 Plus (≤ 256K tokens) | $0.50 | $3.00 | $0.05 | $0.625 | **$60** |
| Qwen3.6 Plus (> 256K tokens) | $2.00 | $6.00 | $0.20 | $2.50 | **$60** |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | ~~$15~~ **$60**<br /><small>4x · Endet am 27. Sept.</small> |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | ~~$15~~ **$60**<br /><small>4x · Endet am 27. Sept.</small> |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$60** |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | **$60** |
| DeepSeek V4 Pro (Off-Peak) | $0.66 | $1.98 | $0.022 | - | **$15** |
| DeepSeek V4 Pro (Peak) | $1.32 | $3.96 | $0.044 | - | **$15** |
| DeepSeek V4 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$30** |
@@ -180,6 +181,7 @@ Tokenpreise gelten pro 1M Tokens.
| Hy4 preview | $0.834 | $2.501 | $0.042 | - | **$30** |
| Hy3 | $0.14 | $0.58 | $0.035 | - | **$60** |
| Space Bunny Free | Free | Free | Free | - | **Unbegrenzt**<br /><small>für begrenzte Zeit</small> |
| LongCat 2.5 Preview Free | Free | Free | Free | - | **Unbegrenzt**<br /><small>für begrenzte Zeit</small> |
| Grok 4.7 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
| Grok 4.7 (> 200K tokens) | $4.00 | $12.00 | $1.00 | - | **$15** |
| Grok 4.6 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
@@ -191,6 +193,8 @@ Tokenpreise gelten pro 1M Tokens.
**Space Bunny Free:** Für begrenzte Zeit kostenlos.
**LongCat 2.5 Preview Free:** Für begrenzte Zeit kostenlos.
**DeepSeek V4.1 Flash / V4 Pro / V4 Flash / V4 Flash Vision Exp:** Die Peak-Zeiten sind montags bis freitags von 01:00-04:00 und 06:00-10:00 UTC; alle anderen Zeiten, einschließlich der Wochenenden, sind Off-Peak. [Mehr erfahren](https://api-docs.deepseek.com/quick_start/pricing/).
**DeepSeek V4 Flash Vision Exp:** Bilder werden anhand ihrer Abmessungen in Tokens umgewandelt und zusammen mit Text-Tokens als Input-Tokens abgerechnet. [Mehr erfahren](https://api-docs.deepseek.com/quick_start/pricing/).
@@ -200,7 +204,7 @@ Tokenpreise gelten pro 1M Tokens.
Die folgende Tabelle enthält eine geschätzte Anzahl von Anfragen basierend auf typischen Go-Nutzungsmustern:
| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat |
| --------------------------------------------------------------- | ------------------------- | -------------------------- | --------------------------- |
| ---------------------------- | ---------------------- | ------------------ | ------------------ |
| GLM-5.3-Flash | 6,320 | 15,790 | 31,580 |
| GLM-5.3 | 220 | 540 | 1,080 |
| GLM-5.2 | 880 | 2,150 | 4,300 |
@@ -222,13 +226,14 @@ Die folgende Tabelle enthält eine geschätzte Anzahl von Anfragen basierend auf
| Qwen3.7 Max | 170 | 420 | 840 |
| Qwen3.7 Plus | 4,300 | 10,800 | 21,600 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| DeepSeek V4.1 Flash<br /><small>4x · Endet am 27. Sept.</small> | ~~6,500~~<br />**26,000** | ~~16,250~~<br />**65,000** | ~~32,500~~<br />**130,000** |
| DeepSeek V4.1 Flash | 26,000 | 65,000 | 130,000 |
| DeepSeek V4 Pro | 1,050 | 2,600 | 5,200 |
| DeepSeek V4 Flash | 13,000 | 32,500 | 65,000 |
| DeepSeek V4 Flash Vision Exp | 6,500 | 16,250 | 32,500 |
| Hy4 preview | 1,350 | 3,380 | 6,770 |
| Hy3 | 4,300 | 10,750 | 21,500 |
| Space Bunny Free | Unbegrenzt | Unbegrenzt | Unbegrenzt |
| LongCat 2.5 Preview Free | Unbegrenzt | Unbegrenzt | Unbegrenzt |
| Grok 4.7 | 169 | 423 | 845 |
| Grok 4.6 | 169 | 423 | 845 |
| GPT 6 Luna | 4,230 | 10,560 | 21,130 |
@@ -331,6 +336,7 @@ Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen.
| Hy4 preview | hy4-preview | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
Die [Modell-ID](/docs/config/#models) in deiner OpenCode Config verwendet das Format `opencode-go/<model-id>`. Für Kimi K3 würdest du beispielsweise `opencode-go/kimi-k3` in deiner Config verwenden.
@@ -382,6 +388,7 @@ https://opencode.ai/zen/go/v1/models
| Hy4 preview | Nicht verwendet | 0 Tage |
| Hy3 | Nicht verwendet | 0 Tage |
| Space Bunny Free | Nicht verwendet | 0 Tage |
| LongCat 2.5 Preview Free | Nicht verwendet | 0 Tage |
- **Grok 4.7/4.6:** ZDR deaktiviert wichtige API-Funktionen, die von gespeicherten Daten abhängen, einschließlich der zustandsbehafteten Responses API, Files and Collections und der Batch API. [Mehr erfahren](https://docs.x.ai/developers/faq/security#what-is-zero-data-retention-zdr).
- **GPT 6 Luna / GPT 5.6 Luna:** Für die Nutzung aller API-Funktionen werden Protokolle zur Missbrauchsüberwachung erstellt und bis zu 30 Tage lang aufbewahrt. [Mehr erfahren](https://developers.openai.com/api/docs/guides/your-data#data-retention-controls-for-abuse-monitoring).
+5
View File
@@ -99,6 +99,7 @@ Du kannst auch über die folgenden API-Endpunkte auf unsere Modelle zugreifen.
| Grok Build 0.1 | grok-build-0.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.3 | muse-spark-1.3 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.2 | muse-spark-1.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Qwen3.8 Max | qwen3.8-max | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Qwen3.8 Flash | qwen3.8-flash | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Plus | qwen3.7-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
@@ -124,6 +125,7 @@ Du kannst auch über die folgenden API-Endpunkte auf unsere Modelle zugreifen.
| Jev 1.13 Free | jev-1.13-free | `https://opencode.ai/zen/v1/systemone` | - |
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.6-Flash Free | mimo-v2.6-flash-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5 Free | mimo-v2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Ling 3.0 Flash Fin Free | ling-3.0-flash-fin-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@@ -207,6 +209,7 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M
| --------------------------------- | --------- | --------- | ----------- | ------------ |
| Big Pickle | Free | Free | Free | - |
| Space Bunny Free | Free | Free | Free | - |
| LongCat 2.5 Preview Free | Free | Free | Free | - |
| MiMo-V2.6-Flash Free | Free | Free | Free | - |
| MiMo-V2.5 Free | Free | Free | Free | - |
| Ling 3.0 Flash Fin Free | Free | Free | Free | - |
@@ -227,6 +230,7 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M
| Kimi K3 | $3.00 | $15.00 | $0.30 | - |
| Kimi K2.6 | $0.95 | $4.00 | $0.16 | - |
| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - |
| Qwen3.8 Max | $2.00 | $6.00 | $0.25 | $2.50 |
| Qwen3.8 Flash | $0.15 | $0.47 | $0.016 | $0.20 |
| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 |
| Qwen3.7 Plus | $0.40 | $1.60 | $0.04 | $0.50 |
@@ -315,6 +319,7 @@ Die kostenlosen Modelle:
- Nemotron 3.5 Lightning Free ist für begrenzte Zeit auf OpenCode verfügbar. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern.
- Big Pickle ist ein Stealth-Modell, das für begrenzte Zeit kostenlos auf OpenCode verfügbar ist. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern.
- Space Bunny Free ist ein Stealth-Modell, das für begrenzte Zeit kostenlos auf OpenCode verfügbar ist. Der Anbieter befolgt eine Zero-Retention-Richtlinie und verwendet deine Daten nicht zum Trainieren von Modellen.
- LongCat 2.5 Preview Free ist für begrenzte Zeit kostenlos auf OpenCode verfügbar. Der Anbieter befolgt eine Zero-Retention-Richtlinie und verwendet deine Daten nicht zum Trainieren von Modellen.
- Muse Spark 1.3 Contributor Free ist für begrenzte Zeit auf OpenCode verfügbar. Das Team nutzt diese Zeit, um Feedback zu sammeln und das Modell zu verbessern.
- Jev 1.13 Free ist für begrenzte Zeit auf OpenCode verfügbar.
+1 -1
View File
@@ -62,7 +62,7 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw
| Name | Description |
| ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- |
| [kimaki](https://github.com/remorses/kimaki) | Discord bot to control OpenCode sessions, built on the SDK |
| [kimaki](https://kimaki.dev) | Discord bot to control OpenCode sessions, built on the SDK |
| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Neovim plugin for editor-aware prompts, built on the API |
| [portal](https://github.com/hosenur/portal) | Mobile-first web UI for OpenCode over Tailscale/VPN |
| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Template for building OpenCode plugins |
@@ -56,7 +56,7 @@ También puedes consultar [awesome-opencode](https://github.com/awesome-opencode
| Nombre | Descripción |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| [kimaki](https://github.com/remorses/kimaki) | Bot de Discord para controlar sesiones OpenCode, basado en el SDK |
| [kimaki](https://kimaki.dev) | Bot de Discord para controlar sesiones OpenCode, basado en el SDK |
| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Complemento Neovim para avisos compatibles con el editor, creado en API |
| [portal](https://github.com/hosenur/portal) | Interfaz de usuario web móvil para OpenCode a través de Tailscale/VPN |
| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Plantilla para crear complementos OpenCode |
+12 -5
View File
@@ -91,6 +91,7 @@ La lista actual de modelos incluye:
- **Hy4 preview**
- **Hy3**
- **Space Bunny Free** (por tiempo limitado)
- **LongCat 2.5 Preview Free** (por tiempo limitado)
La lista de modelos puede cambiar a medida que probamos y agregamos otros nuevos.
@@ -152,7 +153,7 @@ Por ejemplo, si un modelo tiene un límite mensual de $60, puedes gastar hasta:
Los precios de tokens se indican por 1M tokens.
| Modelo | Entrada | Salida | Lectura en caché | Escritura en caché | Límite mensual |
| --------------------------------------- | ------- | ------ | ---------------- | ------------------ | ------------------------------------------------------------- |
| --------------------------------------- | ------- | ------ | ---------------- | ------------------ | ----------------------------------------------------- |
| GLM-5.3-Flash | $0.15 | $0.50 | $0.03 | - | **$60** |
| GLM-5.3 | $1.40 | $4.40 | $0.26 | - | **$15** |
| GLM-5.2 | $1.40 | $4.40 | $0.26 | - | **$60** |
@@ -177,8 +178,8 @@ Los precios de tokens se indican por 1M tokens.
| Qwen3.7 Plus (> 256K tokens) | $1.20 | $4.80 | $0.12 | $1.50 | **$60** |
| Qwen3.6 Plus (≤ 256K tokens) | $0.50 | $3.00 | $0.05 | $0.625 | **$60** |
| Qwen3.6 Plus (> 256K tokens) | $2.00 | $6.00 | $0.20 | $2.50 | **$60** |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | ~~$15~~ **$60**<br /><small>4x · Hasta el 27 de sept.</small> |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | ~~$15~~ **$60**<br /><small>4x · Hasta el 27 de sept.</small> |
| DeepSeek V4.1 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$60** |
| DeepSeek V4.1 Flash (Peak) | $0.30 | $1.20 | $0.006 | - | **$60** |
| DeepSeek V4 Pro (Off-Peak) | $0.66 | $1.98 | $0.022 | - | **$15** |
| DeepSeek V4 Pro (Peak) | $1.32 | $3.96 | $0.044 | - | **$15** |
| DeepSeek V4 Flash (Off-Peak) | $0.15 | $0.60 | $0.003 | - | **$30** |
@@ -188,6 +189,7 @@ Los precios de tokens se indican por 1M tokens.
| Hy4 preview | $0.834 | $2.501 | $0.042 | - | **$30** |
| Hy3 | $0.14 | $0.58 | $0.035 | - | **$60** |
| Space Bunny Free | Free | Free | Free | - | **Ilimitado**<br /><small>por tiempo limitado</small> |
| LongCat 2.5 Preview Free | Free | Free | Free | - | **Ilimitado**<br /><small>por tiempo limitado</small> |
| Grok 4.7 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
| Grok 4.7 (> 200K tokens) | $4.00 | $12.00 | $1.00 | - | **$15** |
| Grok 4.6 (≤ 200K tokens) | $2.00 | $6.00 | $0.50 | - | **$15** |
@@ -199,6 +201,8 @@ Los precios de tokens se indican por 1M tokens.
**Space Bunny Free:** Gratis por tiempo limitado.
**LongCat 2.5 Preview Free:** Gratis por tiempo limitado.
**DeepSeek V4.1 Flash / V4 Pro / V4 Flash / V4 Flash Vision Exp:** Las horas Peak son 01:00-04:00 y 06:00-10:00 UTC, de lunes a viernes; todas las demás horas, incluidos los fines de semana, son Off-Peak. [Más información](https://api-docs.deepseek.com/quick_start/pricing/).
**DeepSeek V4 Flash Vision Exp:** Las imágenes se convierten en tokens según sus dimensiones y se facturan como tokens de entrada junto con los tokens de texto. [Más información](https://api-docs.deepseek.com/quick_start/pricing/).
@@ -208,7 +212,7 @@ Los precios de tokens se indican por 1M tokens.
La siguiente tabla ofrece una cantidad estimada de peticiones basada en los patrones típicos de uso de Go:
| Model | peticiones por 5 horas | peticiones por semana | peticiones por mes |
| ----------------------------------------------------------------- | ------------------------- | -------------------------- | --------------------------- |
| ---------------------------- | ---------------------- | --------------------- | ------------------ |
| GLM-5.3-Flash | 6,320 | 15,790 | 31,580 |
| GLM-5.3 | 220 | 540 | 1,080 |
| GLM-5.2 | 880 | 2,150 | 4,300 |
@@ -230,13 +234,14 @@ La siguiente tabla ofrece una cantidad estimada de peticiones basada en los patr
| Qwen3.7 Max | 170 | 420 | 840 |
| Qwen3.7 Plus | 4,300 | 10,800 | 21,600 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| DeepSeek V4.1 Flash<br /><small>4x · Hasta el 27 de sept.</small> | ~~6,500~~<br />**26,000** | ~~16,250~~<br />**65,000** | ~~32,500~~<br />**130,000** |
| DeepSeek V4.1 Flash | 26,000 | 65,000 | 130,000 |
| DeepSeek V4 Pro | 1,050 | 2,600 | 5,200 |
| DeepSeek V4 Flash | 13,000 | 32,500 | 65,000 |
| DeepSeek V4 Flash Vision Exp | 6,500 | 16,250 | 32,500 |
| Hy4 preview | 1,350 | 3,380 | 6,770 |
| Hy3 | 4,300 | 10,750 | 21,500 |
| Space Bunny Free | Ilimitado | Ilimitado | Ilimitado |
| LongCat 2.5 Preview Free | Ilimitado | Ilimitado | Ilimitado |
| Grok 4.7 | 169 | 423 | 845 |
| Grok 4.6 | 169 | 423 | 845 |
| GPT 6 Luna | 4,230 | 10,560 | 21,130 |
@@ -341,6 +346,7 @@ También puedes acceder a los modelos de Go a través de los siguientes endpoint
| Hy4 preview | hy4-preview | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Hy3 | hy3 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
El [ID del modelo](/docs/config/#models) en tu configuración de OpenCode
usa el formato `opencode-go/<model-id>`. Por ejemplo, para Kimi K3, usarías
@@ -394,6 +400,7 @@ https://opencode.ai/zen/go/v1/models
| Hy4 preview | No utilizado | 0 días |
| Hy3 | No utilizado | 0 días |
| Space Bunny Free | No utilizado | 0 días |
| LongCat 2.5 Preview Free | No utilizado | 0 días |
- **Grok 4.7/4.6:** ZDR deshabilita funciones importantes de la API que dependen de datos almacenados, incluidas la Responses API con estado, Files and Collections y la Batch API. [Más información](https://docs.x.ai/developers/faq/security#what-is-zero-data-retention-zdr).
- **GPT 6 Luna / GPT 5.6 Luna:** Se generan registros de supervisión de abusos para todo el uso de funciones de la API y se conservan durante un máximo de 30 días. [Más información](https://developers.openai.com/api/docs/guides/your-data#data-retention-controls-for-abuse-monitoring).
+5
View File
@@ -108,6 +108,7 @@ También puedes acceder a nuestros modelos a través de los siguientes endpoints
| Grok Build 0.1 | grok-build-0.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.3 | muse-spark-1.3 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Muse Spark 1.2 | muse-spark-1.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
| Qwen3.8 Max | qwen3.8-max | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Qwen3.8 Flash | qwen3.8-flash | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Max | qwen3.7-max | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
| Qwen3.7 Plus | qwen3.7-plus | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` |
@@ -133,6 +134,7 @@ También puedes acceder a nuestros modelos a través de los siguientes endpoints
| Jev 1.13 Free | jev-1.13-free | `https://opencode.ai/zen/v1/systemone` | - |
| Big Pickle | big-pickle | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Space Bunny Free | space-bunny-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| LongCat 2.5 Preview Free | longcat-2.5-preview-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.6-Flash Free | mimo-v2.6-flash-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5 Free | mimo-v2.5-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Ling 3.0 Flash Fin Free | ling-3.0-flash-fin-free | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@@ -218,6 +220,7 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p
| --------------------------------- | ------- | ------- | ---------------- | ------------------ |
| Big Pickle | Free | Free | Free | - |
| Space Bunny Free | Free | Free | Free | - |
| LongCat 2.5 Preview Free | Free | Free | Free | - |
| MiMo-V2.6-Flash Free | Free | Free | Free | - |
| MiMo-V2.5 Free | Free | Free | Free | - |
| Ling 3.0 Flash Fin Free | Free | Free | Free | - |
@@ -238,6 +241,7 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p
| Kimi K3 | $3.00 | $15.00 | $0.30 | - |
| Kimi K2.6 | $0.95 | $4.00 | $0.16 | - |
| Kimi K2.5 | $0.60 | $3.00 | $0.10 | - |
| Qwen3.8 Max | $2.00 | $6.00 | $0.25 | $2.50 |
| Qwen3.8 Flash | $0.15 | $0.47 | $0.016 | $0.20 |
| Qwen3.7 Max | $2.50 | $7.50 | $0.50 | $3.125 |
| Qwen3.7 Plus | $0.40 | $1.60 | $0.04 | $0.50 |
@@ -326,6 +330,7 @@ Los modelos gratuitos:
- Nemotron 3.5 Lightning Free está disponible en OpenCode por tiempo limitado. El equipo está usando este tiempo para recopilar comentarios y mejorar el modelo.
- Big Pickle es un modelo stealth que es gratuito en OpenCode por tiempo limitado. El equipo está usando este tiempo para recopilar comentarios y mejorar el modelo.
- Space Bunny Free es un modelo stealth que es gratuito en OpenCode por tiempo limitado. Su proveedor sigue una política de retención cero y no utiliza tus datos para entrenar modelos.
- LongCat 2.5 Preview Free es gratuito en OpenCode por tiempo limitado. Su proveedor sigue una política de retención cero y no utiliza tus datos para entrenar modelos.
- Muse Spark 1.3 Contributor Free está disponible en OpenCode por tiempo limitado. El equipo está aprovechando este período para recopilar comentarios y mejorar el modelo.
- Jev 1.13 Free está disponible en OpenCode por tiempo limitado.

Some files were not shown because too many files have changed in this diff Show More