Merge remote-tracking branch 'upstream/dev' into refactor-shells

This commit is contained in:
LukeParkerDev 2026-04-27 08:59:39 +10:00
commit 5a7e69b325
88 changed files with 2959 additions and 1699 deletions

View file

@ -1,899 +0,0 @@
---
description: Translate content for a specified locale while preserving technical terms
mode: subagent
model: opencode/gpt-5.4
---
You are a professional translator and localization specialist.
Translate the user's content into the requested target locale (language + region, e.g. fr-FR, de-DE).
Requirements:
- Preserve meaning, intent, tone, and formatting (including Markdown/MDX structure).
- Preserve all technical terms and artifacts exactly: product/company names, API names, identifiers, code, commands/flags, file paths, URLs, versions, error messages, config keys/values, and anything inside inline code or code blocks.
- Also preserve every term listed in the Do-Not-Translate glossary below.
- Also apply locale-specific guidance from `.opencode/glossary/<locale>.md` when available (for example, `zh-cn.md`).
- Do not modify fenced code blocks.
- Output ONLY the translation (no commentary).
If the target locale is missing, ask the user to provide it.
If no locale-specific glossary exists, use the global glossary only.
---
# Locale-Specific Glossaries
When a locale glossary exists, use it to:
- Apply preferred wording for recurring UI/docs terms in that locale
- Preserve locale-specific do-not-translate terms and casing decisions
- Prefer natural phrasing over literal translation when the locale file calls it out
- If the repo uses a locale alias slug, apply that file too (for example, `pt-BR` maps to `br.md` in this repo)
Locale guidance does not override code/command preservation rules or the global Do-Not-Translate glossary below.
---
# Do-Not-Translate Terms (OpenCode Docs)
Generated from: `packages/web/src/content/docs/*.mdx` (default English docs)
Generated on: 2026-02-10
Use this as a translation QA checklist / glossary. Preserve listed terms exactly (spelling, casing, punctuation).
General rules (verbatim, even if not listed below):
- Anything inside inline code (single backticks) or fenced code blocks (triple backticks)
- MDX/JS code in docs: `import ... from "..."`, component tags, identifiers
- CLI commands, flags, config keys/values, file paths, URLs/domains, and env vars
## Proper nouns and product names
Additional (not reliably captured via link text):
```text
Astro
Bun
Chocolatey
Cursor
Docker
Git
GitHub Actions
GitLab CI
GNOME Terminal
Homebrew
Mise
Neovim
Node.js
npm
Obsidian
opencode
opencode-ai
Paru
pnpm
ripgrep
Scoop
SST
Starlight
Visual Studio Code
VS Code
VSCodium
Windsurf
Windows Terminal
Yarn
Zellij
Zed
anomalyco
```
Extracted from link labels in the English docs (review and prune as desired):
```text
@openspoon/subtask2
302.AI console
ACP progress report
Agent Client Protocol
Agent Skills
Agentic
AGENTS.md
AI SDK
Alacritty
Anthropic
Anthropic's Data Policies
Atom One
Avante.nvim
Ayu
Azure AI Foundry
Azure portal
Baseten
built-in GITHUB_TOKEN
Bun.$
Catppuccin
Cerebras console
ChatGPT Plus or Pro
Cloudflare dashboard
CodeCompanion.nvim
CodeNomad
Configuring Adapters: Environment Variables
Context7 MCP server
Cortecs console
Deep Infra dashboard
DeepSeek console
Duo Agent Platform
Everforest
Fireworks AI console
Firmware dashboard
Ghostty
GitLab CLI agents docs
GitLab docs
GitLab User Settings > Access Tokens
Granular Rules (Object Syntax)
Grep by Vercel
Groq console
Gruvbox
Helicone
Helicone documentation
Helicone Header Directory
Helicone's Model Directory
Hugging Face Inference Providers
Hugging Face settings
install WSL
IO.NET console
JetBrains IDE
Kanagawa
Kitty
MiniMax API Console
Models.dev
Moonshot AI console
Nebius Token Factory console
Nord
OAuth
Ollama integration docs
OpenAI's Data Policies
OpenChamber
OpenCode
OpenCode config
OpenCode Config
OpenCode TUI with the opencode theme
OpenCode Web - Active Session
OpenCode Web - New Session
OpenCode Web - See Servers
OpenCode Zen
OpenCode-Obsidian
OpenRouter dashboard
OpenWork
OVHcloud panel
Pro+ subscription
SAP BTP Cockpit
Scaleway Console IAM settings
Scaleway Generative APIs
SDK documentation
Sentry MCP server
shell API
Together AI console
Tokyonight
Unified Billing
Venice AI console
Vercel dashboard
WezTerm
Windows Subsystem for Linux (WSL)
WSL
WSL (Windows Subsystem for Linux)
WSL extension
xAI console
Z.AI API console
Zed
ZenMux dashboard
Zod
```
## Acronyms and initialisms
```text
ACP
AGENTS
AI
AI21
ANSI
API
AST
AWS
BTP
CD
CDN
CI
CLI
CMD
CORS
DEBUG
EKS
ERROR
FAQ
GLM
GNOME
GPT
HTML
HTTP
HTTPS
IAM
ID
IDE
INFO
IO
IP
IRSA
JS
JSON
JSONC
K2
LLM
LM
LSP
M2
MCP
MR
NET
NPM
NTLM
OIDC
OS
PAT
PATH
PHP
PR
PTY
README
RFC
RPC
SAP
SDK
SKILL
SSE
SSO
TS
TTY
TUI
UI
URL
US
UX
VCS
VPC
VPN
VS
WARN
WSL
X11
YAML
```
## Code identifiers used in prose (CamelCase, mixedCase)
```text
apiKey
AppleScript
AssistantMessage
baseURL
BurntSushi
ChatGPT
ClangFormat
CodeCompanion
CodeNomad
DeepSeek
DefaultV2
FileContent
FileDiff
FileNode
fineGrained
FormatterStatus
GitHub
GitLab
iTerm2
JavaScript
JetBrains
macOS
mDNS
MiniMax
NeuralNomadsAI
NickvanDyke
NoeFabris
OpenAI
OpenAPI
OpenChamber
OpenCode
OpenRouter
OpenTUI
OpenWork
ownUserPermissions
PowerShell
ProviderAuthAuthorization
ProviderAuthMethod
ProviderInitError
SessionStatus
TabItem
tokenType
ToolIDs
ToolList
TypeScript
typesUrl
UserMessage
VcsInfo
WebView2
WezTerm
xAI
ZenMux
```
## OpenCode CLI commands (as shown in docs)
```text
opencode
opencode [project]
opencode /path/to/project
opencode acp
opencode agent [command]
opencode agent create
opencode agent list
opencode attach [url]
opencode attach http://10.20.30.40:4096
opencode attach http://localhost:4096
opencode auth [command]
opencode auth list
opencode auth login
opencode auth logout
opencode auth ls
opencode export [sessionID]
opencode github [command]
opencode github install
opencode github run
opencode import <file>
opencode import https://opncd.ai/s/abc123
opencode import session.json
opencode mcp [command]
opencode mcp add
opencode mcp auth [name]
opencode mcp auth list
opencode mcp auth ls
opencode mcp auth my-oauth-server
opencode mcp auth sentry
opencode mcp debug <name>
opencode mcp debug my-oauth-server
opencode mcp list
opencode mcp logout [name]
opencode mcp logout my-oauth-server
opencode mcp ls
opencode models --refresh
opencode models [provider]
opencode models anthropic
opencode run [message..]
opencode run Explain the use of context in Go
opencode serve
opencode serve --cors http://localhost:5173 --cors https://app.example.com
opencode serve --hostname 0.0.0.0 --port 4096
opencode serve [--port <number>] [--hostname <string>] [--cors <origin>]
opencode session [command]
opencode session list
opencode session delete <sessionID>
opencode stats
opencode uninstall
opencode upgrade
opencode upgrade [target]
opencode upgrade v0.1.48
opencode web
opencode web --cors https://example.com
opencode web --hostname 0.0.0.0
opencode web --mdns
opencode web --mdns --mdns-domain myproject.local
opencode web --port 4096
opencode web --port 4096 --hostname 0.0.0.0
opencode.server.close()
```
## Slash commands and routes
```text
/agent
/auth/:id
/clear
/command
/config
/config/providers
/connect
/continue
/doc
/editor
/event
/experimental/tool?provider=<p>&model=<m>
/experimental/tool/ids
/export
/file?path=<path>
/file/content?path=<p>
/file/status
/find?pattern=<pat>
/find/file
/find/file?query=<q>
/find/symbol?query=<q>
/formatter
/global/event
/global/health
/help
/init
/instance/dispose
/log
/lsp
/mcp
/mnt/
/mnt/c/
/mnt/d/
/models
/oc
/opencode
/path
/project
/project/current
/provider
/provider/{id}/oauth/authorize
/provider/{id}/oauth/callback
/provider/auth
/q
/quit
/redo
/resume
/session
/session/:id
/session/:id/abort
/session/:id/children
/session/:id/command
/session/:id/diff
/session/:id/fork
/session/:id/init
/session/:id/message
/session/:id/message/:messageID
/session/:id/permissions/:permissionID
/session/:id/prompt_async
/session/:id/revert
/session/:id/share
/session/:id/shell
/session/:id/summarize
/session/:id/todo
/session/:id/unrevert
/session/status
/share
/summarize
/theme
/tui
/tui/append-prompt
/tui/clear-prompt
/tui/control/next
/tui/control/response
/tui/execute-command
/tui/open-help
/tui/open-models
/tui/open-sessions
/tui/open-themes
/tui/show-toast
/tui/submit-prompt
/undo
/Users/username
/Users/username/projects/*
/vcs
```
## CLI flags and short options
```text
--agent
--attach
--command
--continue
--cors
--cwd
--days
--dir
--dry-run
--event
--file
--force
--fork
--format
--help
--hostname
--hostname 0.0.0.0
--keep-config
--keep-data
--log-level
--max-count
--mdns
--mdns-domain
--method
--model
--models
--port
--print-logs
--project
--prompt
--refresh
--session
--share
--title
--token
--tools
--verbose
--version
--wait
-c
-d
-f
-h
-m
-n
-s
-v
```
## Environment variables
```text
AI_API_URL
AI_FLOW_CONTEXT
AI_FLOW_EVENT
AI_FLOW_INPUT
AICORE_DEPLOYMENT_ID
AICORE_RESOURCE_GROUP
AICORE_SERVICE_KEY
ANTHROPIC_API_KEY
AWS_ACCESS_KEY_ID
AWS_BEARER_TOKEN_BEDROCK
AWS_PROFILE
AWS_REGION
AWS_ROLE_ARN
AWS_SECRET_ACCESS_KEY
AWS_WEB_IDENTITY_TOKEN_FILE
AZURE_COGNITIVE_SERVICES_RESOURCE_NAME
AZURE_RESOURCE_NAME
CI_PROJECT_DIR
CI_SERVER_FQDN
CI_WORKLOAD_REF
CLOUDFLARE_ACCOUNT_ID
CLOUDFLARE_API_TOKEN
CLOUDFLARE_GATEWAY_ID
CONTEXT7_API_KEY
GITHUB_TOKEN
GITLAB_AI_GATEWAY_URL
GITLAB_HOST
GITLAB_INSTANCE_URL
GITLAB_OAUTH_CLIENT_ID
GITLAB_TOKEN
GITLAB_TOKEN_OPENCODE
GOOGLE_APPLICATION_CREDENTIALS
GOOGLE_CLOUD_PROJECT
HTTP_PROXY
HTTPS_PROXY
K2_
MY_API_KEY
MY_ENV_VAR
MY_MCP_CLIENT_ID
MY_MCP_CLIENT_SECRET
NO_PROXY
NODE_ENV
NODE_EXTRA_CA_CERTS
NPM_AUTH_TOKEN
OC_ALLOW_WAYLAND
OPENCODE_API_KEY
OPENCODE_AUTH_JSON
OPENCODE_AUTO_SHARE
OPENCODE_CLIENT
OPENCODE_CONFIG
OPENCODE_CONFIG_CONTENT
OPENCODE_CONFIG_DIR
OPENCODE_DISABLE_AUTOCOMPACT
OPENCODE_DISABLE_AUTOUPDATE
OPENCODE_DISABLE_CLAUDE_CODE
OPENCODE_DISABLE_CLAUDE_CODE_PROMPT
OPENCODE_DISABLE_CLAUDE_CODE_SKILLS
OPENCODE_DISABLE_DEFAULT_PLUGINS
OPENCODE_DISABLE_LSP_DOWNLOAD
OPENCODE_DISABLE_MODELS_FETCH
OPENCODE_DISABLE_PRUNE
OPENCODE_DISABLE_TERMINAL_TITLE
OPENCODE_ENABLE_EXA
OPENCODE_ENABLE_EXPERIMENTAL_MODELS
OPENCODE_EXPERIMENTAL
OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS
OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT
OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER
OPENCODE_EXPERIMENTAL_EXA
OPENCODE_EXPERIMENTAL_FILEWATCHER
OPENCODE_EXPERIMENTAL_ICON_DISCOVERY
OPENCODE_EXPERIMENTAL_LSP_TOOL
OPENCODE_EXPERIMENTAL_LSP_TY
OPENCODE_EXPERIMENTAL_MARKDOWN
OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX
OPENCODE_EXPERIMENTAL_OXFMT
OPENCODE_EXPERIMENTAL_PLAN_MODE
OPENCODE_ENABLE_QUESTION_TOOL
OPENCODE_FAKE_VCS
OPENCODE_GIT_BASH_PATH
OPENCODE_MODEL
OPENCODE_MODELS_URL
OPENCODE_PERMISSION
OPENCODE_PORT
OPENCODE_SERVER_PASSWORD
OPENCODE_SERVER_USERNAME
PROJECT_ROOT
RESOURCE_NAME
RUST_LOG
VARIABLE_NAME
VERTEX_LOCATION
XDG_CONFIG_HOME
```
## Package/module identifiers
```text
../../../config.mjs
@astrojs/starlight/components
@opencode-ai/plugin
@opencode-ai/sdk
path
shescape
zod
@
@ai-sdk/anthropic
@ai-sdk/cerebras
@ai-sdk/google
@ai-sdk/openai
@ai-sdk/openai-compatible
@File#L37-42
@modelcontextprotocol/server-everything
@opencode
```
## GitHub owner/repo slugs referenced in docs
```text
24601/opencode-zellij-namer
angristan/opencode-wakatime
anomalyco/opencode
apps/opencode-agent
athal7/opencode-devcontainers
awesome-opencode/awesome-opencode
backnotprop/plannotator
ben-vargas/ai-sdk-provider-opencode-sdk
btriapitsyn/openchamber
BurntSushi/ripgrep
Cluster444/agentic
code-yeongyu/oh-my-opencode
darrenhinde/opencode-agents
different-ai/opencode-scheduler
different-ai/openwork
features/copilot
folke/tokyonight.nvim
franlol/opencode-md-table-formatter
ggml-org/llama.cpp
ghoulr/opencode-websearch-cited.git
H2Shami/opencode-helicone-session
hosenur/portal
jamesmurdza/daytona
jenslys/opencode-gemini-auth
JRedeker/opencode-morph-fast-apply
JRedeker/opencode-shell-strategy
kdcokenny/ocx
kdcokenny/opencode-background-agents
kdcokenny/opencode-notify
kdcokenny/opencode-workspace
kdcokenny/opencode-worktree
login/device
mohak34/opencode-notifier
morhetz/gruvbox
mtymek/opencode-obsidian
NeuralNomadsAI/CodeNomad
nick-vi/opencode-type-inject
NickvanDyke/opencode.nvim
NoeFabris/opencode-antigravity-auth
nordtheme/nord
numman-ali/opencode-openai-codex-auth
olimorris/codecompanion.nvim
panta82/opencode-notificator
rebelot/kanagawa.nvim
remorses/kimaki
sainnhe/everforest
shekohex/opencode-google-antigravity-auth
shekohex/opencode-pty.git
spoons-and-mirrors/subtask2
sudo-tee/opencode.nvim
supermemoryai/opencode-supermemory
Tarquinen/opencode-dynamic-context-pruning
Th3Whit3Wolf/one-nvim
upstash/context7
vtemian/micode
vtemian/octto
yetone/avante.nvim
zenobi-us/opencode-plugin-template
zenobi-us/opencode-skillful
```
## Paths, filenames, globs, and URLs
```text
./.opencode/themes/*.json
./<project-slug>/storage/
./config/#custom-directory
./global/storage/
.agents/skills/*/SKILL.md
.agents/skills/<name>/SKILL.md
.clang-format
.claude
.claude/skills
.claude/skills/*/SKILL.md
.claude/skills/<name>/SKILL.md
.env
.github/workflows/opencode.yml
.gitignore
.gitlab-ci.yml
.ignore
.NET SDK
.npmrc
.ocamlformat
.opencode
.opencode/
.opencode/agents/
.opencode/commands/
.opencode/commands/test.md
.opencode/modes/
.opencode/plans/*.md
.opencode/plugins/
.opencode/skills/<name>/SKILL.md
.opencode/skills/git-release/SKILL.md
.opencode/tools/
.well-known/opencode
{ type: "raw" \| "patch", content: string }
{file:path/to/file}
**/*.js
%USERPROFILE%/intelephense/license.txt
%USERPROFILE%\.cache\opencode
%USERPROFILE%\.config\opencode\opencode.jsonc
%USERPROFILE%\.config\opencode\plugins
%USERPROFILE%\.local\share\opencode
%USERPROFILE%\.local\share\opencode\log
<project-root>/.opencode/themes/*.json
<providerId>/<modelId>
<your-project>/.opencode/plugins/
~
~/...
~/.agents/skills/*/SKILL.md
~/.agents/skills/<name>/SKILL.md
~/.aws/credentials
~/.bashrc
~/.cache/opencode
~/.cache/opencode/node_modules/
~/.claude/CLAUDE.md
~/.claude/skills/
~/.claude/skills/*/SKILL.md
~/.claude/skills/<name>/SKILL.md
~/.config/opencode
~/.config/opencode/AGENTS.md
~/.config/opencode/agents/
~/.config/opencode/commands/
~/.config/opencode/modes/
~/.config/opencode/opencode.json
~/.config/opencode/opencode.jsonc
~/.config/opencode/plugins/
~/.config/opencode/skills/*/SKILL.md
~/.config/opencode/skills/<name>/SKILL.md
~/.config/opencode/themes/*.json
~/.config/opencode/tools/
~/.config/zed/settings.json
~/.local/share
~/.local/share/opencode/
~/.local/share/opencode/auth.json
~/.local/share/opencode/log/
~/.local/share/opencode/mcp-auth.json
~/.local/share/opencode/opencode.jsonc
~/.npmrc
~/.zshrc
~/code/
~/Library/Application Support
~/projects/*
~/projects/personal/
${config.github}/blob/dev/packages/sdk/js/src/gen/types.gen.ts
$HOME/intelephense/license.txt
$HOME/projects/*
$XDG_CONFIG_HOME/opencode/themes/*.json
agent/
agents/
build/
commands/
dist/
http://<wsl-ip>:4096
http://127.0.0.1:8080/callback
http://localhost:<port>
http://localhost:4096
http://localhost:4096/doc
https://app.example.com
https://AZURE_COGNITIVE_SERVICES_RESOURCE_NAME.cognitiveservices.azure.com/
https://opencode.ai/zen/v1/chat/completions
https://opencode.ai/zen/v1/messages
https://opencode.ai/zen/v1/models/gemini-3-flash
https://opencode.ai/zen/v1/models/gemini-3-pro
https://opencode.ai/zen/v1/responses
https://RESOURCE_NAME.openai.azure.com/
laravel/pint
log/
model: "anthropic/claude-sonnet-4-5"
modes/
node_modules/
openai/gpt-4.1
opencode.ai/config.json
opencode/<model-id>
opencode/gpt-5.1-codex
opencode/gpt-5.2-codex
opencode/kimi-k2
openrouter/google/gemini-2.5-flash
opncd.ai/s/<share-id>
packages/*/AGENTS.md
plugins/
project/
provider_id/model_id
provider/model
provider/model-id
rm -rf ~/.cache/opencode
skills/
skills/*/SKILL.md
src/**/*.ts
themes/
tools/
```
## Keybind strings
```text
alt+b
Alt+Ctrl+K
alt+d
alt+f
Cmd+Esc
Cmd+Option+K
Cmd+Shift+Esc
Cmd+Shift+G
Cmd+Shift+P
ctrl+a
ctrl+b
ctrl+d
ctrl+e
Ctrl+Esc
ctrl+f
ctrl+g
ctrl+k
Ctrl+Shift+Esc
Ctrl+Shift+P
ctrl+t
ctrl+u
ctrl+w
ctrl+x
DELETE
Shift+Enter
WIN+R
```
## Model ID strings referenced
```text
{env:OPENCODE_MODEL}
anthropic/claude-3-5-sonnet-20241022
anthropic/claude-haiku-4-20250514
anthropic/claude-haiku-4-5
anthropic/claude-sonnet-4-20250514
anthropic/claude-sonnet-4-5
gitlab/duo-chat-haiku-4-5
lmstudio/google/gemma-3n-e4b
openai/gpt-4.1
openai/gpt-5
opencode/gpt-5.1-codex
opencode/gpt-5.2-codex
opencode/kimi-k2
openrouter/google/gemini-2.5-flash
```

View file

@ -0,0 +1,14 @@
---
description: translate English to other languages
model: opencode/claude-opus-4-7
---
run git diff and translate changed english doc and UI copy files to other international languages. Translate all languages in parallel to save time.
Requirements:
- Preserve meaning, intent, tone, and formatting (including Markdown/MDX structure).
- Preserve all technical terms and artifacts exactly: product/company names, API names, identifiers, code, commands/flags, file paths, URLs, versions, error messages, config keys/values, and anything inside inline code or code blocks.
- Also preserve every term listed in the Do-Not-Translate glossary below.
- Also apply locale-specific guidance from `.opencode/glossary/<locale>.md` when available (for example, `zh-cn.md`).
- Do not modify fenced code blocks.

View file

@ -3,8 +3,8 @@ import { tool } from "@opencode-ai/plugin"
const TEAM = {
desktop: ["adamdotdevin", "iamdavidhill", "Brendonovich", "nexxeln"],
zen: ["fwang", "MrMushrooooom"],
tui: ["thdxr", "kommander", "rekram1-node"],
core: ["thdxr", "rekram1-node", "jlongster"],
tui: ["kommander", "rekram1-node", "simonklee"],
core: ["kitlangton", "rekram1-node", "jlongster"],
docs: ["R44VC0RP"],
windows: ["Hona"],
} as const

View file

@ -29,7 +29,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
@ -83,7 +83,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@ -117,7 +117,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@ -144,7 +144,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@ai-sdk/anthropic": "3.0.64",
"@ai-sdk/openai": "3.0.48",
@ -168,7 +168,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@ -192,7 +192,7 @@
},
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.14.25",
"version": "1.14.26",
"bin": {
"opencode": "./bin/opencode",
},
@ -226,7 +226,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@opencode-ai/app": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@ -259,7 +259,7 @@
},
"packages/desktop-electron": {
"name": "@opencode-ai/desktop-electron",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
@ -303,7 +303,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@ -332,7 +332,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@ -348,7 +348,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.14.25",
"version": "1.14.26",
"bin": {
"opencode": "./bin/opencode",
},
@ -393,7 +393,7 @@
"@opencode-ai/plugin": "workspace:*",
"@opencode-ai/script": "workspace:*",
"@opencode-ai/sdk": "workspace:*",
"@openrouter/ai-sdk-provider": "2.5.1",
"@openrouter/ai-sdk-provider": "2.8.1",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/context-async-hooks": "2.6.1",
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
@ -491,7 +491,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"effect": "catalog:",
@ -506,8 +506,8 @@
"typescript": "catalog:",
},
"peerDependencies": {
"@opentui/core": ">=0.1.103",
"@opentui/solid": ">=0.1.103",
"@opentui/core": ">=0.1.104",
"@opentui/solid": ">=0.1.104",
},
"optionalPeers": [
"@opentui/core",
@ -526,7 +526,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"cross-spawn": "catalog:",
},
@ -541,7 +541,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@ -576,7 +576,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
@ -625,7 +625,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@ -685,8 +685,8 @@
"@npmcli/arborist": "9.4.0",
"@octokit/rest": "22.0.0",
"@openauthjs/openauth": "0.0.0-20250322224806",
"@opentui/core": "0.1.103",
"@opentui/solid": "0.1.103",
"@opentui/core": "0.1.104",
"@opentui/solid": "0.1.104",
"@pierre/diffs": "1.1.0-beta.18",
"@playwright/test": "1.59.1",
"@solid-primitives/storage": "4.3.3",
@ -1585,7 +1585,7 @@
"@opencode-ai/web": ["@opencode-ai/web@workspace:packages/web"],
"@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@2.5.1", "", { "peerDependencies": { "ai": "^6.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-r1fJL1Cb3gQDa2MpWH/sfx1BsEW0uzlRriJM6eihaKqbtKDmZoBisF32VcVaQYassighX7NGCkF68EsrZA43uQ=="],
"@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@2.8.1", "", { "peerDependencies": { "ai": "^6.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Y6j3yivgoEUf/kutD/k5GX/mzZfioRFoSx0gbQ+mIOzMaH/vJv1rCkztiuvlLw5xRYQil7oxHUZvmSfXqOx1NQ=="],
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
@ -1613,21 +1613,21 @@
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
"@opentui/core": ["@opentui/core@0.1.103", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.103", "@opentui/core-darwin-x64": "0.1.103", "@opentui/core-linux-arm64": "0.1.103", "@opentui/core-linux-x64": "0.1.103", "@opentui/core-win32-arm64": "0.1.103", "@opentui/core-win32-x64": "0.1.103", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-PWVv/bDmlk1i6X1f0zXs+jSaTrQ/ByX8wFbP2WinOObTGf//UbcRP4dbWxPXvOyka9QlmRBG/7GbloQSIStyVw=="],
"@opentui/core": ["@opentui/core@0.1.104", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.104", "@opentui/core-darwin-x64": "0.1.104", "@opentui/core-linux-arm64": "0.1.104", "@opentui/core-linux-x64": "0.1.104", "@opentui/core-win32-arm64": "0.1.104", "@opentui/core-win32-x64": "0.1.104", "bun-webgpu": "0.1.5", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-29RZ+f7sw5B6ebDFRuhrDs2UOV7vR76npr0vVRAJAmIMtdLb4Dse35Y0Hk6WerFKNuX4ajlQK4eO3oAY/29KLQ=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.103", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lxCyedDkcen12IgBtXjkJ7iY66xa7VC4nxRNKCUeLY2ZP9hUE1AsDtbyQzqY+BQadsI/ZME9STzaHDCUFg0TpA=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.104", "", { "os": "darwin", "cpu": "arm64" }, "sha512-83Bf+LOLYCgWccAuPzftchs8LIoTzYU8f8CM7GeUFqH0VLKs2Ey+TtCTsBWpeDklOal0XFQr5begotqc/ldPVg=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.103", "", { "os": "darwin", "cpu": "x64" }, "sha512-QMYD+zUDGQliJ6m5nuNvA72jtluFeyVMoHkuA5m/Xmed/u8eLfahAKmDj3kY66ntUroPHWevcpbpvd7NCFEoFQ=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.104", "", { "os": "darwin", "cpu": "x64" }, "sha512-TAHRtEi7Gz2O3TXolPCiWpXsoapKllGCl74bOuJsyipMwfk3wuUu6SeqBPC/cmVJlp143dC8kcGLwLsd3dxsgA=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.103", "", { "os": "linux", "cpu": "arm64" }, "sha512-GzOvNr9dN6JaQ9qs7m8E75wLAHwT5CyxqkE6rEr1BO23/d2Ix7e3GYw/JRY5VnTge+eXrfDVbqNtPcQamUNiEA=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.104", "", { "os": "linux", "cpu": "arm64" }, "sha512-WJ8ssxcRpoHWgGLDYlVjlYZGkmA2G9melgXTrzk6CbwhW5tVAE6AmW5Kq9DUHclYssCpNWTvZFMDsVsf5kn2Xw=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.103", "", { "os": "linux", "cpu": "x64" }, "sha512-odywllco5zUKNc60uD3JKaCybK64u6BfmpScs4a8Qn89yH/yk23bzWXDRWaGgQdY65L2/VCbcGs1ezA1S/2YTw=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.104", "", { "os": "linux", "cpu": "x64" }, "sha512-I4DurCkJXJxxGwAq1wGZ1vzXh57GxdzljWeCJ5sIPy7coICn+/cWRw9gE9VxiWTa3T85l4YN0UFSQx7IFCEbvg=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.103", "", { "os": "win32", "cpu": "arm64" }, "sha512-tZL5w3Y0JnO7RkIvfuNDAzJn0j6+JIYl6M8DgPM5p8AQt+162S8LmbumzmqQLZl4cEev2eN7/tw72WIk6b+/CQ=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.104", "", { "os": "win32", "cpu": "arm64" }, "sha512-PDwqGHlVUiAiZa8GXiPPJVWIxucQ5+2FLcK4C76VT8HJzUXiUEGJFtuvi9oY7k29p8olcFHW75Gj1WMUrw+JKw=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.103", "", { "os": "win32", "cpu": "x64" }, "sha512-wqnibt/OE5ldSzVPxEbriA0TjI2B11CJl4uJoLxTZ47KDx7tAFIMdhBf9IRAGNCSbcDuZ8ZGEFhV+SLaftkrlw=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.104", "", { "os": "win32", "cpu": "x64" }, "sha512-fQGMxFshk/i7KskqaK5lB8u2K8Lx/LO9+PdfKu/+GBIMKmElpJXQ8Bq2sMf+7COcoXcjAjUJn8cpTyIqbFxAyQ=="],
"@opentui/solid": ["@opentui/solid@0.1.103", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.103", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-L28WFBs17Z5JXkJhPagLy8tUamkttDaaQDdb2KEO01IQ9r81yLBRpYqD/lHp6UoSISXgwQVDQ9yNtxwR1BQZvQ=="],
"@opentui/solid": ["@opentui/solid@0.1.104", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.104", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.10", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.11" } }, "sha512-Mma1OR3s0QZayRGdbdNv1m3H6IExRrF9QRUNWEZzDOqo3oNxTxaY9K7Qk6eGrk0unMjwwE113TSOdnG80RwYnQ=="],
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
@ -5723,6 +5723,8 @@
"ai-gateway-provider/@ai-sdk/xai": ["@ai-sdk/xai@3.0.75", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.37", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-V8UKK4fNpI9cnrtsZBvUp9O9J6Y9fTKBRoSLyEaNGPirACewixmLDbXsSgAeownPVWiWpK34bFysd+XouI5Ywg=="],
"ai-gateway-provider/@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@2.5.1", "", { "peerDependencies": { "ai": "^6.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-r1fJL1Cb3gQDa2MpWH/sfx1BsEW0uzlRriJM6eihaKqbtKDmZoBisF32VcVaQYassighX7NGCkF68EsrZA43uQ=="],
"ajv-keywords/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
"ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],

View file

@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-LpzWEZzURUEj7fcHGvh33gM7D9GNPE+XIvU0/hmdcQM=",
"aarch64-linux": "sha256-0zdO3zuj6g9cMZFEOsvQJcKKcPjGVZJ2DkJdDcb2VCM=",
"aarch64-darwin": "sha256-dmT8R9Pmzh5tjO8NCCCtENiQpJQeifQpVdhaty1MXOs=",
"x86_64-darwin": "sha256-Q6rAQRoC6WaMAQl++YHAZmbNuO303cWgGaYzXaRlzy4="
"x86_64-linux": "sha256-zQOuZkuOLm9xV5YzfcQiWSzvussXVw/dRPw4HhuYsdc=",
"aarch64-linux": "sha256-J8Ak9rCCkKlBj0KhdUOklglpR3ntRP2VjtdmEJox6Ro=",
"aarch64-darwin": "sha256-r4F6S9CfGR6qxSaSqu9AIjWCEKd/PuT1Wprcbzk0IwY=",
"x86_64-darwin": "sha256-I/ztb7VnLbJYzAxf2egN0+YsJcP5yix3tIoHtiuRUXE="
}
}

View file

@ -64,7 +64,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
[
ripgrep
]
# bun runs sysctl to detect if dunning on rosetta2
# bun runs sysctl to detect if running on rosetta2
++ lib.optional stdenvNoCC.hostPlatform.isDarwin sysctl
)
}

View file

@ -34,8 +34,8 @@
"@types/cross-spawn": "6.0.6",
"@octokit/rest": "22.0.0",
"@hono/zod-validator": "0.4.2",
"@opentui/core": "0.1.103",
"@opentui/solid": "0.1.103",
"@opentui/core": "0.1.104",
"@opentui/solid": "0.1.104",
"ulid": "3.0.1",
"@kobalte/core": "0.13.11",
"@types/luxon": "3.7.1",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.14.25",
"version": "1.14.26",
"description": "",
"type": "module",
"exports": {

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.14.25",
"version": "1.14.26",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -0,0 +1,10 @@
import type { APIEvent } from "@solidjs/start/server"
import { getHandler, optionsHandler } from "../../util/modelsHandler"
export async function OPTIONS(_input: APIEvent) {
return optionsHandler()
}
export async function GET(input: APIEvent) {
return getHandler({ modelList: "lite" })
}

View file

@ -101,12 +101,13 @@ export async function handler(
const requestId = input.request.headers.get("x-opencode-request") ?? ""
const projectId = input.request.headers.get("x-opencode-project") ?? ""
const ocClient = input.request.headers.get("x-opencode-client") ?? ""
const userAgent = input.request.headers.get("user-agent") ?? ""
logger.metric({
is_stream: isStream,
session: sessionId,
request: requestId,
client: ocClient,
...(model === "mimo-v2-pro-free" && JSON.stringify(body).length < 1000 ? { payload: JSON.stringify(body) } : {}),
user_agent: userAgent,
})
const zenData = ZenData.list(opts.modelList)
const modelInfo = validateModel(zenData, model)

View file

@ -0,0 +1,36 @@
import { ZenData } from "@opencode-ai/console-core/model.js"
export async function optionsHandler() {
return new Response(null, {
status: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
})
}
export async function getHandler(opts: { modelList: "lite" | "full"; disabledModels?: string[] }) {
const zenData = ZenData.list(opts.modelList)
return new Response(
JSON.stringify({
object: "list",
data: Object.entries(zenData.models)
.filter(([id]) => !opts.disabledModels?.includes(id))
.filter(([id]) => !id.startsWith("alpha-"))
.map(([id, _model]) => ({
id,
object: "model",
created: Math.floor(Date.now() / 1000),
owned_by: "opencode",
})),
}),
{
headers: {
"Content-Type": "application/json",
},
},
)
}

View file

@ -3,59 +3,29 @@ import { and, Database, eq, isNull } from "@opencode-ai/console-core/drizzle/ind
import { KeyTable } from "@opencode-ai/console-core/schema/key.sql.js"
import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js"
import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js"
import { ZenData } from "@opencode-ai/console-core/model.js"
import { optionsHandler, getHandler } from "~/routes/zen/util/modelsHandler"
export async function OPTIONS(_input: APIEvent) {
return new Response(null, {
status: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
})
return optionsHandler()
}
export async function GET(input: APIEvent) {
const zenData = ZenData.list("full")
const disabledModels = await authenticate()
return new Response(
JSON.stringify({
object: "list",
data: Object.entries(zenData.models)
.filter(([id]) => !disabledModels.includes(id))
.filter(([id]) => !id.startsWith("alpha-"))
.map(([id, _model]) => ({
id,
object: "model",
created: Math.floor(Date.now() / 1000),
owned_by: "opencode",
})),
}),
{
headers: {
"Content-Type": "application/json",
},
},
)
async function authenticate() {
const disabledModels = await (() => {
const apiKey = input.request.headers.get("authorization")?.split(" ")[1]
if (!apiKey) return []
const disabledModels = await Database.use((tx) =>
return Database.use((tx) =>
tx
.select({
model: ModelTable.model,
})
.from(KeyTable)
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
.leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)))
.innerJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)))
.where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted)))
.then((rows) => rows.map((row) => row.model)),
)
})()
return disabledModels
}
return getHandler({ modelList: "full", disabledModels })
}

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.14.25",
"version": "1.14.26",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.14.25",
"version": "1.14.26",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.14.25",
"version": "1.14.26",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.14.25",
"version": "1.14.26",
"name": "@opencode-ai/core",
"type": "module",
"license": "MIT",

View file

@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop-electron",
"private": true,
"version": "1.14.25",
"version": "1.14.26",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",

View file

@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.14.25",
"version": "1.14.26",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.14.25",
"version": "1.14.26",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,7 +1,7 @@
id = "opencode"
name = "OpenCode"
description = "The open source coding agent."
version = "1.14.25"
version = "1.14.26"
schema_version = 1
authors = ["Anomaly"]
repository = "https://github.com/anomalyco/opencode"
@ -11,26 +11,26 @@ name = "OpenCode"
icon = "./icons/opencode.svg"
[agent_servers.opencode.targets.darwin-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.25/opencode-darwin-arm64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.26/opencode-darwin-arm64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.darwin-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.25/opencode-darwin-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.26/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.25/opencode-linux-arm64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.26/opencode-linux-arm64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.25/opencode-linux-x64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.26/opencode-linux-x64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.windows-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.25/opencode-windows-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.14.26/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.14.25",
"version": "1.14.26",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.14.25",
"version": "1.14.26",
"name": "opencode",
"type": "module",
"license": "MIT",
@ -115,7 +115,7 @@
"@opencode-ai/plugin": "workspace:*",
"@opencode-ai/script": "workspace:*",
"@opencode-ai/sdk": "workspace:*",
"@openrouter/ai-sdk-provider": "2.5.1",
"@openrouter/ai-sdk-provider": "2.8.1",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/context-async-hooks": "2.6.1",
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",

View file

@ -170,23 +170,23 @@ Use raw Effect HTTP routes where `HttpApi` does not fit. The goal is deleting Ho
## Current Route Status
| Area | Status | Notes |
| ------------------------- | ----------------- | -------------------------------------------------------------------------------------------------- |
| `question` | `bridged` | `GET /question`, reply, reject |
| `permission` | `bridged` | list and reply |
| `provider` | `bridged` | list, auth, OAuth authorize/callback |
| `config` | `bridged` | read, providers, update |
| `project` | `bridged` | list, current, git init, update |
| `file` | `bridged` partial | find text/file/symbol, list/content/status |
| `mcp` | `bridged` | status, add, OAuth, connect/disconnect |
| `workspace` | `bridged` partial | adaptor/list/status; create/remove/session-restore remain |
| top-level instance routes | `bridged` | path, vcs, command, agent, skill, lsp, formatter, dispose |
| experimental JSON routes | `bridged` partial | console reads, tool ids, worktree list/mutations, resource list; global session list remains later |
| `session` | `later/special` | large stateful surface plus streaming |
| `sync` | `later` | process/control side effects |
| `event` | `special` | SSE |
| `pty` | `special` | websocket |
| `tui` | `special` | UI bridge |
| Area | Status | Notes |
| ------------------------- | ----------------- | -------------------------------------------------------------------------- |
| `question` | `bridged` | `GET /question`, reply, reject |
| `permission` | `bridged` | list and reply |
| `provider` | `bridged` | list, auth, OAuth authorize/callback |
| `config` | `bridged` | read, providers, update |
| `project` | `bridged` | list, current, git init, update |
| `file` | `bridged` partial | find text/file/symbol, list/content/status |
| `mcp` | `bridged` | status, add, OAuth, connect/disconnect |
| `workspace` | `bridged` | adaptor/list/status/create/remove/session-restore |
| top-level instance routes | `bridged` | path, vcs, command, agent, skill, lsp, formatter, dispose |
| experimental JSON routes | `bridged` | console, tool, worktree list/mutations, global session list, resource list |
| `session` | `bridged` | read, lifecycle, prompt, message/part mutations, revert, permission reply |
| `sync` | `bridged` | start/replay/history |
| `event` | `special` | SSE |
| `pty` | `special` | websocket |
| `tui` | `special` | UI bridge |
## Full Route Checklist
@ -259,60 +259,60 @@ This checklist tracks bridge parity only. Checked routes are available through t
- [x] `GET /experimental/console` - active Console provider metadata.
- [x] `GET /experimental/console/orgs` - switchable Console orgs.
- [ ] `POST /experimental/console/switch` - switch active Console org.
- [x] `POST /experimental/console/switch` - switch active Console org.
- [x] `GET /experimental/tool/ids` - tool IDs.
- [ ] `GET /experimental/tool` - tools for provider/model.
- [x] `GET /experimental/tool` - tools for provider/model.
- [x] `GET /experimental/worktree` - list worktrees.
- [x] `POST /experimental/worktree` - create worktree.
- [x] `DELETE /experimental/worktree` - remove worktree.
- [x] `POST /experimental/worktree/reset` - reset worktree.
- [ ] `GET /experimental/session` - global session list.
- [x] `GET /experimental/session` - global session list.
- [x] `GET /experimental/resource` - MCP resources.
### Workspace Routes
- [x] `GET /experimental/workspace/adaptor` - list workspace adaptors.
- [ ] `POST /experimental/workspace` - create workspace.
- [x] `POST /experimental/workspace` - create workspace.
- [x] `GET /experimental/workspace` - list workspaces.
- [x] `GET /experimental/workspace/status` - workspace status.
- [ ] `DELETE /experimental/workspace/:id` - remove workspace.
- [ ] `POST /experimental/workspace/:id/session-restore` - restore session into workspace.
- [x] `DELETE /experimental/workspace/:id` - remove workspace.
- [x] `POST /experimental/workspace/:id/session-restore` - restore session into workspace.
### Sync Routes
- [ ] `POST /sync/start` - start workspace sync.
- [ ] `POST /sync/replay` - replay sync events.
- [ ] `POST /sync/history` - list sync event history.
- [x] `POST /sync/start` - start workspace sync.
- [x] `POST /sync/replay` - replay sync events.
- [x] `POST /sync/history` - list sync event history.
### Session Routes
- [ ] `GET /session` - list sessions.
- [ ] `GET /session/status` - session status map.
- [ ] `GET /session/:sessionID` - get session.
- [ ] `GET /session/:sessionID/children` - get child sessions.
- [ ] `GET /session/:sessionID/todo` - get session todos.
- [ ] `POST /session` - create session.
- [ ] `DELETE /session/:sessionID` - delete session.
- [ ] `PATCH /session/:sessionID` - update session metadata.
- [ ] `POST /session/:sessionID/init` - run project init command.
- [ ] `POST /session/:sessionID/fork` - fork session.
- [ ] `POST /session/:sessionID/abort` - abort session.
- [ ] `POST /session/:sessionID/share` - share session.
- [ ] `GET /session/:sessionID/diff` - session diff.
- [ ] `DELETE /session/:sessionID/share` - unshare session.
- [ ] `POST /session/:sessionID/summarize` - summarize session.
- [ ] `GET /session/:sessionID/message` - list session messages.
- [ ] `GET /session/:sessionID/message/:messageID` - get message.
- [ ] `DELETE /session/:sessionID/message/:messageID` - delete message.
- [ ] `DELETE /session/:sessionID/message/:messageID/part/:partID` - delete part.
- [ ] `PATCH /session/:sessionID/message/:messageID/part/:partID` - update part.
- [ ] `POST /session/:sessionID/message` - prompt with streaming response.
- [ ] `POST /session/:sessionID/prompt_async` - async prompt.
- [ ] `POST /session/:sessionID/command` - run command.
- [ ] `POST /session/:sessionID/shell` - run shell command.
- [ ] `POST /session/:sessionID/revert` - revert message.
- [ ] `POST /session/:sessionID/unrevert` - restore reverted messages.
- [ ] `POST /session/:sessionID/permissions/:permissionID` - deprecated permission response route.
- [x] `GET /session` - list sessions.
- [x] `GET /session/status` - session status map.
- [x] `GET /session/:sessionID` - get session.
- [x] `GET /session/:sessionID/children` - get child sessions.
- [x] `GET /session/:sessionID/todo` - get session todos.
- [x] `POST /session` - create session.
- [x] `DELETE /session/:sessionID` - delete session.
- [x] `PATCH /session/:sessionID` - update session metadata.
- [x] `POST /session/:sessionID/init` - run project init command.
- [x] `POST /session/:sessionID/fork` - fork session.
- [x] `POST /session/:sessionID/abort` - abort session.
- [x] `POST /session/:sessionID/share` - share session.
- [x] `GET /session/:sessionID/diff` - session diff.
- [x] `DELETE /session/:sessionID/share` - unshare session.
- [x] `POST /session/:sessionID/summarize` - summarize session.
- [x] `GET /session/:sessionID/message` - list session messages.
- [x] `GET /session/:sessionID/message/:messageID` - get message.
- [x] `DELETE /session/:sessionID/message/:messageID` - delete message.
- [x] `DELETE /session/:sessionID/message/:messageID/part/:partID` - delete part.
- [x] `PATCH /session/:sessionID/message/:messageID/part/:partID` - update part.
- [x] `POST /session/:sessionID/message` - prompt with streaming response.
- [x] `POST /session/:sessionID/prompt_async` - async prompt.
- [x] `POST /session/:sessionID/command` - run command.
- [x] `POST /session/:sessionID/shell` - run shell command.
- [x] `POST /session/:sessionID/revert` - revert message.
- [x] `POST /session/:sessionID/unrevert` - restore reverted messages.
- [x] `POST /session/:sessionID/permissions/:permissionID` - deprecated permission response route.
### Event Routes
@ -350,13 +350,13 @@ Prefer smaller PRs from here so route behavior and SDK/OpenAPI fallout stays rev
1. [x] Bridge `PATCH /project/:projectID`.
2. [x] Bridge MCP add/connect/disconnect routes.
3. [x] Bridge MCP OAuth routes: start, callback, authenticate, remove.
4. [ ] Bridge experimental console switch and tool list routes.
5. [ ] Bridge experimental global session list.
6. [ ] Bridge workspace create/remove/session-restore routes.
7. [ ] Bridge sync start/replay/history routes.
8. [ ] Bridge session read routes: list, status, get, children, todo, diff, messages.
9. [ ] Bridge session lifecycle mutation routes: create, delete, update, fork, abort.
10. [ ] Bridge session share/summary/message/part mutation routes.
4. [x] Bridge experimental console switch and tool list routes.
5. [x] Bridge experimental global session list.
6. [x] Bridge workspace create/remove/session-restore routes.
7. [x] Bridge sync start/replay/history routes.
8. [x] Bridge session read routes: list, status, get, children, todo, diff, messages.
9. [x] Bridge session lifecycle mutation routes: create, delete, update, fork, abort.
10. [x] Bridge remaining session mutation and prompt routes.
11. [ ] Replace event SSE with non-Hono Effect HTTP.
12. [ ] Replace pty websocket/control routes with non-Hono Effect HTTP.
13. [ ] Replace tui bridge routes or explicitly isolate them behind a non-Hono compatibility layer.

View file

@ -278,12 +278,16 @@ function resolveEditorLockFile() {
}
const cwd = process.cwd()
// longest workspace folder that contains cwd; 0 if none match
const bestMatchLength = (lock: EditorLockFile) =>
Math.max(0, ...lock.workspaceFolders.map((folder) => pathContainsLength(folder, cwd)))
const locks = entries
.filter((entry) => entry.endsWith(".lock"))
.map((entry) => readEditorLockFile(path.join(directory, entry)))
.filter((entry): entry is EditorLockFile => Boolean(entry))
.sort((left, right) => scoreEditorLock(right, cwd) - scoreEditorLock(left, cwd))
.filter((entry) => bestMatchLength(entry) > 0)
// prefer locks with longer matching workspace folders, then more recent ones
.sort((left, right) => bestMatchLength(right) - bestMatchLength(left) || right.mtimeMs - left.mtimeMs)
return locks[0]
}
@ -310,11 +314,6 @@ function readEditorLockFile(filePath: string): EditorLockFile | undefined {
}
}
function scoreEditorLock(lock: EditorLockFile, cwd: string) {
const workspaceMatch = lock.workspaceFolders.some((folder) => pathContains(folder, cwd)) ? 1 : 0
return workspaceMatch * 1_000_000_000_000 + lock.mtimeMs
}
function editorSelectionKey(selection: EditorSelection | undefined) {
if (!selection) return ""
return [
@ -327,9 +326,10 @@ function editorSelectionKey(selection: EditorSelection | undefined) {
].join("\0")
}
function pathContains(parent: string, child: string) {
const relative = path.relative(path.resolve(parent), path.resolve(child))
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative))
function pathContainsLength(parent: string, child: string) {
const resolved = path.resolve(parent)
const relative = path.relative(resolved, path.resolve(child))
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative)) ? resolved.length : 0
}
function openEditorSocket(connection: EditorConnection) {

View file

@ -1,6 +1,8 @@
import { BusEvent } from "@/bus/bus-event"
import { SessionID } from "@/session/schema"
import { Schema } from "effect"
import { Effect, Schema } from "effect"
const DEFAULT_TOAST_DURATION = 5000
export const TuiEvent = {
PromptAppend: BusEvent.define("tui.prompt.append", Schema.Struct({ text: Schema.String })),
@ -36,7 +38,9 @@ export const TuiEvent = {
title: Schema.optional(Schema.String),
message: Schema.String,
variant: Schema.Literals(["info", "success", "warning", "error"]),
duration: Schema.optional(Schema.Number).annotate({ description: "Duration in milliseconds" }),
duration: Schema.Number.pipe(Schema.withDecodingDefault(Effect.succeed(DEFAULT_TOAST_DURATION))).annotate({
description: "Duration in milliseconds",
}),
}),
),
SessionSelect: BusEvent.define(

View file

@ -5,10 +5,13 @@ import { useTerminalDimensions } from "@opentui/solid"
import { SplitBorder } from "../component/border"
import { TextAttributes } from "@opentui/core"
import { Schema } from "effect"
import { type TuiEvent } from "../event"
import { TuiEvent } from "../event"
type ToastInput = Schema.Codec.Encoded<typeof TuiEvent.ToastShow.properties>
export type ToastOptions = Schema.Schema.Type<typeof TuiEvent.ToastShow.properties>
const decodeToastOptions = Schema.decodeUnknownSync(TuiEvent.ToastShow.properties)
export function Toast() {
const toast = useToast()
const { theme } = useTheme()
@ -55,13 +58,13 @@ function init() {
let timeoutHandle: NodeJS.Timeout | null = null
const toast = {
show(options: ToastOptions) {
const { duration, ...currentToast } = options
setStore("currentToast", currentToast)
show(options: ToastInput) {
const toastOptions = decodeToastOptions(options)
setStore("currentToast", toastOptions)
if (timeoutHandle) clearTimeout(timeoutHandle)
timeoutHandle = setTimeout(() => {
setStore("currentToast", null)
}, duration).unref()
}, toastOptions.duration).unref()
},
error: (err: any) => {
if (err instanceof Error)

View file

@ -1,5 +1,4 @@
export * as Editor from "./editor"
export * as Selection from "./selection"
export * as Sound from "./sound"
export * as Terminal from "./terminal"
export * as Clipboard from "./clipboard"

View file

@ -1,96 +0,0 @@
import { RGBA } from "@opentui/core"
export type Colors = Awaited<ReturnType<typeof colors>>
function parse(color: string): RGBA | null {
if (color.startsWith("rgb:")) {
const parts = color.substring(4).split("/")
return RGBA.fromInts(parseInt(parts[0], 16) >> 8, parseInt(parts[1], 16) >> 8, parseInt(parts[2], 16) >> 8, 255)
}
if (color.startsWith("#")) {
return RGBA.fromHex(color)
}
if (color.startsWith("rgb(")) {
const parts = color.substring(4, color.length - 1).split(",")
return RGBA.fromInts(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]), 255)
}
return null
}
/**
* Query terminal colors including background, foreground, and palette (0-15).
* Uses OSC escape sequences to retrieve actual terminal color values.
*
* Note: OSC 4 (palette) queries may not work through tmux as responses are filtered.
* OSC 10/11 (foreground/background) typically work in most environments.
*
* Returns an object with background, foreground, and colors array.
* Any query that fails will be null/empty.
*/
export async function colors(): Promise<{
background: RGBA | null
foreground: RGBA | null
colors: RGBA[]
}> {
if (!process.stdin.isTTY) return { background: null, foreground: null, colors: [] }
return new Promise((resolve) => {
let background: RGBA | null = null
let foreground: RGBA | null = null
const paletteColors: RGBA[] = []
let timeout: NodeJS.Timeout
const cleanup = () => {
process.stdin.setRawMode(false)
process.stdin.removeListener("data", handler)
clearTimeout(timeout)
}
const handler = (data: Buffer) => {
const str = data.toString()
// Match OSC 11 (background color)
const bgMatch = str.match(/\x1b]11;([^\x07\x1b]+)/)
if (bgMatch) {
background = parse(bgMatch[1])
}
// Match OSC 10 (foreground color)
const fgMatch = str.match(/\x1b]10;([^\x07\x1b]+)/)
if (fgMatch) {
foreground = parse(fgMatch[1])
}
// Match OSC 4 (palette colors)
const paletteMatches = str.matchAll(/\x1b]4;(\d+);([^\x07\x1b]+)/g)
for (const match of paletteMatches) {
const index = parseInt(match[1])
const color = parse(match[2])
if (color) paletteColors[index] = color
}
// Return immediately if we have all 16 palette colors
if (paletteColors.filter((c) => c !== undefined).length === 16) {
cleanup()
resolve({ background, foreground, colors: paletteColors })
}
}
process.stdin.setRawMode(true)
process.stdin.on("data", handler)
// Query background (OSC 11)
process.stdout.write("\x1b]11;?\x07")
// Query foreground (OSC 10)
process.stdout.write("\x1b]10;?\x07")
// Query palette colors 0-15 (OSC 4)
for (let i = 0; i < 16; i++) {
process.stdout.write(`\x1b]4;${i};?\x07`)
}
timeout = setTimeout(() => {
cleanup()
resolve({ background, foreground, colors: paletteColors })
}, 1000)
})
}

View file

@ -193,7 +193,11 @@ function normalizeMessages(
})
}
if (typeof model.capabilities.interleaved === "object" && model.capabilities.interleaved.field) {
if (
typeof model.capabilities.interleaved === "object" &&
model.capabilities.interleaved.field &&
model.api.npm !== "@openrouter/ai-sdk-provider"
) {
const field = model.capabilities.interleaved.field
return msgs.map((msg) => {
if (msg.role === "assistant" && Array.isArray(msg.content)) {

View file

@ -1,12 +1,18 @@
import { Account } from "@/account/account"
import { AccountID, OrgID } from "@/account/schema"
import { Agent } from "@/agent/agent"
import { Config } from "@/config"
import { InstanceState } from "@/effect"
import { MCP } from "@/mcp"
import { Project } from "@/project"
import { ProviderID, ModelID } from "@/provider/schema"
import { Session } from "@/session"
import { ToolRegistry } from "@/tool"
import * as EffectZod from "@/util/effect-zod"
import { Worktree } from "@/worktree"
import { Effect, Layer, Option, Schema } from "effect"
import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse"
import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiError, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
import { Authorization } from "./auth"
const ConsoleStateResponse = Schema.Struct({
@ -28,16 +34,43 @@ const ConsoleOrgList = Schema.Struct({
orgs: Schema.Array(ConsoleOrgOption),
}).annotate({ identifier: "ConsoleOrgList" })
const ConsoleSwitchPayload = Schema.Struct({
accountID: AccountID,
orgID: OrgID,
}).annotate({ identifier: "ConsoleSwitchInput" })
const ToolIDs = Schema.Array(Schema.String).annotate({ identifier: "ToolIDs" })
const ToolListItem = Schema.Struct({
id: Schema.String,
description: Schema.String,
parameters: Schema.Record(Schema.String, Schema.Any),
}).annotate({ identifier: "ToolListItem" })
const ToolList = Schema.Array(ToolListItem).annotate({ identifier: "ToolList" })
const ToolListQuery = Schema.Struct({
provider: ProviderID,
model: ModelID,
})
const WorktreeList = Schema.Array(Schema.String).annotate({ identifier: "WorktreeList" })
const SessionListQuery = Schema.Struct({
directory: Schema.optional(Schema.String),
roots: Schema.optional(Schema.Literals(["true", "false"])),
start: Schema.optional(Schema.NumberFromString),
cursor: Schema.optional(Schema.NumberFromString),
search: Schema.optional(Schema.String),
limit: Schema.optional(Schema.NumberFromString),
archived: Schema.optional(Schema.Literals(["true", "false"])),
})
export const ExperimentalPaths = {
console: "/experimental/console",
consoleOrgs: "/experimental/console/orgs",
consoleSwitch: "/experimental/console/switch",
tool: "/experimental/tool",
toolIDs: "/experimental/tool/ids",
worktree: "/experimental/worktree",
worktreeReset: "/experimental/worktree/reset",
session: "/experimental/session",
resource: "/experimental/resource",
} as const
@ -63,6 +96,27 @@ export const ExperimentalApi = HttpApi.make("experimental")
description: "Get the available Console orgs across logged-in accounts, including the current active org.",
}),
),
HttpApiEndpoint.post("consoleSwitch", ExperimentalPaths.consoleSwitch, {
payload: ConsoleSwitchPayload,
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "experimental.console.switchOrg",
summary: "Switch active Console org",
description: "Persist a new active Console account/org selection for the current local OpenCode state.",
}),
),
HttpApiEndpoint.get("tool", ExperimentalPaths.tool, {
query: ToolListQuery,
success: ToolList,
}).annotateMerge(
OpenApi.annotations({
identifier: "tool.list",
summary: "List tools",
description:
"Get a list of available tools with their JSON schema parameters for a specific provider and model combination.",
}),
),
HttpApiEndpoint.get("toolIDs", ExperimentalPaths.toolIDs, {
success: ToolIDs,
}).annotateMerge(
@ -112,6 +166,17 @@ export const ExperimentalApi = HttpApi.make("experimental")
description: "Reset a worktree branch to the primary default branch.",
}),
),
HttpApiEndpoint.get("session", ExperimentalPaths.session, {
query: SessionListQuery,
success: Schema.Array(Session.GlobalInfo),
}).annotateMerge(
OpenApi.annotations({
identifier: "experimental.session.list",
summary: "List sessions",
description:
"Get a list of all OpenCode sessions across projects, sorted by most recently updated. Archived sessions are excluded by default.",
}),
),
HttpApiEndpoint.get("resource", ExperimentalPaths.resource, {
success: Schema.Record(Schema.String, MCP.Resource),
}).annotateMerge(
@ -141,6 +206,7 @@ export const ExperimentalApi = HttpApi.make("experimental")
export const experimentalHandlers = Layer.unwrap(
Effect.gen(function* () {
const account = yield* Account.Service
const agents = yield* Agent.Service
const config = yield* Config.Service
const mcp = yield* MCP.Service
const project = yield* Project.Service
@ -183,6 +249,28 @@ export const experimentalHandlers = Layer.unwrap(
}
})
const switchConsole = Effect.fn("ExperimentalHttpApi.consoleSwitch")(function* (ctx: {
payload: typeof ConsoleSwitchPayload.Type
}) {
yield* account
.use(ctx.payload.accountID, Option.some(ctx.payload.orgID))
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
return true
})
const tool = Effect.fn("ExperimentalHttpApi.tool")(function* (ctx: { query: typeof ToolListQuery.Type }) {
const list = yield* registry.tools({
providerID: ctx.query.provider,
modelID: ctx.query.model,
agent: yield* agents.get(yield* agents.defaultAgent()),
})
return list.map((item) => ({
id: item.id,
description: item.description,
parameters: EffectZod.toJsonSchema(item.parameters),
}))
})
const toolIDs = Effect.fn("ExperimentalHttpApi.toolIDs")(function* () {
return yield* registry.ids()
})
@ -214,6 +302,28 @@ export const experimentalHandlers = Layer.unwrap(
return true
})
const session = Effect.fn("ExperimentalHttpApi.session")(function* (ctx: { query: typeof SessionListQuery.Type }) {
const limit = ctx.query.limit ?? 100
const sessions = Array.from(
Session.listGlobal({
directory: ctx.query.directory,
roots: ctx.query.roots === "true" ? true : undefined,
start: ctx.query.start,
cursor: ctx.query.cursor,
search: ctx.query.search,
limit: limit + 1,
archived: ctx.query.archived === "true" ? true : undefined,
}),
)
const list = sessions.length > limit ? sessions.slice(0, limit) : sessions
return HttpServerResponse.jsonUnsafe(list, {
headers:
sessions.length > limit && list.length > 0
? { "x-next-cursor": String(list[list.length - 1].time.updated) }
: undefined,
})
})
const resource = Effect.fn("ExperimentalHttpApi.resource")(function* () {
return yield* mcp.resources()
})
@ -222,16 +332,20 @@ export const experimentalHandlers = Layer.unwrap(
handlers
.handle("console", getConsole)
.handle("consoleOrgs", listConsoleOrgs)
.handle("consoleSwitch", switchConsole)
.handle("tool", tool)
.handle("toolIDs", toolIDs)
.handle("worktree", worktree)
.handle("worktreeCreate", worktreeCreate)
.handle("worktreeRemove", worktreeRemove)
.handle("worktreeReset", worktreeReset)
.handle("session", session)
.handle("resource", resource),
)
}),
).pipe(
Layer.provide(Account.defaultLayer),
Layer.provide(Agent.defaultLayer),
Layer.provide(Config.defaultLayer),
Layer.provide(MCP.defaultLayer),
Layer.provide(Project.defaultLayer),

View file

@ -139,9 +139,10 @@ export const mcpHandlers = Layer.unwrap(
})
const add = Effect.fn("McpHttpApi.add")(function* (ctx: { payload: typeof AddPayload.Type }) {
const payload = Schema.decodeUnknownSync(AddPayload)(ctx.payload)
const result = (yield* mcp.add(payload.name, payload.config)).status
return Schema.decodeUnknownSync(StatusMap)("status" in result ? { [payload.name]: result } : result)
const result = (yield* mcp.add(ctx.payload.name, ctx.payload.config)).status
return yield* Schema.decodeUnknownEffect(StatusMap)(
"status" in result ? { [ctx.payload.name]: result } : result,
).pipe(Effect.mapError(() => new HttpApiError.BadRequest({})))
})
const authStart = Effect.fn("McpHttpApi.authStart")(function* (ctx: { params: { name: string } }) {

View file

@ -18,6 +18,8 @@ import { PermissionApi, permissionHandlers } from "./permission"
import { ProjectApi, projectHandlers } from "./project"
import { ProviderApi, providerHandlers } from "./provider"
import { QuestionApi, questionHandlers } from "./question"
import { SessionApi, sessionHandlers } from "./session"
import { SyncApi, syncHandlers } from "./sync"
import { WorkspaceApi, workspaceHandlers } from "./workspace"
import { disposeMiddleware } from "./lifecycle"
import { memoMap } from "@opencode-ai/core/effect/memo-map"
@ -73,6 +75,8 @@ export const routes = Layer.mergeAll(
HttpApiBuilder.layer(QuestionApi).pipe(Layer.provide(questionHandlers)),
HttpApiBuilder.layer(PermissionApi).pipe(Layer.provide(permissionHandlers)),
HttpApiBuilder.layer(ProviderApi).pipe(Layer.provide(providerHandlers)),
HttpApiBuilder.layer(SessionApi).pipe(Layer.provide(sessionHandlers)),
HttpApiBuilder.layer(SyncApi).pipe(Layer.provide(syncHandlers)),
HttpApiBuilder.layer(WorkspaceApi).pipe(Layer.provide(workspaceHandlers)),
).pipe(
Layer.provide(authorizationLayer),

View file

@ -0,0 +1,924 @@
import * as InstanceState from "@/effect/instance-state"
import { AppRuntime } from "@/effect/app-runtime"
import { Agent } from "@/agent/agent"
import { Bus } from "@/bus"
import { Command } from "@/command"
import { Permission } from "@/permission"
import { PermissionID } from "@/permission/schema"
import { Instance } from "@/project/instance"
import { ModelID, ProviderID } from "@/provider/schema"
import { SessionShare } from "@/share"
import { Session } from "@/session"
import { SessionCompaction } from "@/session/compaction"
import { MessageV2 } from "@/session/message-v2"
import { SessionPrompt } from "@/session/prompt"
import { SessionRevert } from "@/session/revert"
import { SessionRunState } from "@/session/run-state"
import { SessionStatus } from "@/session/status"
import { SessionSummary } from "@/session/summary"
import { Todo } from "@/session/todo"
import { MessageID, PartID, SessionID } from "@/session/schema"
import { Snapshot } from "@/snapshot"
import { Log } from "@/util"
import { NamedError } from "@opencode-ai/core/util/error"
import { Effect, Layer, Schema, Struct } from "effect"
import * as Stream from "effect/Stream"
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
import {
HttpApi,
HttpApiBuilder,
HttpApiEndpoint,
HttpApiError,
HttpApiGroup,
HttpApiSchema,
OpenApi,
} from "effect/unstable/httpapi"
import { Authorization } from "./auth"
const log = Log.create({ service: "server" })
const root = "/session"
const ListQuery = Schema.Struct({
directory: Schema.optional(Schema.String),
roots: Schema.optional(Schema.Literals(["true", "false"])),
start: Schema.optional(Schema.NumberFromString),
search: Schema.optional(Schema.String),
limit: Schema.optional(Schema.NumberFromString),
})
const DiffQuery = Schema.Struct(Struct.omit(SessionSummary.DiffInput.fields, ["sessionID"]))
const MessagesQuery = Schema.Struct({
limit: Schema.optional(Schema.NumberFromString.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0))),
before: Schema.optional(Schema.String),
})
const StatusMap = Schema.Record(Schema.String, SessionStatus.Info)
const UpdatePayload = Schema.Struct({
title: Schema.optional(Schema.String),
permission: Schema.optional(Permission.Ruleset),
time: Schema.optional(
Schema.Struct({
archived: Schema.optional(Schema.Number),
}),
),
}).annotate({ identifier: "SessionUpdateInput" })
const ForkPayload = Schema.Struct(Struct.omit(Session.ForkInput.fields, ["sessionID"])).annotate({
identifier: "SessionForkInput",
})
const InitPayload = Schema.Struct({
modelID: ModelID,
providerID: ProviderID,
messageID: MessageID,
}).annotate({ identifier: "SessionInitInput" })
const SummarizePayload = Schema.Struct({
providerID: ProviderID,
modelID: ModelID,
auto: Schema.optional(Schema.Boolean),
}).annotate({ identifier: "SessionSummarizeInput" })
const PromptPayload = Schema.Struct(Struct.omit(SessionPrompt.PromptInput.fields, ["sessionID"])).annotate({
identifier: "SessionPromptInput",
})
const CommandPayload = Schema.Struct(Struct.omit(SessionPrompt.CommandInput.fields, ["sessionID"])).annotate({
identifier: "SessionCommandInput",
})
const ShellPayload = Schema.Struct(Struct.omit(SessionPrompt.ShellInput.fields, ["sessionID"])).annotate({
identifier: "SessionShellInput",
})
const RevertPayload = Schema.Struct(Struct.omit(SessionRevert.RevertInput.fields, ["sessionID"])).annotate({
identifier: "SessionRevertInput",
})
const PermissionResponsePayload = Schema.Struct({
response: Permission.Reply,
}).annotate({ identifier: "SessionPermissionResponseInput" })
export const SessionPaths = {
list: root,
status: `${root}/status`,
get: `${root}/:sessionID`,
children: `${root}/:sessionID/children`,
todo: `${root}/:sessionID/todo`,
diff: `${root}/:sessionID/diff`,
messages: `${root}/:sessionID/message`,
message: `${root}/:sessionID/message/:messageID`,
create: root,
remove: `${root}/:sessionID`,
update: `${root}/:sessionID`,
fork: `${root}/:sessionID/fork`,
abort: `${root}/:sessionID/abort`,
share: `${root}/:sessionID/share`,
init: `${root}/:sessionID/init`,
summarize: `${root}/:sessionID/summarize`,
prompt: `${root}/:sessionID/message`,
promptAsync: `${root}/:sessionID/prompt_async`,
command: `${root}/:sessionID/command`,
shell: `${root}/:sessionID/shell`,
revert: `${root}/:sessionID/revert`,
unrevert: `${root}/:sessionID/unrevert`,
permissions: `${root}/:sessionID/permissions/:permissionID`,
deleteMessage: `${root}/:sessionID/message/:messageID`,
deletePart: `${root}/:sessionID/message/:messageID/part/:partID`,
updatePart: `${root}/:sessionID/message/:messageID/part/:partID`,
} as const
export const SessionApi = HttpApi.make("session")
.add(
HttpApiGroup.make("session")
.add(
HttpApiEndpoint.get("list", SessionPaths.list, {
query: ListQuery,
success: Schema.Array(Session.Info),
}).annotateMerge(
OpenApi.annotations({
identifier: "session.list",
summary: "List sessions",
description: "Get a list of all OpenCode sessions, sorted by most recently updated.",
}),
),
HttpApiEndpoint.get("status", SessionPaths.status, {
success: StatusMap,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.status",
summary: "Get session status",
description: "Retrieve the current status of all sessions, including active, idle, and completed states.",
}),
),
HttpApiEndpoint.get("get", SessionPaths.get, {
params: { sessionID: SessionID },
success: Session.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.get",
summary: "Get session",
description: "Retrieve detailed information about a specific OpenCode session.",
}),
),
HttpApiEndpoint.get("children", SessionPaths.children, {
params: { sessionID: SessionID },
success: Schema.Array(Session.Info),
}).annotateMerge(
OpenApi.annotations({
identifier: "session.children",
summary: "Get session children",
description: "Retrieve all child sessions that were forked from the specified parent session.",
}),
),
HttpApiEndpoint.get("todo", SessionPaths.todo, {
params: { sessionID: SessionID },
success: Schema.Array(Todo.Info),
}).annotateMerge(
OpenApi.annotations({
identifier: "session.todo",
summary: "Get session todos",
description: "Retrieve the todo list associated with a specific session, showing tasks and action items.",
}),
),
HttpApiEndpoint.get("diff", SessionPaths.diff, {
params: { sessionID: SessionID },
query: DiffQuery,
success: Schema.Array(Snapshot.FileDiff),
}).annotateMerge(
OpenApi.annotations({
identifier: "session.diff",
summary: "Get message diff",
description: "Get the file changes (diff) that resulted from a specific user message in the session.",
}),
),
HttpApiEndpoint.get("messages", SessionPaths.messages, {
params: { sessionID: SessionID },
query: MessagesQuery,
success: Schema.Array(MessageV2.WithParts),
}).annotateMerge(
OpenApi.annotations({
identifier: "session.messages",
summary: "Get session messages",
description: "Retrieve all messages in a session, including user prompts and AI responses.",
}),
),
HttpApiEndpoint.get("message", SessionPaths.message, {
params: { sessionID: SessionID, messageID: MessageID },
success: MessageV2.WithParts,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.message",
summary: "Get message",
description: "Retrieve a specific message from a session by its message ID.",
}),
),
HttpApiEndpoint.post("create", SessionPaths.create, {
payload: Session.CreateInput,
success: Session.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.create",
summary: "Create session",
description: "Create a new OpenCode session for interacting with AI assistants and managing conversations.",
}),
),
HttpApiEndpoint.delete("remove", SessionPaths.remove, {
params: { sessionID: SessionID },
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.delete",
summary: "Delete session",
description: "Delete a session and permanently remove all associated data, including messages and history.",
}),
),
HttpApiEndpoint.patch("update", SessionPaths.update, {
params: { sessionID: SessionID },
payload: UpdatePayload,
success: Session.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.update",
summary: "Update session",
description: "Update properties of an existing session, such as title or other metadata.",
}),
),
HttpApiEndpoint.post("fork", SessionPaths.fork, {
params: { sessionID: SessionID },
payload: ForkPayload,
success: Session.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.fork",
summary: "Fork session",
description: "Create a new session by forking an existing session at a specific message point.",
}),
),
HttpApiEndpoint.post("abort", SessionPaths.abort, {
params: { sessionID: SessionID },
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.abort",
summary: "Abort session",
description: "Abort an active session and stop any ongoing AI processing or command execution.",
}),
),
HttpApiEndpoint.post("init", SessionPaths.init, {
params: { sessionID: SessionID },
payload: InitPayload,
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.init",
summary: "Initialize session",
description:
"Analyze the current application and create an AGENTS.md file with project-specific agent configurations.",
}),
),
HttpApiEndpoint.post("share", SessionPaths.share, {
params: { sessionID: SessionID },
success: Session.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.share",
summary: "Share session",
description: "Create a shareable link for a session, allowing others to view the conversation.",
}),
),
HttpApiEndpoint.delete("unshare", SessionPaths.share, {
params: { sessionID: SessionID },
success: Session.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.unshare",
summary: "Unshare session",
description: "Remove the shareable link for a session, making it private again.",
}),
),
HttpApiEndpoint.post("summarize", SessionPaths.summarize, {
params: { sessionID: SessionID },
payload: SummarizePayload,
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.summarize",
summary: "Summarize session",
description: "Generate a concise summary of the session using AI compaction to preserve key information.",
}),
),
HttpApiEndpoint.post("prompt", SessionPaths.prompt, {
params: { sessionID: SessionID },
payload: PromptPayload,
success: MessageV2.WithParts,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.prompt",
summary: "Send message",
description: "Create and send a new message to a session, streaming the AI response.",
}),
),
HttpApiEndpoint.post("promptAsync", SessionPaths.promptAsync, {
params: { sessionID: SessionID },
payload: PromptPayload,
success: HttpApiSchema.NoContent,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.prompt_async",
summary: "Send async message",
description:
"Create and send a new message to a session asynchronously, starting the session if needed and returning immediately.",
}),
),
HttpApiEndpoint.post("command", SessionPaths.command, {
params: { sessionID: SessionID },
payload: CommandPayload,
success: MessageV2.WithParts,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.command",
summary: "Send command",
description: "Send a new command to a session for execution by the AI assistant.",
}),
),
HttpApiEndpoint.post("shell", SessionPaths.shell, {
params: { sessionID: SessionID },
payload: ShellPayload,
success: MessageV2.WithParts,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.shell",
summary: "Run shell command",
description: "Execute a shell command within the session context and return the AI's response.",
}),
),
HttpApiEndpoint.post("revert", SessionPaths.revert, {
params: { sessionID: SessionID },
payload: RevertPayload,
success: Session.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.revert",
summary: "Revert message",
description:
"Revert a specific message in a session, undoing its effects and restoring the previous state.",
}),
),
HttpApiEndpoint.post("unrevert", SessionPaths.unrevert, {
params: { sessionID: SessionID },
success: Session.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.unrevert",
summary: "Restore reverted messages",
description: "Restore all previously reverted messages in a session.",
}),
),
HttpApiEndpoint.post("permissionRespond", SessionPaths.permissions, {
params: { sessionID: SessionID, permissionID: PermissionID },
payload: PermissionResponsePayload,
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "permission.respond",
summary: "Respond to permission",
description: "Approve or deny a permission request from the AI assistant.",
deprecated: true,
}),
),
HttpApiEndpoint.delete("deleteMessage", SessionPaths.deleteMessage, {
params: { sessionID: SessionID, messageID: MessageID },
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "session.deleteMessage",
summary: "Delete message",
description:
"Permanently delete a specific message and all of its parts from a session without reverting file changes.",
}),
),
HttpApiEndpoint.delete("deletePart", SessionPaths.deletePart, {
params: { sessionID: SessionID, messageID: MessageID, partID: PartID },
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "part.delete",
description: "Delete a part from a message.",
}),
),
HttpApiEndpoint.patch("updatePart", SessionPaths.updatePart, {
params: { sessionID: SessionID, messageID: MessageID, partID: PartID },
payload: MessageV2.Part,
success: MessageV2.Part,
}).annotateMerge(
OpenApi.annotations({
identifier: "part.update",
description: "Update a part in a message.",
}),
),
)
.annotateMerge(
OpenApi.annotations({
title: "session",
description: "Experimental HttpApi session routes.",
}),
)
.middleware(Authorization),
)
.annotateMerge(
OpenApi.annotations({
title: "opencode experimental HttpApi",
version: "0.0.1",
description: "Experimental HttpApi surface for selected instance routes.",
}),
)
export const sessionHandlers = Layer.unwrap(
Effect.gen(function* () {
const session = yield* Session.Service
const statusSvc = yield* SessionStatus.Service
const todoSvc = yield* Todo.Service
const summary = yield* SessionSummary.Service
const list = Effect.fn("SessionHttpApi.list")(function* (ctx: { query: typeof ListQuery.Type }) {
const instance = yield* InstanceState.context
return Instance.restore(instance, () =>
Array.from(
Session.list({
directory: ctx.query.directory,
roots: ctx.query.roots === "true" ? true : undefined,
start: ctx.query.start,
search: ctx.query.search,
limit: ctx.query.limit,
}),
),
)
})
const status = Effect.fn("SessionHttpApi.status")(function* () {
return Object.fromEntries(yield* statusSvc.list())
})
const get = Effect.fn("SessionHttpApi.get")(function* (ctx: { params: { sessionID: SessionID } }) {
return yield* session.get(ctx.params.sessionID)
})
const children = Effect.fn("SessionHttpApi.children")(function* (ctx: { params: { sessionID: SessionID } }) {
return yield* session.children(ctx.params.sessionID)
})
const todo = Effect.fn("SessionHttpApi.todo")(function* (ctx: { params: { sessionID: SessionID } }) {
return yield* todoSvc.get(ctx.params.sessionID)
})
const diff = Effect.fn("SessionHttpApi.diff")(function* (ctx: {
params: { sessionID: SessionID }
query: typeof DiffQuery.Type
}) {
return yield* summary.diff({ sessionID: ctx.params.sessionID, messageID: ctx.query.messageID })
})
const messages = Effect.fn("SessionHttpApi.messages")(function* (ctx: {
params: { sessionID: SessionID }
query: typeof MessagesQuery.Type
}) {
if (ctx.query.before !== undefined && ctx.query.limit === undefined) return yield* new HttpApiError.BadRequest({})
if (ctx.query.before !== undefined) {
const before = ctx.query.before
yield* Effect.try({
try: () => MessageV2.cursor.decode(before),
catch: () => new HttpApiError.BadRequest({}),
})
}
if (ctx.query.limit === undefined || ctx.query.limit === 0) {
yield* session.get(ctx.params.sessionID)
return yield* session.messages({ sessionID: ctx.params.sessionID })
}
const page = MessageV2.page({
sessionID: ctx.params.sessionID,
limit: ctx.query.limit,
before: ctx.query.before,
})
if (!page.cursor) return page.items
const request = yield* HttpServerRequest.HttpServerRequest
const url = new URL(request.url, "http://localhost")
url.searchParams.set("limit", ctx.query.limit.toString())
url.searchParams.set("before", page.cursor)
return HttpServerResponse.jsonUnsafe(page.items, {
headers: {
"Access-Control-Expose-Headers": "Link, X-Next-Cursor",
Link: `<${url.toString()}>; rel="next"`,
"X-Next-Cursor": page.cursor,
},
})
})
const message = Effect.fn("SessionHttpApi.message")(function* (ctx: {
params: { sessionID: SessionID; messageID: MessageID }
}) {
return yield* Effect.sync(() =>
MessageV2.get({ sessionID: ctx.params.sessionID, messageID: ctx.params.messageID }),
)
})
const create = Effect.fn("SessionHttpApi.create")(function* (ctx: { payload: Session.CreateInput }) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
SessionShare.Service.use((svc) => svc.create(ctx.payload)).pipe(Effect.provide(SessionShare.defaultLayer)),
),
),
)
})
const remove = Effect.fn("SessionHttpApi.remove")(function* (ctx: { params: { sessionID: SessionID } }) {
const instance = yield* InstanceState.context
yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Session.Service.use((svc) => svc.remove(ctx.params.sessionID)).pipe(Effect.provide(Session.defaultLayer)),
),
),
)
return true
})
const update = Effect.fn("SessionHttpApi.update")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof UpdatePayload.Type
}) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Session.Service.use((svc) =>
Effect.gen(function* () {
const current = yield* svc.get(ctx.params.sessionID)
if (ctx.payload.title !== undefined) {
yield* svc.setTitle({ sessionID: ctx.params.sessionID, title: ctx.payload.title })
}
if (ctx.payload.permission !== undefined) {
yield* svc.setPermission({
sessionID: ctx.params.sessionID,
permission: Permission.merge(current.permission ?? [], ctx.payload.permission),
})
}
if (ctx.payload.time?.archived !== undefined) {
yield* svc.setArchived({ sessionID: ctx.params.sessionID, time: ctx.payload.time.archived })
}
return yield* svc.get(ctx.params.sessionID)
}),
).pipe(Effect.provide(Session.defaultLayer)),
),
),
)
})
const fork = Effect.fn("SessionHttpApi.fork")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof ForkPayload.Type
}) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Session.Service.use((svc) =>
svc.fork({ sessionID: ctx.params.sessionID, messageID: ctx.payload.messageID }),
).pipe(Effect.provide(Session.defaultLayer)),
),
),
)
})
const abort = Effect.fn("SessionHttpApi.abort")(function* (ctx: { params: { sessionID: SessionID } }) {
const instance = yield* InstanceState.context
yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
SessionPrompt.Service.use((svc) => svc.cancel(ctx.params.sessionID)).pipe(
Effect.provide(SessionPrompt.defaultLayer),
),
),
),
)
return true
})
const init = Effect.fn("SessionHttpApi.init")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof InitPayload.Type
}) {
const instance = yield* InstanceState.context
yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
SessionPrompt.Service.use((svc) =>
svc.command({
sessionID: ctx.params.sessionID,
messageID: ctx.payload.messageID,
model: `${ctx.payload.providerID}/${ctx.payload.modelID}`,
command: Command.Default.INIT,
arguments: "",
}),
).pipe(Effect.provide(SessionPrompt.defaultLayer)),
),
),
)
return true
})
const share = Effect.fn("SessionHttpApi.share")(function* (ctx: { params: { sessionID: SessionID } }) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Effect.gen(function* () {
const share = yield* SessionShare.Service
const session = yield* Session.Service
yield* share.share(ctx.params.sessionID)
return yield* session.get(ctx.params.sessionID)
}).pipe(Effect.provide(SessionShare.defaultLayer)),
),
),
)
})
const unshare = Effect.fn("SessionHttpApi.unshare")(function* (ctx: { params: { sessionID: SessionID } }) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Effect.gen(function* () {
const share = yield* SessionShare.Service
const session = yield* Session.Service
yield* share.unshare(ctx.params.sessionID)
return yield* session.get(ctx.params.sessionID)
}).pipe(Effect.provide(SessionShare.defaultLayer)),
),
),
)
})
const summarize = Effect.fn("SessionHttpApi.summarize")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof SummarizePayload.Type
}) {
const instance = yield* InstanceState.context
yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Effect.gen(function* () {
const session = yield* Session.Service
const revert = yield* SessionRevert.Service
const compact = yield* SessionCompaction.Service
const prompt = yield* SessionPrompt.Service
const agent = yield* Agent.Service
yield* revert.cleanup(yield* session.get(ctx.params.sessionID))
const messages = yield* session.messages({ sessionID: ctx.params.sessionID })
const defaultAgent = yield* agent.defaultAgent()
const currentAgent =
messages.findLast((message) => message.info.role === "user")?.info.agent ?? defaultAgent
yield* compact.create({
sessionID: ctx.params.sessionID,
agent: currentAgent,
model: {
providerID: ctx.payload.providerID,
modelID: ctx.payload.modelID,
},
auto: ctx.payload.auto ?? false,
})
yield* prompt.loop({ sessionID: ctx.params.sessionID })
}).pipe(
Effect.provide(SessionRevert.defaultLayer),
Effect.provide(SessionCompaction.defaultLayer),
Effect.provide(SessionPrompt.defaultLayer),
Effect.provide(Agent.defaultLayer),
Effect.provide(Session.defaultLayer),
),
),
),
)
return true
})
const prompt = Effect.fn("SessionHttpApi.prompt")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof PromptPayload.Type
}) {
const instance = yield* InstanceState.context
return HttpServerResponse.stream(
Stream.fromEffect(
Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
SessionPrompt.Service.use((svc) =>
svc.prompt({
...ctx.payload,
sessionID: ctx.params.sessionID,
} as unknown as SessionPrompt.PromptInput),
).pipe(Effect.provide(SessionPrompt.defaultLayer)),
),
),
),
).pipe(
Stream.map((message) => JSON.stringify(message)),
Stream.encodeText,
),
{ contentType: "application/json" },
)
})
const promptAsync = Effect.fn("SessionHttpApi.promptAsync")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof PromptPayload.Type
}) {
const instance = yield* InstanceState.context
yield* Effect.sync(() => {
Instance.restore(instance, () => {
void AppRuntime.runPromise(
SessionPrompt.Service.use((svc) =>
svc.prompt({ ...ctx.payload, sessionID: ctx.params.sessionID } as unknown as SessionPrompt.PromptInput),
).pipe(Effect.provide(SessionPrompt.defaultLayer)),
).catch((error) => {
log.error("prompt_async failed", { sessionID: ctx.params.sessionID, error })
void Bus.publish(Session.Event.Error, {
sessionID: ctx.params.sessionID,
error: new NamedError.Unknown({
message: error instanceof Error ? error.message : String(error),
}).toObject(),
})
})
})
})
return HttpApiSchema.NoContent.make()
})
const command = Effect.fn("SessionHttpApi.command")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof CommandPayload.Type
}) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
SessionPrompt.Service.use((svc) =>
svc.command({ ...ctx.payload, sessionID: ctx.params.sessionID } as SessionPrompt.CommandInput),
).pipe(Effect.provide(SessionPrompt.defaultLayer)),
),
),
)
})
const shell = Effect.fn("SessionHttpApi.shell")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof ShellPayload.Type
}) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
SessionPrompt.Service.use((svc) =>
svc.shell({ ...ctx.payload, sessionID: ctx.params.sessionID } as SessionPrompt.ShellInput),
).pipe(Effect.provide(SessionPrompt.defaultLayer)),
),
),
)
})
const revert = Effect.fn("SessionHttpApi.revert")(function* (ctx: {
params: { sessionID: SessionID }
payload: typeof RevertPayload.Type
}) {
const instance = yield* InstanceState.context
log.info("revert", ctx.payload)
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
SessionRevert.Service.use((svc) => svc.revert({ sessionID: ctx.params.sessionID, ...ctx.payload })).pipe(
Effect.provide(SessionRevert.defaultLayer),
),
),
),
)
})
const unrevert = Effect.fn("SessionHttpApi.unrevert")(function* (ctx: { params: { sessionID: SessionID } }) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
SessionRevert.Service.use((svc) => svc.unrevert({ sessionID: ctx.params.sessionID })).pipe(
Effect.provide(SessionRevert.defaultLayer),
),
),
),
)
})
const permissionRespond = Effect.fn("SessionHttpApi.permissionRespond")(function* (ctx: {
params: { permissionID: PermissionID }
payload: typeof PermissionResponsePayload.Type
}) {
const instance = yield* InstanceState.context
yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Permission.Service.use((svc) =>
svc.reply({ requestID: ctx.params.permissionID, reply: ctx.payload.response }),
).pipe(Effect.provide(Permission.defaultLayer)),
),
),
)
return true
})
const deleteMessage = Effect.fn("SessionHttpApi.deleteMessage")(function* (ctx: {
params: { sessionID: SessionID; messageID: MessageID }
}) {
const instance = yield* InstanceState.context
yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Effect.gen(function* () {
const state = yield* SessionRunState.Service
const session = yield* Session.Service
yield* state.assertNotBusy(ctx.params.sessionID)
yield* session.removeMessage(ctx.params)
}).pipe(Effect.provide(SessionRunState.defaultLayer), Effect.provide(Session.defaultLayer)),
),
),
)
return true
})
const deletePart = Effect.fn("SessionHttpApi.deletePart")(function* (ctx: {
params: { sessionID: SessionID; messageID: MessageID; partID: PartID }
}) {
const instance = yield* InstanceState.context
yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Session.Service.use((svc) => svc.removePart(ctx.params)).pipe(Effect.provide(Session.defaultLayer)),
),
),
)
return true
})
const updatePart = Effect.fn("SessionHttpApi.updatePart")(function* (ctx: {
params: { sessionID: SessionID; messageID: MessageID; partID: PartID }
payload: typeof MessageV2.Part.Type
}) {
const payload = ctx.payload as MessageV2.Part
if (
payload.id !== ctx.params.partID ||
payload.messageID !== ctx.params.messageID ||
payload.sessionID !== ctx.params.sessionID
) {
throw new Error(
`Part mismatch: body.id='${payload.id}' vs partID='${ctx.params.partID}', body.messageID='${payload.messageID}' vs messageID='${ctx.params.messageID}', body.sessionID='${payload.sessionID}' vs sessionID='${ctx.params.sessionID}'`,
)
}
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
AppRuntime.runPromise(
Session.Service.use((svc) => svc.updatePart(payload)).pipe(Effect.provide(Session.defaultLayer)),
),
),
)
})
return HttpApiBuilder.group(SessionApi, "session", (handlers) =>
handlers
.handle("list", list)
.handle("status", status)
.handle("get", get)
.handle("children", children)
.handle("todo", todo)
.handle("diff", diff)
.handle("messages", messages)
.handle("message", message)
.handle("create", create)
.handle("remove", remove)
.handle("update", update)
.handle("fork", fork)
.handle("abort", abort)
.handle("init", init)
.handle("share", share)
.handle("unshare", unshare)
.handle("summarize", summarize)
.handle("prompt", prompt)
.handle("promptAsync", promptAsync)
.handle("command", command)
.handle("shell", shell)
.handle("revert", revert)
.handle("unrevert", unrevert)
.handle("permissionRespond", permissionRespond)
.handle("deleteMessage", deleteMessage)
.handle("deletePart", deletePart)
.handle("updatePart", updatePart),
)
}),
).pipe(
Layer.provide(Session.defaultLayer),
Layer.provide(SessionRunState.defaultLayer),
Layer.provide(SessionStatus.defaultLayer),
Layer.provide(Todo.defaultLayer),
Layer.provide(SessionSummary.defaultLayer),
)

View file

@ -0,0 +1,130 @@
import { startWorkspaceSyncing } from "@/control-plane/workspace"
import * as InstanceState from "@/effect/instance-state"
import { Database, asc, and, eq, lte, not, or } from "@/storage"
import { SyncEvent } from "@/sync"
import { EventTable } from "@/sync/event.sql"
import { Effect, Layer, Schema } from "effect"
import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
import { Authorization } from "./auth"
const root = "/sync"
const ReplayEvent = Schema.Struct({
id: Schema.String,
aggregateID: Schema.String,
seq: Schema.Number,
type: Schema.String,
data: Schema.Record(Schema.String, Schema.Unknown),
}).annotate({ identifier: "SyncReplayEvent" })
const ReplayPayload = Schema.Struct({
directory: Schema.String,
events: Schema.NonEmptyArray(ReplayEvent),
}).annotate({ identifier: "SyncReplayInput" })
const ReplayResponse = Schema.Struct({
sessionID: Schema.String,
}).annotate({ identifier: "SyncReplayResponse" })
const HistoryPayload = Schema.Record(Schema.String, Schema.Number)
const HistoryEvent = Schema.Struct({
id: Schema.String,
aggregate_id: Schema.String,
seq: Schema.Number,
type: Schema.String,
data: Schema.Record(Schema.String, Schema.Unknown),
}).annotate({ identifier: "SyncHistoryEvent" })
export const SyncPaths = {
start: `${root}/start`,
replay: `${root}/replay`,
history: `${root}/history`,
} as const
export const SyncApi = HttpApi.make("sync")
.add(
HttpApiGroup.make("sync")
.add(
HttpApiEndpoint.post("start", SyncPaths.start, {
success: Schema.Boolean,
}).annotateMerge(
OpenApi.annotations({
identifier: "sync.start",
summary: "Start workspace sync",
description: "Start sync loops for workspaces in the current project that have active sessions.",
}),
),
HttpApiEndpoint.post("replay", SyncPaths.replay, {
payload: ReplayPayload,
success: ReplayResponse,
}).annotateMerge(
OpenApi.annotations({
identifier: "sync.replay",
summary: "Replay sync events",
description: "Validate and replay a complete sync event history.",
}),
),
HttpApiEndpoint.post("history", SyncPaths.history, {
payload: HistoryPayload,
success: Schema.Array(HistoryEvent),
}).annotateMerge(
OpenApi.annotations({
identifier: "sync.history.list",
summary: "List sync events",
description:
"List sync events for all aggregates. Keys are aggregate IDs the client already knows about, values are the last known sequence ID. Events with seq > value are returned for those aggregates. Aggregates not listed in the input get their full history.",
}),
),
)
.annotateMerge(
OpenApi.annotations({
title: "sync",
description: "Experimental HttpApi sync routes.",
}),
)
.middleware(Authorization),
)
.annotateMerge(
OpenApi.annotations({
title: "opencode experimental HttpApi",
version: "0.0.1",
description: "Experimental HttpApi surface for selected instance routes.",
}),
)
export const syncHandlers = Layer.unwrap(
Effect.gen(function* () {
const start = Effect.fn("SyncHttpApi.start")(function* () {
startWorkspaceSyncing((yield* InstanceState.context).project.id)
return true
})
const replay = Effect.fn("SyncHttpApi.replay")(function* (ctx: { payload: typeof ReplayPayload.Type }) {
const events: SyncEvent.SerializedEvent[] = ctx.payload.events.map((event) => ({
id: event.id,
aggregateID: event.aggregateID,
seq: event.seq,
type: event.type,
data: { ...event.data },
}))
SyncEvent.replayAll(events)
return { sessionID: events[0].aggregateID }
})
const history = Effect.fn("SyncHttpApi.history")(function* (ctx: { payload: typeof HistoryPayload.Type }) {
const exclude = Object.entries(ctx.payload)
return Database.use((db) =>
db
.select()
.from(EventTable)
.where(
exclude.length > 0
? not(or(...exclude.map(([id, seq]) => and(eq(EventTable.aggregate_id, id), lte(EventTable.seq, seq))))!)
: undefined,
)
.orderBy(asc(EventTable.seq))
.all(),
)
})
return HttpApiBuilder.group(SyncApi, "sync", (handlers) =>
handlers.handle("start", start).handle("replay", replay).handle("history", history),
)
}),
)

View file

@ -2,15 +2,30 @@ import { listAdaptors } from "@/control-plane/adaptors"
import { Workspace } from "@/control-plane/workspace"
import { WorkspaceAdaptorEntry } from "@/control-plane/types"
import * as InstanceState from "@/effect/instance-state"
import { Effect, Layer, Schema } from "effect"
import { Instance } from "@/project/instance"
import { Effect, Layer, Schema, Struct } from "effect"
import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
import { Authorization } from "./auth"
const root = "/experimental/workspace"
const CreatePayload = Schema.Struct(Struct.omit(Workspace.CreateInput.fields, ["projectID"])).annotate({
identifier: "WorkspaceCreateInput",
})
const SessionRestorePayload = Schema.Struct(
Struct.omit(Workspace.SessionRestoreInput.fields, ["workspaceID"]),
).annotate({
identifier: "WorkspaceSessionRestoreInput",
})
const SessionRestoreResponse = Schema.Struct({
total: Schema.Number,
}).annotate({ identifier: "WorkspaceSessionRestoreResponse" })
export const WorkspacePaths = {
adaptors: `${root}/adaptor`,
list: root,
status: `${root}/status`,
remove: `${root}/:id`,
sessionRestore: `${root}/:id/session-restore`,
} as const
export const WorkspaceApi = HttpApi.make("workspace")
@ -35,6 +50,16 @@ export const WorkspaceApi = HttpApi.make("workspace")
description: "List all workspaces.",
}),
),
HttpApiEndpoint.post("create", WorkspacePaths.list, {
payload: CreatePayload,
success: Workspace.Info,
}).annotateMerge(
OpenApi.annotations({
identifier: "experimental.workspace.create",
summary: "Create workspace",
description: "Create a workspace for the current project.",
}),
),
HttpApiEndpoint.get("status", WorkspacePaths.status, {
success: Schema.Array(Workspace.ConnectionStatus),
}).annotateMerge(
@ -44,6 +69,27 @@ export const WorkspaceApi = HttpApi.make("workspace")
description: "Get connection status for workspaces in the current project.",
}),
),
HttpApiEndpoint.delete("remove", WorkspacePaths.remove, {
params: { id: Workspace.Info.fields.id },
success: Schema.UndefinedOr(Workspace.Info),
}).annotateMerge(
OpenApi.annotations({
identifier: "experimental.workspace.remove",
summary: "Remove workspace",
description: "Remove an existing workspace.",
}),
),
HttpApiEndpoint.post("sessionRestore", WorkspacePaths.sessionRestore, {
params: { id: Workspace.Info.fields.id },
payload: SessionRestorePayload,
success: SessionRestoreResponse,
}).annotateMerge(
OpenApi.annotations({
identifier: "experimental.workspace.sessionRestore",
summary: "Restore session into workspace",
description: "Replay a session's sync events into the target workspace in batches.",
}),
),
)
.annotateMerge(
OpenApi.annotations({
@ -72,13 +118,51 @@ export const workspaceHandlers = Layer.unwrap(
return Workspace.list((yield* InstanceState.context).project)
})
const create = Effect.fn("WorkspaceHttpApi.create")(function* (ctx: { payload: typeof CreatePayload.Type }) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
Workspace.create({
...ctx.payload,
projectID: instance.project.id,
}),
),
)
})
const status = Effect.fn("WorkspaceHttpApi.status")(function* () {
const ids = new Set(Workspace.list((yield* InstanceState.context).project).map((item) => item.id))
return Workspace.status().filter((item) => ids.has(item.workspaceID))
})
const remove = Effect.fn("WorkspaceHttpApi.remove")(function* (ctx: { params: { id: Workspace.Info["id"] } }) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() => Instance.restore(instance, () => Workspace.remove(ctx.params.id)))
})
const sessionRestore = Effect.fn("WorkspaceHttpApi.sessionRestore")(function* (ctx: {
params: { id: Workspace.Info["id"] }
payload: typeof SessionRestorePayload.Type
}) {
const instance = yield* InstanceState.context
return yield* Effect.promise(() =>
Instance.restore(instance, () =>
Workspace.sessionRestore({
workspaceID: ctx.params.id,
sessionID: ctx.payload.sessionID,
}),
),
)
})
return HttpApiBuilder.group(WorkspaceApi, "workspace", (handlers) =>
handlers.handle("adaptors", adaptors).handle("list", list).handle("status", status),
handlers
.handle("adaptors", adaptors)
.handle("list", list)
.handle("create", create)
.handle("status", status)
.handle("remove", remove)
.handle("sessionRestore", sessionRestore),
)
}),
)

View file

@ -20,6 +20,8 @@ import { ExperimentalPaths } from "./httpapi/experimental"
import { FilePaths } from "./httpapi/file"
import { InstancePaths } from "./httpapi/instance"
import { McpPaths } from "./httpapi/mcp"
import { SessionPaths } from "./httpapi/session"
import { SyncPaths } from "./httpapi/sync"
import { ProjectRoutes } from "./project"
import { SessionRoutes } from "./session"
import { PtyRoutes } from "./pty"
@ -49,11 +51,14 @@ export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono => {
app.get("/config/providers", (c) => handler(c.req.raw, context))
app.get(ExperimentalPaths.console, (c) => handler(c.req.raw, context))
app.get(ExperimentalPaths.consoleOrgs, (c) => handler(c.req.raw, context))
app.post(ExperimentalPaths.consoleSwitch, (c) => handler(c.req.raw, context))
app.get(ExperimentalPaths.tool, (c) => handler(c.req.raw, context))
app.get(ExperimentalPaths.toolIDs, (c) => handler(c.req.raw, context))
app.get(ExperimentalPaths.worktree, (c) => handler(c.req.raw, context))
app.post(ExperimentalPaths.worktree, (c) => handler(c.req.raw, context))
app.delete(ExperimentalPaths.worktree, (c) => handler(c.req.raw, context))
app.post(ExperimentalPaths.worktreeReset, (c) => handler(c.req.raw, context))
app.get(ExperimentalPaths.session, (c) => handler(c.req.raw, context))
app.get(ExperimentalPaths.resource, (c) => handler(c.req.raw, context))
app.get("/provider", (c) => handler(c.req.raw, context))
app.get("/provider/auth", (c) => handler(c.req.raw, context))
@ -86,6 +91,36 @@ export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono => {
app.delete(McpPaths.auth, (c) => handler(c.req.raw, context))
app.post(McpPaths.connect, (c) => handler(c.req.raw, context))
app.post(McpPaths.disconnect, (c) => handler(c.req.raw, context))
app.post(SyncPaths.start, (c) => handler(c.req.raw, context))
app.post(SyncPaths.replay, (c) => handler(c.req.raw, context))
app.post(SyncPaths.history, (c) => handler(c.req.raw, context))
app.get(SessionPaths.list, (c) => handler(c.req.raw, context))
app.get(SessionPaths.status, (c) => handler(c.req.raw, context))
app.get(SessionPaths.get, (c) => handler(c.req.raw, context))
app.get(SessionPaths.children, (c) => handler(c.req.raw, context))
app.get(SessionPaths.todo, (c) => handler(c.req.raw, context))
app.get(SessionPaths.diff, (c) => handler(c.req.raw, context))
app.get(SessionPaths.messages, (c) => handler(c.req.raw, context))
app.get(SessionPaths.message, (c) => handler(c.req.raw, context))
app.post(SessionPaths.create, (c) => handler(c.req.raw, context))
app.delete(SessionPaths.remove, (c) => handler(c.req.raw, context))
app.patch(SessionPaths.update, (c) => handler(c.req.raw, context))
app.post(SessionPaths.init, (c) => handler(c.req.raw, context))
app.post(SessionPaths.fork, (c) => handler(c.req.raw, context))
app.post(SessionPaths.abort, (c) => handler(c.req.raw, context))
app.post(SessionPaths.share, (c) => handler(c.req.raw, context))
app.delete(SessionPaths.share, (c) => handler(c.req.raw, context))
app.post(SessionPaths.summarize, (c) => handler(c.req.raw, context))
app.post(SessionPaths.prompt, (c) => handler(c.req.raw, context))
app.post(SessionPaths.promptAsync, (c) => handler(c.req.raw, context))
app.post(SessionPaths.command, (c) => handler(c.req.raw, context))
app.post(SessionPaths.shell, (c) => handler(c.req.raw, context))
app.post(SessionPaths.revert, (c) => handler(c.req.raw, context))
app.post(SessionPaths.unrevert, (c) => handler(c.req.raw, context))
app.post(SessionPaths.permissions, (c) => handler(c.req.raw, context))
app.delete(SessionPaths.deleteMessage, (c) => handler(c.req.raw, context))
app.delete(SessionPaths.deletePart, (c) => handler(c.req.raw, context))
app.patch(SessionPaths.updatePart, (c) => handler(c.req.raw, context))
}
return app

View file

@ -67,7 +67,10 @@ function create(opts: { cors?: string[] }) {
const context = Context.empty() as Context.Context<unknown>
workspaceApp.get(WorkspacePaths.adaptors, (c) => handler(c.req.raw, context))
workspaceApp.get(WorkspacePaths.list, (c) => handler(c.req.raw, context))
workspaceApp.post(WorkspacePaths.list, (c) => handler(c.req.raw, context))
workspaceApp.get(WorkspacePaths.status, (c) => handler(c.req.raw, context))
workspaceApp.delete(WorkspacePaths.remove, (c) => handler(c.req.raw, context))
workspaceApp.post(WorkspacePaths.sessionRestore, (c) => handler(c.req.raw, context))
}
workspaceApp.route("/", workspaceLegacyApp)

View file

@ -376,6 +376,7 @@ const live: Layer.Layer<
"x-opencode-session": input.sessionID,
"x-opencode-request": input.user.id,
"x-opencode-client": Flag.OPENCODE_CLIENT,
"User-Agent": `opencode/${InstallationVersion}`,
}
: {
"x-session-affinity": input.sessionID,

View file

@ -55,6 +55,14 @@ async function defaultModel() {
return run((provider) => provider.defaultModel())
}
async function markPluginDependenciesReady(dir: string) {
await mkdir(path.join(dir, "node_modules"), { recursive: true })
await Bun.write(
path.join(dir, "package-lock.json"),
JSON.stringify({ packages: { "": { dependencies: { "@opencode-ai/plugin": "0.0.0" } } } }),
)
}
function paid(providers: Awaited<ReturnType<typeof list>>) {
const item = providers[ProviderID.make("opencode")]
expect(item).toBeDefined()
@ -2439,8 +2447,11 @@ test("cloudflare-ai-gateway forwards config metadata options", async () => {
test("plugin config providers persist after instance dispose", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
const root = path.join(dir, ".opencode", "plugin")
const configDir = path.join(dir, ".opencode")
const root = path.join(configDir, "plugin")
await mkdir(root, { recursive: true })
await markPluginDependenciesReady(configDir)
await markPluginDependenciesReady(Global.Path.config)
await Bun.write(
path.join(root, "demo-provider.ts"),
[

View file

@ -1,10 +1,13 @@
import { afterEach, describe, expect, test } from "bun:test"
import type { UpgradeWebSocket } from "hono/ws"
import { Effect } from "effect"
import { Flag } from "@opencode-ai/core/flag/flag"
import { GlobalBus } from "@/bus/global"
import { Instance } from "../../src/project/instance"
import { InstanceRoutes } from "../../src/server/routes/instance"
import { ExperimentalPaths } from "../../src/server/routes/instance/httpapi/experimental"
import { Session } from "../../src/session"
import { Database } from "../../src/storage"
import { Log } from "../../src/util"
import { Worktree } from "../../src/worktree"
import { resetDatabase } from "../fixture/db"
@ -14,12 +17,21 @@ void Log.init({ print: false })
const original = Flag.OPENCODE_EXPERIMENTAL_HTTPAPI
const websocket = (() => () => new Response(null, { status: 501 })) as unknown as UpgradeWebSocket
const testWorktreeMutations = process.platform === "win32" ? test.skip : test
function app() {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = true
return InstanceRoutes(websocket)
}
function runSession<A, E>(fx: Effect.Effect<A, E, Session.Service>) {
return Effect.runPromise(fx.pipe(Effect.provide(Session.defaultLayer)))
}
function createSession(input?: Session.CreateInput) {
return runSession(Session.Service.use((svc) => svc.create(input)))
}
async function waitReady(directory: string) {
return await new Promise<void>((resolve, reject) => {
const timer = setTimeout(() => {
@ -61,9 +73,10 @@ describe("experimental HttpApi", () => {
})
const headers = { "x-opencode-directory": tmp.path }
const [consoleState, consoleOrgs, toolIDs, worktrees, resources] = await Promise.all([
const [consoleState, consoleOrgs, toolList, toolIDs, worktrees, resources] = await Promise.all([
app().request(ExperimentalPaths.console, { headers }),
app().request(ExperimentalPaths.consoleOrgs, { headers }),
app().request(`${ExperimentalPaths.tool}?provider=opencode&model=gpt-5`, { headers }),
app().request(ExperimentalPaths.toolIDs, { headers }),
app().request(ExperimentalPaths.worktree, { headers }),
app().request(ExperimentalPaths.resource, { headers }),
@ -78,6 +91,15 @@ describe("experimental HttpApi", () => {
expect(consoleOrgs.status).toBe(200)
expect(await consoleOrgs.json()).toEqual({ orgs: [] })
expect(toolList.status).toBe(200)
expect(await toolList.json()).toContainEqual(
expect.objectContaining({
id: "bash",
description: expect.any(String),
parameters: expect.any(Object),
}),
)
expect(toolIDs.status).toBe(200)
expect(await toolIDs.json()).toContain("bash")
@ -88,7 +110,70 @@ describe("experimental HttpApi", () => {
expect(await resources.json()).toEqual({})
})
test("serves worktree mutations through Hono bridge", async () => {
test("serves Console org switch through Hono bridge", async () => {
await using tmp = await tmpdir({ config: { formatter: false, lsp: false } })
Database.Client()
.$client.prepare(
"INSERT INTO account (id, email, url, access_token, refresh_token, time_created, time_updated) VALUES (?, ?, ?, ?, ?, ?, ?)",
)
.run(
"account-test",
"test@example.com",
"https://console.example.com",
"access",
"refresh",
Date.now(),
Date.now(),
)
const switched = await app().request(ExperimentalPaths.consoleSwitch, {
method: "POST",
headers: { "x-opencode-directory": tmp.path, "content-type": "application/json" },
body: JSON.stringify({ accountID: "account-test", orgID: "org-test" }),
})
expect(switched.status).toBe(200)
expect(await switched.json()).toBe(true)
})
test("serves global session list through Hono bridge", async () => {
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } })
const first = await Instance.provide({
directory: tmp.path,
fn: async () => createSession({ title: "page-one" }),
})
await new Promise((resolve) => setTimeout(resolve, 5))
const second = await Instance.provide({
directory: tmp.path,
fn: async () => createSession({ title: "page-two" }),
})
const headers = { "x-opencode-directory": tmp.path }
const page = await app().request(
`${ExperimentalPaths.session}?${new URLSearchParams({ directory: tmp.path, limit: "1" })}`,
{ headers },
)
expect(page.status).toBe(200)
expect(page.headers.get("x-next-cursor")).toBeTruthy()
const body = (await page.json()) as Session.GlobalInfo[]
expect(body.map((session) => session.id)).toEqual([second.id])
expect(body[0].project?.id).toBe(second.projectID)
const next = await app().request(
`${ExperimentalPaths.session}?${new URLSearchParams({
directory: tmp.path,
limit: "10",
cursor: body[0].time.updated.toString(),
})}`,
{ headers },
)
expect(next.status).toBe(200)
expect(((await next.json()) as Session.GlobalInfo[]).map((session) => session.id)).toContain(first.id)
})
testWorktreeMutations("serves worktree mutations through Hono bridge", async () => {
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } })
const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" }

View file

@ -0,0 +1,280 @@
import { afterEach, describe, expect, test } from "bun:test"
import type { UpgradeWebSocket } from "hono/ws"
import { Effect } from "effect"
import { Flag } from "@opencode-ai/core/flag/flag"
import { PermissionID } from "../../src/permission/schema"
import { ModelID, ProviderID } from "../../src/provider/schema"
import { Instance } from "../../src/project/instance"
import { InstanceRoutes } from "../../src/server/routes/instance"
import { SessionPaths } from "../../src/server/routes/instance/httpapi/session"
import { Session } from "../../src/session"
import { MessageID, PartID, type SessionID } from "../../src/session/schema"
import { MessageV2 } from "../../src/session/message-v2"
import { Log } from "../../src/util"
import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
const original = Flag.OPENCODE_EXPERIMENTAL_HTTPAPI
const websocket = (() => () => new Response(null, { status: 501 })) as unknown as UpgradeWebSocket
function app() {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = true
return InstanceRoutes(websocket)
}
function runSession<A, E>(fx: Effect.Effect<A, E, Session.Service>) {
return Effect.runPromise(fx.pipe(Effect.provide(Session.defaultLayer)))
}
function pathFor(path: string, params: Record<string, string>) {
return Object.entries(params).reduce((result, [key, value]) => result.replace(`:${key}`, value), path)
}
async function createSession(directory: string, input?: Session.CreateInput) {
return Instance.provide({
directory,
fn: async () => runSession(Session.Service.use((svc) => svc.create(input))),
})
}
async function createTextMessage(directory: string, sessionID: SessionID, text: string) {
return Instance.provide({
directory,
fn: async () =>
runSession(
Effect.gen(function* () {
const svc = yield* Session.Service
const info = yield* svc.updateMessage({
id: MessageID.ascending(),
role: "user",
sessionID,
agent: "build",
model: { providerID: ProviderID.make("test"), modelID: ModelID.make("test") },
time: { created: Date.now() },
})
const part = yield* svc.updatePart({
id: PartID.ascending(),
sessionID,
messageID: info.id,
type: "text",
text,
})
return { info, part }
}),
),
})
}
async function json<T>(response: Response) {
if (response.status !== 200) throw new Error(await response.text())
return (await response.json()) as T
}
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = original
await Instance.disposeAll()
await resetDatabase()
})
describe("session HttpApi", () => {
test("serves read routes through Hono bridge", async () => {
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } })
const headers = { "x-opencode-directory": tmp.path }
const parent = await createSession(tmp.path, { title: "parent" })
const child = await createSession(tmp.path, { title: "child", parentID: parent.id })
const message = await createTextMessage(tmp.path, parent.id, "hello")
await createTextMessage(tmp.path, parent.id, "world")
expect(
(await json<Session.Info[]>(await app().request(`${SessionPaths.list}?roots=true`, { headers }))).map(
(item) => item.id,
),
).toContain(parent.id)
expect(await json<Record<string, unknown>>(await app().request(SessionPaths.status, { headers }))).toEqual({})
expect(
await json<Session.Info>(await app().request(pathFor(SessionPaths.get, { sessionID: parent.id }), { headers })),
).toMatchObject({ id: parent.id, title: "parent" })
expect(
(
await json<Session.Info[]>(
await app().request(pathFor(SessionPaths.children, { sessionID: parent.id }), { headers }),
)
).map((item) => item.id),
).toEqual([child.id])
expect(
await json<unknown[]>(await app().request(pathFor(SessionPaths.todo, { sessionID: parent.id }), { headers })),
).toEqual([])
expect(
await json<unknown[]>(await app().request(pathFor(SessionPaths.diff, { sessionID: parent.id }), { headers })),
).toEqual([])
const messages = await app().request(`${pathFor(SessionPaths.messages, { sessionID: parent.id })}?limit=1`, {
headers,
})
const messagePage = await json<MessageV2.WithParts[]>(messages)
const nextCursor = messages.headers.get("x-next-cursor")
expect(nextCursor).toBeTruthy()
expect(messagePage[0]?.parts[0]).toMatchObject({ type: "text" })
expect(
(
await app().request(`${pathFor(SessionPaths.messages, { sessionID: parent.id })}?before=${nextCursor}`, {
headers,
})
).status,
).toBe(400)
expect(
(
await app().request(`${pathFor(SessionPaths.messages, { sessionID: parent.id })}?limit=1&before=invalid`, {
headers,
})
).status,
).toBe(400)
expect(
await json<MessageV2.WithParts>(
await app().request(pathFor(SessionPaths.message, { sessionID: parent.id, messageID: message.info.id }), {
headers,
}),
),
).toMatchObject({ info: { id: message.info.id } })
})
test("serves lifecycle mutation routes through Hono bridge", async () => {
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false, share: "disabled" } })
const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" }
const created = await json<Session.Info>(
await app().request(SessionPaths.create, {
method: "POST",
headers,
body: JSON.stringify({ title: "created" }),
}),
)
expect(created.title).toBe("created")
const updated = await json<Session.Info>(
await app().request(pathFor(SessionPaths.update, { sessionID: created.id }), {
method: "PATCH",
headers,
body: JSON.stringify({ title: "updated", time: { archived: 1 } }),
}),
)
expect(updated).toMatchObject({ id: created.id, title: "updated", time: { archived: 1 } })
const forked = await json<Session.Info>(
await app().request(pathFor(SessionPaths.fork, { sessionID: created.id }), {
method: "POST",
headers,
body: JSON.stringify({}),
}),
)
expect(forked.id).not.toBe(created.id)
expect(
await json<boolean>(
await app().request(pathFor(SessionPaths.abort, { sessionID: created.id }), { method: "POST", headers }),
),
).toBe(true)
expect(
await json<boolean>(
await app().request(pathFor(SessionPaths.remove, { sessionID: created.id }), { method: "DELETE", headers }),
),
).toBe(true)
})
test("serves message mutation routes through Hono bridge", async () => {
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } })
const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" }
const session = await createSession(tmp.path, { title: "messages" })
const first = await createTextMessage(tmp.path, session.id, "first")
const second = await createTextMessage(tmp.path, session.id, "second")
const updated = await json<MessageV2.Part>(
await app().request(
pathFor(SessionPaths.updatePart, {
sessionID: session.id,
messageID: first.info.id,
partID: first.part.id,
}),
{
method: "PATCH",
headers,
body: JSON.stringify({ ...first.part, text: "updated" }),
},
),
)
expect(updated).toMatchObject({ id: first.part.id, type: "text", text: "updated" })
expect(
await json<boolean>(
await app().request(
pathFor(SessionPaths.deletePart, {
sessionID: session.id,
messageID: first.info.id,
partID: first.part.id,
}),
{ method: "DELETE", headers },
),
),
).toBe(true)
expect(
await json<boolean>(
await app().request(pathFor(SessionPaths.deleteMessage, { sessionID: session.id, messageID: second.info.id }), {
method: "DELETE",
headers,
}),
),
).toBe(true)
})
test("serves remaining non-LLM session mutation routes through Hono bridge", async () => {
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } })
const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" }
const session = await createSession(tmp.path, { title: "remaining" })
expect(
await json<Session.Info>(
await app().request(pathFor(SessionPaths.revert, { sessionID: session.id }), {
method: "POST",
headers,
body: JSON.stringify({ messageID: MessageID.ascending() }),
}),
),
).toMatchObject({ id: session.id })
expect(
await json<Session.Info>(
await app().request(pathFor(SessionPaths.unrevert, { sessionID: session.id }), {
method: "POST",
headers,
}),
),
).toMatchObject({ id: session.id })
expect(
await json<boolean>(
await app().request(
pathFor(SessionPaths.permissions, {
sessionID: session.id,
permissionID: String(PermissionID.ascending()),
}),
{
method: "POST",
headers,
body: JSON.stringify({ response: "once" }),
},
),
),
).toBe(true)
})
})

View file

@ -0,0 +1,84 @@
import { afterEach, describe, expect, test } from "bun:test"
import type { UpgradeWebSocket } from "hono/ws"
import { Effect } from "effect"
import { Flag } from "@opencode-ai/core/flag/flag"
import { Instance } from "../../src/project/instance"
import { InstanceRoutes } from "../../src/server/routes/instance"
import { SyncPaths } from "../../src/server/routes/instance/httpapi/sync"
import { Session } from "../../src/session"
import { Log } from "../../src/util"
import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
const originalHttpApi = Flag.OPENCODE_EXPERIMENTAL_HTTPAPI
const originalWorkspaces = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES
const websocket = (() => () => new Response(null, { status: 501 })) as unknown as UpgradeWebSocket
function app() {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = true
return InstanceRoutes(websocket)
}
function runSession<A, E>(fx: Effect.Effect<A, E, Session.Service>) {
return Effect.runPromise(fx.pipe(Effect.provide(Session.defaultLayer)))
}
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = originalHttpApi
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
await Instance.disposeAll()
await resetDatabase()
})
describe("sync HttpApi", () => {
test("serves sync routes through Hono bridge", async () => {
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true
await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } })
const headers = { "x-opencode-directory": tmp.path, "content-type": "application/json" }
const session = await Instance.provide({
directory: tmp.path,
fn: async () => runSession(Session.Service.use((svc) => svc.create({ title: "sync" }))),
})
const started = await app().request(SyncPaths.start, { method: "POST", headers })
expect(started.status).toBe(200)
expect(await started.json()).toBe(true)
const history = await app().request(SyncPaths.history, {
method: "POST",
headers,
body: JSON.stringify({}),
})
expect(history.status).toBe(200)
const rows = (await history.json()) as Array<{
id: string
aggregate_id: string
seq: number
type: string
data: Record<string, unknown>
}>
expect(rows.map((row) => row.aggregate_id)).toContain(session.id)
const replayed = await app().request(SyncPaths.replay, {
method: "POST",
headers,
body: JSON.stringify({
directory: tmp.path,
events: rows
.filter((row) => row.aggregate_id === session.id)
.map((row) => ({
id: row.id,
aggregateID: row.aggregate_id,
seq: row.seq,
type: row.type,
data: row.data,
})),
}),
})
expect(replayed.status).toBe(200)
expect(await replayed.json()).toEqual({ sessionID: session.id })
})
})

View file

@ -1,7 +1,14 @@
import { afterEach, describe, expect, test } from "bun:test"
import { Context } from "effect"
import { mkdir } from "node:fs/promises"
import path from "node:path"
import { Context, Effect } from "effect"
import { Flag } from "@opencode-ai/core/flag/flag"
import { registerAdaptor } from "../../src/control-plane/adaptors"
import type { WorkspaceAdaptor } from "../../src/control-plane/types"
import { Workspace } from "../../src/control-plane/workspace"
import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server"
import { WorkspacePaths } from "../../src/server/routes/instance/httpapi/workspace"
import { Session } from "../../src/session"
import { Log } from "../../src/util"
import { resetDatabase } from "../fixture/db"
import { tmpdir } from "../fixture/fixture"
@ -10,19 +17,50 @@ import { Instance } from "../../src/project/instance"
void Log.init({ print: false })
const context = Context.empty() as Context.Context<unknown>
const originalWorkspaces = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES
function request(path: string, directory: string) {
function request(path: string, directory: string, init: RequestInit = {}) {
const headers = new Headers(init.headers)
headers.set("x-opencode-directory", directory)
return ExperimentalHttpApiServer.webHandler().handler(
new Request(`http://localhost${path}`, {
headers: {
"x-opencode-directory": directory,
},
...init,
headers,
}),
context,
)
}
function runSession<A, E>(fx: Effect.Effect<A, E, Session.Service>) {
return Effect.runPromise(fx.pipe(Effect.provide(Session.defaultLayer)))
}
function localAdaptor(directory: string): WorkspaceAdaptor {
return {
name: "Local Test",
description: "Create a local test workspace",
configure(info) {
return {
...info,
name: "local-test",
directory,
}
},
async create() {
await mkdir(directory, { recursive: true })
},
async remove() {},
target() {
return {
type: "local" as const,
directory,
}
},
}
}
afterEach(async () => {
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = originalWorkspaces
await Instance.disposeAll()
await resetDatabase()
})
@ -52,4 +90,43 @@ describe("workspace HttpApi", () => {
expect(status.status).toBe(200)
expect(await status.json()).toEqual([])
})
test("serves mutation endpoints", async () => {
Flag.OPENCODE_EXPERIMENTAL_WORKSPACES = true
await using tmp = await tmpdir({ git: true })
await Instance.provide({
directory: tmp.path,
fn: async () =>
registerAdaptor(Instance.project.id, "local-test", localAdaptor(path.join(tmp.path, ".workspace"))),
})
const created = await request(WorkspacePaths.list, tmp.path, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ type: "local-test", branch: null, extra: null }),
})
expect(created.status).toBe(200)
const workspace = (await created.json()) as Workspace.Info
expect(workspace).toMatchObject({ type: "local-test", name: "local-test" })
const session = await Instance.provide({
directory: tmp.path,
fn: async () => runSession(Session.Service.use((svc) => svc.create({}))),
})
const restored = await request(WorkspacePaths.sessionRestore.replace(":id", workspace.id), tmp.path, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ sessionID: session.id }),
})
expect(restored.status).toBe(200)
expect((await restored.json()) as { total: number }).toMatchObject({ total: expect.any(Number) })
const removed = await request(WorkspacePaths.remove.replace(":id", workspace.id), tmp.path, { method: "DELETE" })
expect(removed.status).toBe(200)
expect(await removed.json()).toMatchObject({ id: workspace.id })
const listed = await request(WorkspacePaths.list, tmp.path)
expect(listed.status).toBe(200)
expect(await listed.json()).toEqual([])
})
})

View file

@ -873,6 +873,79 @@ describe("session.message-v2.toModelMessage", () => {
])
})
test("preserves OpenRouter reasoning details through provider transform", async () => {
const assistantID = "m-assistant"
const openrouterModel: Provider.Model = {
...model,
id: ModelID.make("deepseek/deepseek-v4-pro"),
providerID: ProviderID.make("openrouter"),
api: {
id: "deepseek/deepseek-v4-pro",
url: "https://openrouter.ai/api/v1",
npm: "@openrouter/ai-sdk-provider",
},
capabilities: {
...model.capabilities,
reasoning: true,
interleaved: { field: "reasoning_details" },
},
}
const reasoningDetails = [
{
type: "reasoning.text",
text: "thinking",
format: "unknown",
index: 0,
},
]
const input: MessageV2.WithParts[] = [
{
info: assistantInfo(assistantID, "m-parent", undefined, {
providerID: openrouterModel.providerID,
modelID: openrouterModel.id,
}),
parts: [
{
...basePart(assistantID, "a1"),
type: "reasoning",
text: "thinking",
time: { start: 0 },
metadata: {
openrouter: {
reasoning_details: reasoningDetails,
},
},
},
{
...basePart(assistantID, "a2"),
type: "text",
text: "answer",
},
] as MessageV2.Part[],
},
]
expect(
ProviderTransform.message(await MessageV2.toModelMessages(input, openrouterModel), openrouterModel, {}),
).toStrictEqual([
{
role: "assistant",
content: [
{
type: "reasoning",
text: "thinking",
providerOptions: {
openrouter: {
reasoning_details: reasoningDetails,
},
},
},
{ type: "text", text: "answer" },
],
},
])
})
test("splits assistant messages on step-start boundaries", async () => {
const assistantID = "m-assistant"

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.14.25",
"version": "1.14.26",
"type": "module",
"license": "MIT",
"scripts": {
@ -22,8 +22,8 @@
"zod": "catalog:"
},
"peerDependencies": {
"@opentui/core": ">=0.1.103",
"@opentui/solid": ">=0.1.103"
"@opentui/core": ">=0.1.104",
"@opentui/solid": ">=0.1.104"
},
"peerDependenciesMeta": {
"@opentui/core": {

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.14.25",
"version": "1.14.26",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.14.25",
"version": "1.14.26",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.14.25",
"version": "1.14.26",
"type": "module",
"license": "MIT",
"exports": {

View file

@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.14.25",
"version": "1.14.26",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",

View file

@ -84,22 +84,22 @@ OpenCode Go حاليًا في المرحلة التجريبية.
يوضح الجدول أدناه عددًا تقديريًا للطلبات بناءً على أنماط استخدام Go المعتادة:
| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر |
| ----------------- | ------------------- | ------------------ | ---------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | الطلبات لكل 5 ساعات | الطلبات في الأسبوع | الطلبات في الشهر |
| ------------------ | ------------------- | ------------------ | ---------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
تستند التقديرات إلى متوسطات أنماط الطلبات المرصودة:
@ -140,8 +140,8 @@ OpenCode Go حاليًا في المرحلة التجريبية.
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -155,6 +155,16 @@ OpenCode Go حاليًا في المرحلة التجريبية.
---
### النماذج
يمكنك جلب القائمة الكاملة بالنماذج المتاحة وبياناتها الوصفية من:
```
https://opencode.ai/zen/go/v1/models
```
---
## الخصوصية
صُمّمت هذه الخطة أساسًا للمستخدمين الدوليين، مع استضافة النماذج في الولايات المتحدة والاتحاد الأوروبي وسنغافورة لضمان وصول عالمي مستقر. ويتّبع مزودونا سياسة عدم الاحتفاظ بالبيانات، ولا يستخدمون بياناتك لتدريب النماذج.

View file

@ -144,7 +144,6 @@ https://opencode.ai/zen/v1/models
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -204,15 +203,23 @@ https://opencode.ai/zen/v1/models
### النماذج المهملة
| النموذج | تاريخ الإيقاف |
| ---------------- | ------------- |
| MiniMax M2.1 | 15 مارس 2026 |
| GLM 4.7 | 15 مارس 2026 |
| GLM 4.6 | 15 مارس 2026 |
| Gemini 3 Pro | 9 مارس 2026 |
| Kimi K2 Thinking | 6 مارس 2026 |
| Kimi K2 | 6 مارس 2026 |
| Qwen3 Coder 480B | 6 فبراير 2026 |
| النموذج | تاريخ الإيقاف |
| ------------------ | -------------- |
| GPT 5.2 Codex | 23 يوليو 2026 |
| GPT 5.1 Codex | 23 يوليو 2026 |
| GPT 5.1 Codex Max | 23 يوليو 2026 |
| GPT 5.1 Codex Mini | 23 يوليو 2026 |
| GPT 5 Codex | 23 يوليو 2026 |
| Claude Sonnet 4 | 15 يونيو 2026 |
| GLM 5 | 14 مايو 2026 |
| MiniMax M2.1 | 15 مارس 2026 |
| GLM 4.7 | 15 مارس 2026 |
| GLM 4.6 | 15 مارس 2026 |
| Gemini 3 Pro | 9 مارس 2026 |
| Kimi K2 Thinking | 6 مارس 2026 |
| Kimi K2 | 6 مارس 2026 |
| Claude Haiku 3.5 | 16 فبراير 2026 |
| Qwen3 Coder 480B | 6 فبراير 2026 |
---

View file

@ -94,22 +94,22 @@ Ograničenja su definisana u dolarskoj vrijednosti. To znači da vaš stvarni br
Tabela ispod pruža procijenjeni broj zahtjeva na osnovu tipičnih obrazaca korištenja Go pretplate:
| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno |
| ----------------- | ------------------ | ----------------- | ----------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | zahtjeva na 5 sati | zahtjeva sedmično | zahtjeva mjesečno |
| ------------------ | ------------------ | ----------------- | ----------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Procjene se zasnivaju na zapaženim prosječnim obrascima zahtjeva:
@ -152,8 +152,8 @@ Također možete pristupiti Go modelima putem sljedećih API endpointa.
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -169,6 +169,16 @@ koristi format `opencode-go/<model-id>`. Na primjer, za Kimi K2.6, koristili bis
---
### Modeli
Pun spisak dostupnih modela i njihovih metapodataka možete preuzeti na:
```
https://opencode.ai/zen/go/v1/models
```
---
## Privatnost
Plan je prvenstveno namijenjen međunarodnim korisnicima, a modeli su smješteni u US, EU i Singaporeu radi stabilnog globalnog pristupa. Naši pružaoci usluga primjenjuju politiku nultog zadržavanja podataka i ne koriste vaše podatke za treniranje modela.

View file

@ -151,7 +151,6 @@ Podržavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**.
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -215,15 +214,23 @@ vam ipak može naplatiti više od $20 ako vam stanje padne ispod $5.
### Zastarjeli modeli
| Model | Datum zastarijevanja |
| ---------------- | -------------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Model | Datum zastarijevanja |
| ------------------ | -------------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -94,22 +94,22 @@ Grænserne er defineret i dollarværdi. Det betyder, at dit faktiske antal anmod
Tabellen nedenfor giver et estimeret antal anmodninger baseret på typiske Go-forbrugsmønstre:
| Model | anmodninger pr. 5 timer | anmodninger pr. uge | anmodninger pr. måned |
| ----------------- | ----------------------- | ------------------- | --------------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | anmodninger pr. 5 timer | anmodninger pr. uge | anmodninger pr. måned |
| ------------------ | ----------------------- | ------------------- | --------------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Estimaterne er baseret på observerede gennemsnitlige anmodningsmønstre:
@ -152,8 +152,8 @@ Du kan også få adgang til Go-modeller gennem følgende API-endpoints.
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -169,6 +169,16 @@ bruge `opencode-go/kimi-k2.6` i din config.
---
### Modeller
Du kan hente den fulde liste over tilgængelige modeller og deres metadata fra:
```
https://opencode.ai/zen/go/v1/models
```
---
## Privatliv
Planen er primært designet til internationale brugere med modeller hostet i US, EU og Singapore for stabil global adgang. Vores udbydere følger en zero-retention-policy og bruger ikke dine data til modeltræning.

View file

@ -151,7 +151,6 @@ Vi understøtter en pay-as-you-go-model. Nedenfor er priserne **pr. 1M tokens**.
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -214,15 +213,23 @@ at opkræve dig mere end $20, hvis din saldo kommer under $5.
### Udfasede modeller
| Model | Udfasningsdato |
| ---------------- | -------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Model | Udfasningsdato |
| ------------------ | -------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -86,22 +86,22 @@ Limits sind in Dollarwerten definiert. Das bedeutet, dass die tatsächliche Anza
Die folgende Tabelle zeigt eine geschätzte Anzahl von Anfragen basierend auf typischen Go-Nutzungsmustern:
| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat |
| ----------------- | ---------------------- | ------------------ | ------------------ |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | Anfragen pro 5 Stunden | Anfragen pro Woche | Anfragen pro Monat |
| ------------------ | ---------------------- | ------------------ | ------------------ |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Die Schätzungen basieren auf beobachteten durchschnittlichen Anfragemustern:
@ -142,8 +142,8 @@ Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen.
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -157,6 +157,16 @@ Die [Modell-ID](/docs/config/#models) in deiner OpenCode Config verwendet das Fo
---
### Models
Du kannst die vollständige Liste der verfügbaren Modelle und ihrer Metadaten hier abrufen:
```
https://opencode.ai/zen/go/v1/models
```
---
## Datenschutz
Der Plan ist in erster Linie für internationale Nutzer konzipiert, mit in US, EU und Singapore gehosteten Modellen für einen stabilen weltweiten Zugriff. Unsere Anbieter befolgen eine Zero-Retention-Richtlinie und verwenden Ihre Daten nicht für das Modelltraining.

View file

@ -140,7 +140,6 @@ Wir unterstützen ein Pay-as-you-go-Modell. Unten findest du die Preise **pro 1M
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -200,15 +199,23 @@ Angenommen, du setzt ein monatliches Nutzungslimit von $20, dann wird Zen in ein
### Veraltete Modelle
| Model | Deprecation date |
| ---------------- | ---------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Model | Deprecation date |
| ------------------ | ---------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -94,22 +94,22 @@ Los límites se definen en valor en dólares. Esto significa que tu cantidad rea
La siguiente tabla proporciona 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.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | peticiones por 5 horas | peticiones por semana | peticiones por mes |
| ------------------ | ---------------------- | --------------------- | ------------------ |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Las estimaciones se basan en los patrones de peticiones promedio observados:
@ -152,8 +152,8 @@ También puedes acceder a los modelos de Go a través de los siguientes endpoint
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -169,6 +169,16 @@ usa el formato `opencode-go/<model-id>`. Por ejemplo, para Kimi K2.6, usarías
---
### Modelos
Puedes obtener la lista completa de modelos disponibles y sus metadatos desde:
```
https://opencode.ai/zen/go/v1/models
```
---
## Privacidad
El plan está diseñado principalmente para usuarios internacionales, con modelos alojados en US, EU y Singapore para ofrecer un acceso global estable. Nuestros proveedores siguen una política de retención cero y no utilizan tus datos para el entrenamiento de modelos.

View file

@ -151,7 +151,6 @@ Admitimos un modelo de pago por uso. A continuación se muestran los precios **p
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -214,15 +213,23 @@ cobrándote más de $20 si tu saldo baja de $5.
### Modelos obsoletos
| Modelo | Fecha de retirada |
| ---------------- | ----------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Modelo | Fecha de retirada |
| ------------------ | ----------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -84,22 +84,22 @@ Les limites sont définies en valeur monétaire (dollars). Cela signifie que vot
Le tableau ci-dessous fournit une estimation du nombre de requêtes basée sur des modèles d'utilisation typiques de Go :
| Model | requêtes par 5 heures | requêtes par semaine | requêtes par mois |
| ----------------- | --------------------- | -------------------- | ----------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | requêtes par 5 heures | requêtes par semaine | requêtes par mois |
| ------------------ | --------------------- | -------------------- | ----------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Les estimations sont basées sur les modèles de requêtes moyens observés :
@ -140,8 +140,8 @@ Vous pouvez également accéder aux modèles Go via les points de terminaison d'
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -155,6 +155,16 @@ L'[ID de modèle](/docs/config/#models) dans votre configuration OpenCode utilis
---
### Modèles
Vous pouvez récupérer la liste complète des modèles disponibles et leurs métadonnées à partir de :
```
https://opencode.ai/zen/go/v1/models
```
---
## Confidentialité
Cette offre est conçue avant tout pour les utilisateurs internationaux, avec des modèles hébergés aux US, dans lEU et à Singapore afin dassurer un accès mondial stable. Nos fournisseurs appliquent une politique de rétention zéro et nutilisent pas vos données pour lentraînement des modèles.

View file

@ -140,7 +140,6 @@ Nous prenons en charge un modèle de paiement à l'utilisation. Vous trouverez c
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -200,15 +199,23 @@ Par exemple, si vous définissez une limite d'utilisation mensuelle à $20, Zen
### Modèles obsolètes
| Modèle | Date de dépréciation |
| ---------------- | -------------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Modèle | Date de dépréciation |
| ------------------ | -------------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -94,22 +94,22 @@ Limits are defined in dollar value. This means your actual request count depends
The table below provides an estimated request count based on typical Go usage patterns:
| Model | requests per 5 hour | requests per week | requests per month |
| ----------------- | ------------------- | ----------------- | ------------------ |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | requests per 5 hour | requests per week | requests per month |
| ------------------ | ------------------- | ----------------- | ------------------ |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Estimates are based on observed average request patterns:
@ -152,8 +152,8 @@ You can also access Go models through the following API endpoints.
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -169,6 +169,16 @@ use `opencode-go/kimi-k2.6` in your config.
---
### Models
You can fetch the full list of available models and their metadata from:
```
https://opencode.ai/zen/go/v1/models
```
---
## Privacy
The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access. Our providers follow a zero-retention policy and do not use your data for model training.

View file

@ -92,22 +92,22 @@ I limiti sono definiti in valore in dollari. Questo significa che il conteggio e
La tabella seguente fornisce una stima del conteggio delle richieste in base a pattern di utilizzo tipici di Go:
| Model | richieste ogni 5 ore | richieste a settimana | richieste al mese |
| ----------------- | -------------------- | --------------------- | ----------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | richieste ogni 5 ore | richieste a settimana | richieste al mese |
| ------------------ | -------------------- | --------------------- | ----------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Le stime si basano sui pattern medi di richieste osservati:
@ -150,8 +150,8 @@ Puoi anche accedere ai modelli Go tramite i seguenti endpoint API.
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -167,6 +167,16 @@ utilizza il formato `opencode-go/<model-id>`. Ad esempio, per Kimi K2.6, userest
---
### Modelli
Puoi recuperare l'elenco completo dei modelli disponibili e i relativi metadati da:
```
https://opencode.ai/zen/go/v1/models
```
---
## Privacy
Il piano è pensato principalmente per gli utenti internazionali, con modelli ospitati negli US, nellEU e a Singapore per un accesso globale stabile. I nostri provider seguono una politica di zero-retention e non utilizzano i tuoi dati per laddestramento dei modelli.

View file

@ -151,7 +151,6 @@ Supportiamo un modello pay-as-you-go. Qui sotto trovi i prezzi **per 1M token**.
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -214,15 +213,23 @@ per addebitarti più di $20 se il tuo saldo scende sotto $5.
### Modelli deprecati
| Modello | Data di deprecazione |
| ---------------- | -------------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Modello | Data di deprecazione |
| ------------------ | -------------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -84,22 +84,22 @@ OpenCode Goには以下の制限が含まれています
以下の表は、一般的なGoの利用パターンに基づいた推定リクエスト数を示しています
| Model | 5時間あたりのリクエスト数 | 週間リクエスト数 | 月間リクエスト数 |
| ----------------- | ------------------------- | ---------------- | ---------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | 5時間あたりのリクエスト数 | 週間リクエスト数 | 月間リクエスト数 |
| ------------------ | ------------------------- | ---------------- | ---------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
推定値は、観測された平均的なリクエストパターンに基づいています:
@ -140,8 +140,8 @@ Zen残高にクレジットがある場合は、コンソールで**Use balance*
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -155,6 +155,16 @@ OpenCode設定の[model id](/docs/config/#models)は、`opencode-go/<model-id>`
---
### モデル
利用可能なモデルとそのメタデータの完全な一覧は、次から取得できます。
```
https://opencode.ai/zen/go/v1/models
```
---
## プライバシー
このプランは主に海外ユーザー向けに設計されており、安定したグローバルアクセスのため、モデルは US、EU、Singapore でホストされています。各プロバイダーはデータを保持しないポリシーに従っており、お客様のデータをモデルのトレーニングに使用することはありません。

View file

@ -140,7 +140,6 @@ https://opencode.ai/zen/v1/models
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -200,15 +199,23 @@ https://opencode.ai/zen/v1/models
### 非推奨モデル
| Model | Deprecation date |
| ---------------- | ---------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Model | Deprecation date |
| ------------------ | ---------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -84,22 +84,22 @@ OpenCode Go에는 다음과 같은 한도가 포함됩니다.
아래 표는 일반적인 Go 사용 패턴을 기준으로 한 예상 요청 횟수를 보여줍니다.
| Model | 5시간당 요청 횟수 | 주간 요청 횟수 | 월간 요청 횟수 |
| ----------------- | ----------------- | -------------- | -------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | 5시간당 요청 횟수 | 주간 요청 횟수 | 월간 요청 횟수 |
| ------------------ | ----------------- | -------------- | -------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
예상치는 관찰된 평균 요청 패턴을 기준으로 합니다.
@ -140,8 +140,8 @@ Zen 잔액에 크레딧도 있다면, console에서 **Use balance** 옵션을
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -155,6 +155,16 @@ OpenCode config의 [model id](/docs/config/#models)는 `opencode-go/<model-id>`
---
### 모델
사용 가능한 전체 모델 목록과 메타데이터는 다음에서 가져올 수 있습니다.
```
https://opencode.ai/zen/go/v1/models
```
---
## 개인정보 보호
이 플랜은 안정적인 전 세계 액세스를 위해 모델을 미국, EU, 싱가포르에 호스팅하며, 주로 해외 사용자를 위해 설계되었습니다. 저희 제공자는 zero-retention 정책을 따르며, 고객 데이터를 모델 학습에 사용하지 않습니다.

View file

@ -140,7 +140,6 @@ https://opencode.ai/zen/v1/models
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -200,15 +199,23 @@ https://opencode.ai/zen/v1/models
### 지원 중단 모델
| 모델 | 지원 중단 날짜 |
| ---------------- | -------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| 모델 | 지원 중단 날짜 |
| ------------------ | -------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -94,22 +94,22 @@ Grensene er definert i dollarverdi. Dette betyr at ditt faktiske antall forespø
Tabellen nedenfor gir et estimert antall forespørsler basert på typiske bruksmønstre for Go:
| Model | forespørsler per 5 timer | forespørsler per uke | forespørsler per måned |
| ----------------- | ------------------------ | -------------------- | ---------------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | forespørsler per 5 timer | forespørsler per uke | forespørsler per måned |
| ------------------ | ------------------------ | -------------------- | ---------------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Estimatene er basert på observerte gjennomsnittlige forespørselsmønstre:
@ -152,8 +152,8 @@ Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter.
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -169,6 +169,16 @@ bruke `opencode-go/kimi-k2.6` i konfigurasjonen din.
---
### Modeller
Du kan hente hele listen over tilgjengelige modeller og metadataene deres fra:
```
https://opencode.ai/zen/go/v1/models
```
---
## Personvern
Planen er primært utformet for internasjonale brukere, med modeller hostet i US, EU og Singapore for stabil global tilgang. Våre leverandører følger en zero-retention-policy og bruker ikke dataene dine til modelltrening.

View file

@ -151,7 +151,6 @@ Vi støtter en pay-as-you-go-modell. Nedenfor er prisene **per 1M tokens**.
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -214,15 +213,23 @@ med å belaste deg mer enn $20 hvis saldoen din går under $5.
### Utfasede modeller
| Modell | Utfasingsdato |
| ---------------- | -------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Modell | Utfasingsdato |
| ------------------ | -------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -88,22 +88,22 @@ Limity są zdefiniowane w wartości w dolarach. Oznacza to, że rzeczywista licz
Poniższa tabela przedstawia szacunkową liczbę żądań na podstawie typowych wzorców korzystania z Go:
| Model | żądania na 5 godzin | żądania na tydzień | żądania na miesiąc |
| ----------------- | ------------------- | ------------------ | ------------------ |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | żądania na 5 godzin | żądania na tydzień | żądania na miesiąc |
| ------------------ | ------------------- | ------------------ | ------------------ |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Szacunki opierają się na zaobserwowanych średnich wzorcach żądań:
@ -144,8 +144,8 @@ Możesz również uzyskać dostęp do modeli Go za pośrednictwem następującyc
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -161,6 +161,16 @@ używa formatu `opencode-go/<model-id>`. Na przykład dla Kimi K2.6 należy uży
---
### Modele
Pełną listę dostępnych modeli i ich metadane możesz pobrać z:
```
https://opencode.ai/zen/go/v1/models
```
---
## Prywatność
Plan został zaprojektowany przede wszystkim z myślą o użytkownikach międzynarodowych, a modele są hostowane w US, EU i Singapore, aby zapewnić stabilny dostęp na całym świecie. Nasi dostawcy stosują politykę zerowej retencji i nie wykorzystują Twoich danych do trenowania modeli.

View file

@ -151,7 +151,6 @@ Obsługujemy model pay-as-you-go. Poniżej znajdują się ceny **za 1M tokenów*
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -213,17 +212,25 @@ ostatecznie obciążyć Cię kwotą wyższą niż $20, jeśli Twoje saldo spadni
---
### Deprecated models
### Wycofane modele
| Model | Deprecation date |
| ---------------- | ---------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Model | Data wycofania |
| ------------------ | -------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -94,22 +94,22 @@ Os limites são definidos em valor em dólares. Isso significa que a sua contage
A tabela abaixo fornece uma contagem estimada de requisições com base nos padrões típicos de uso do Go:
| Model | requisições por 5 horas | requisições por semana | requisições por mês |
| ----------------- | ----------------------- | ---------------------- | ------------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | requisições por 5 horas | requisições por semana | requisições por mês |
| ------------------ | ----------------------- | ---------------------- | ------------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
As estimativas baseiam-se nos padrões médios de requisições observados:
@ -152,8 +152,8 @@ Você também pode acessar os modelos do Go através dos seguintes endpoints de
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -169,6 +169,16 @@ usa o formato `opencode-go/<model-id>`. Por exemplo, para o Kimi K2.6, você usa
---
### Modelos
Você pode buscar a lista completa de modelos disponíveis e seus metadados em:
```
https://opencode.ai/zen/go/v1/models
```
---
## Privacidade
O plano foi projetado principalmente para usuários internacionais, com modelos hospedados em US, EU e Singapore para garantir acesso global estável. Nossos provedores seguem uma política de retenção zero e não usam seus dados para treinamento de modelos.

View file

@ -140,7 +140,6 @@ Oferecemos um modelo pay-as-you-go. Abaixo estão os preços **por 1M tokens**.
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -200,15 +199,23 @@ Por exemplo, digamos que você defina um limite mensal de uso de $20; o Zen não
### Modelos obsoletos
| Modelo | Data de descontinuação |
| ---------------- | ---------------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Modelo | Data de descontinuação |
| ------------------ | ---------------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -94,22 +94,22 @@ OpenCode Go включает следующие лимиты:
В таблице ниже приведено примерное количество запросов на основе типичных сценариев использования Go:
| Model | запросов за 5 часов | запросов в неделю | запросов в месяц |
| ----------------- | ------------------- | ----------------- | ---------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | запросов за 5 часов | запросов в неделю | запросов в месяц |
| ------------------ | ------------------- | ----------------- | ---------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Оценки основаны на наблюдаемых средних показателях запросов:
@ -152,8 +152,8 @@ OpenCode Go включает следующие лимиты:
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -169,6 +169,16 @@ OpenCode Go включает следующие лимиты:
---
### Модели
Вы можете получить полный список доступных моделей и их метаданных по адресу:
```
https://opencode.ai/zen/go/v1/models
```
---
## Конфиденциальность
Этот план разработан в первую очередь для международных пользователей: модели размещены в US, EU и Singapore, чтобы обеспечить стабильный доступ по всему миру. Наши провайдеры придерживаются политики zero-retention и не используют ваши данные для обучения моделей.

View file

@ -151,7 +151,6 @@ https://opencode.ai/zen/v1/models
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -214,15 +213,23 @@ https://opencode.ai/zen/v1/models
### Устаревшие модели
| Модель | Дата устаревания |
| ---------------- | ---------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Модель | Дата устаревания |
| ------------------ | ---------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -84,22 +84,22 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้:
ตารางด้านล่างแสดงจำนวน request โดยประมาณตามรูปแบบการใช้งานปกติของ Go:
| Model | requests ต่อ 5 ชั่วโมง | requests ต่อสัปดาห์ | requests ต่อเดือน |
| ----------------- | ---------------------- | ------------------- | ----------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | requests ต่อ 5 ชั่วโมง | requests ต่อสัปดาห์ | requests ต่อเดือน |
| ------------------ | ---------------------- | ------------------- | ----------------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
การประมาณการอ้างอิงจากรูปแบบการใช้งาน request โดยเฉลี่ยที่สังเกตพบ:
@ -140,8 +140,8 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้:
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -155,6 +155,16 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้:
---
### Models
คุณสามารถดึงรายการโมเดลทั้งหมดที่พร้อมใช้งานและ metadata ของมันได้จาก:
```
https://opencode.ai/zen/go/v1/models
```
---
## Privacy
แพลนนี้ออกแบบมาสำหรับผู้ใช้ทั่วโลกเป็นหลัก โดยโฮสต์โมเดลไว้ใน US, EU และ Singapore เพื่อให้เข้าถึงได้อย่างเสถียรจากทั่วโลก ผู้ให้บริการของเราปฏิบัติตามนโยบาย zero-retention และไม่นำข้อมูลของคุณไปใช้ในการฝึกโมเดล

View file

@ -142,7 +142,6 @@ https://opencode.ai/zen/v1/models
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -200,17 +199,25 @@ https://opencode.ai/zen/v1/models
---
### Deprecated models
### โมเดลที่ถูกยกเลิก
| Model | Deprecation date |
| ---------------- | ---------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Model | Deprecation date |
| ------------------ | ---------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -84,22 +84,22 @@ Limitler dolar değeri üzerinden belirlenmiştir. Bu, gerçek istek sayınızı
Aşağıdaki tablo, tipik Go kullanım modellerine dayalı tahmini bir istek sayısı sunmaktadır:
| Model | 5 saatte bir istek | haftalık istek | aylık istek |
| ----------------- | ------------------ | -------------- | ----------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | 5 saatte bir istek | haftalık istek | aylık istek |
| ------------------ | ------------------ | -------------- | ----------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
Tahminler, gözlemlenen ortalama istek modellerine dayanmaktadır:
@ -140,8 +140,8 @@ Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsi
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -155,6 +155,16 @@ OpenCode yapılandırmanızdaki [model id](/docs/config/#models) formatı `openc
---
### Modeller
Mevcut modellerin tam listesini ve metadata'larını şuradan alabilirsiniz:
```
https://opencode.ai/zen/go/v1/models
```
---
## Gizlilik
Plan, öncelikle uluslararası kullanıcılar için tasarlanmıştır; dünya genelinde istikrarlı erişim sağlamak için modeller US, EU ve Singapore'da barındırılır. Sağlayıcılarımız sıfır veri saklama politikası uygular ve verilerinizi model eğitimi için kullanmaz.

View file

@ -140,7 +140,6 @@ Kullandıkça öde modelini destekliyoruz. Aşağıda **1M token başına** fiya
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -200,15 +199,23 @@ Ayrıca tüm çalışma alanı için ve ekibinizdeki her üye için aylık kulla
### Kullanımdan kaldırılan modeller
| Model | Kullanımdan kaldırılma tarihi |
| ---------------- | ----------------------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Model | Kullanımdan kaldırılma tarihi |
| ------------------ | ----------------------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -151,7 +151,6 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**.
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -214,15 +213,23 @@ charging you more than $20 if your balance goes below $5.
### Deprecated models
| Model | Deprecation date |
| ---------------- | ---------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| Model | Deprecation date |
| ------------------ | ---------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -84,22 +84,22 @@ OpenCode Go 包含以下限制:
下表提供了基于典型 Go 使用模式的预估请求数:
| Model | 每 5 小时请求数 | 每周请求数 | 每月请求数 |
| ----------------- | --------------- | ---------- | ---------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | 每 5 小时请求数 | 每周请求数 | 每月请求数 |
| ------------------ | --------------- | ---------- | ---------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
预估值基于观察到的平均请求模式:
@ -140,8 +140,8 @@ OpenCode Go 包含以下限制:
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -155,6 +155,16 @@ OpenCode Go 包含以下限制:
---
### 模型
你可以从以下地址获取可用模型及其元数据的完整列表:
```
https://opencode.ai/zen/go/v1/models
```
---
## 隐私保护
该方案主要面向国际用户,模型托管在 US、EU 和 Singapore以提供稳定的全球访问。我们的提供商遵循零保留政策不会将您的数据用于模型训练。

View file

@ -140,7 +140,6 @@ https://opencode.ai/zen/v1/models
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -200,15 +199,23 @@ https://opencode.ai/zen/v1/models
### 已弃用模型
| 模型 | 弃用日期 |
| ---------------- | -------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| 模型 | 弃用日期 |
| ------------------ | -------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -84,22 +84,22 @@ OpenCode Go 包含以下限制:
下表提供了基於典型 Go 使用模式的預估請求次數:
| Model | 每 5 小時請求數 | 每週請求數 | 每月請求數 |
| ----------------- | --------------- | ---------- | ---------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 | 2,150 | 5,450 | 10,900 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
| Model | 每 5 小時請求數 | 每週請求數 | 每月請求數 |
| ------------------ | --------------- | ---------- | ---------- |
| GLM-5.1 | 880 | 2,150 | 4,300 |
| GLM-5 | 1,150 | 2,880 | 5,750 |
| Kimi K2.5 | 1,850 | 4,630 | 9,250 |
| Kimi K2.6 | 1,150 | 2,880 | 5,750 |
| MiMo-V2-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2-Omni | 2,150 | 5,450 | 10,900 |
| MiMo-V2.5-Pro | 1,290 | 3,225 | 6,450 |
| MiMo-V2.5 (≤ 256K) | 2,150 | 5,450 | 10,900 |
| Qwen3.6 Plus | 3,300 | 8,200 | 16,300 |
| MiniMax M2.7 | 3,400 | 8,500 | 17,000 |
| MiniMax M2.5 | 6,300 | 15,900 | 31,800 |
| Qwen3.5 Plus | 10,200 | 25,200 | 50,500 |
| DeepSeek V4 Pro | 1,300 | 3,250 | 6,500 |
| DeepSeek V4 Flash | 7,450 | 18,600 | 37,300 |
預估值是基於觀察到的平均請求模式:
@ -140,8 +140,8 @@ OpenCode Go 包含以下限制:
| GLM-5 | glm-5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.5 | kimi-k2.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Kimi K2.6 | kimi-k2.6 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/messages` | `@ai-sdk/anthropic` |
| DeepSeek V4 Pro | deepseek-v4-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| DeepSeek V4 Flash | deepseek-v4-flash | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Pro | mimo-v2-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2-Omni | mimo-v2-omni | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| MiMo-V2.5-Pro | mimo-v2.5-pro | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
@ -155,6 +155,16 @@ OpenCode Go 包含以下限制:
---
### 模型
你可以從以下位置取得所有可用模型及其中繼資料的完整清單:
```
https://opencode.ai/zen/go/v1/models
```
---
## 隱私權
此方案主要為國際使用者設計,模型部署於 US、EU 與 Singapore以提供穩定的全球存取體驗。我們的供應商遵循零保留政策不會將你的資料用於模型訓練。

View file

@ -145,7 +145,6 @@ https://opencode.ai/zen/v1/models
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
| Claude Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
| Gemini 3.1 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
| Gemini 3.1 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
| Gemini 3 Flash | $0.50 | $3.00 | $0.05 | - |
@ -207,15 +206,23 @@ https://opencode.ai/zen/v1/models
### 已棄用模型
| 模型 | 棄用日期 |
| ---------------- | -------------- |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
| 模型 | 棄用日期 |
| ------------------ | -------------- |
| GPT 5.2 Codex | July 23, 2026 |
| GPT 5.1 Codex | July 23, 2026 |
| GPT 5.1 Codex Max | July 23, 2026 |
| GPT 5.1 Codex Mini | July 23, 2026 |
| GPT 5 Codex | July 23, 2026 |
| Claude Sonnet 4 | June 15, 2026 |
| GLM 5 | May 14, 2026 |
| MiniMax M2.1 | March 15, 2026 |
| GLM 4.7 | March 15, 2026 |
| GLM 4.6 | March 15, 2026 |
| Gemini 3 Pro | March 9, 2026 |
| Kimi K2 Thinking | March 6, 2026 |
| Kimi K2 | March 6, 2026 |
| Claude Haiku 3.5 | Feb 16, 2026 |
| Qwen3 Coder 480B | Feb 6, 2026 |
---

View file

@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.14.25",
"version": "1.14.26",
"publisher": "sst-dev",
"repository": {
"type": "git",

View file