From fba5a79c45716989dc0f70d8960324d2a6455b1b Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:40:29 -0600 Subject: [PATCH 01/31] fix: ensure that github copilot plugin properly sets headers when used in other clients than tui (#12316) --- packages/opencode/src/plugin/copilot.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/opencode/src/plugin/copilot.ts b/packages/opencode/src/plugin/copilot.ts index ef41ee38d3..39ea0d00d2 100644 --- a/packages/opencode/src/plugin/copilot.ts +++ b/packages/opencode/src/plugin/copilot.ts @@ -301,17 +301,20 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise { }, ], }, - "chat.headers": async (input, output) => { - if (!input.model.providerID.includes("github-copilot")) return + "chat.headers": async (incoming, output) => { + if (!incoming.model.providerID.includes("github-copilot")) return - if (input.model.api.npm === "@ai-sdk/anthropic") { + if (incoming.model.api.npm === "@ai-sdk/anthropic") { output.headers["anthropic-beta"] = "interleaved-thinking-2025-05-14" } const session = await sdk.session .get({ path: { - id: input.sessionID, + id: incoming.sessionID, + }, + query: { + directory: input.directory, }, throwOnError: true, }) From 7c748ef08925e8dfba364e3d6388537d4e0c1ea9 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 5 Feb 2026 12:47:32 -0500 Subject: [PATCH 02/31] core: silently ignore proxy command failures to prevent config initialization crashes --- packages/opencode/src/config/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index e1110e0927..ed1b155003 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -274,7 +274,7 @@ export namespace Config { ...(proxied() ? ["--no-cache"] : []), ], { cwd: dir }, - ) + ).catch(() => {}) } async function isWritable(dir: string) { From e08705f4ef128f20912925de9d08c41515a9709b Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 5 Feb 2026 13:01:48 -0500 Subject: [PATCH 03/31] zen: opus 4.6 --- packages/web/src/content/docs/zen.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index 27f4c229c5..f9b7e68cdb 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -77,6 +77,7 @@ You can also access our models through the following API endpoints. | Claude Sonnet 4 | claude-sonnet-4 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| Claude Opus 4.6 | claude-opus-4-6 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.5 | claude-opus-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Gemini 3 Pro | gemini-3-pro | `https://opencode.ai/zen/v1/models/gemini-3-pro` | `@ai-sdk/google` | @@ -132,6 +133,8 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | 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 | +| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 | +| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 | | Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 | | Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 | | Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - | From 40ebc34909fdb45a0cce5f73725f52ae5dcf8509 Mon Sep 17 00:00:00 2001 From: Goni Zahavy Date: Thu, 5 Feb 2026 20:23:02 +0200 Subject: [PATCH 04/31] feat(tui): add running spinner to bash tool in TUI (#12317) --- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 8a38d9e6f1..5aba1a56a5 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -1625,6 +1625,7 @@ function BlockTool(props: { function Bash(props: ToolProps) { const { theme } = useTheme() const sync = useSync() + const isRunning = createMemo(() => props.part.state.status === "running") const output = createMemo(() => stripAnsi(props.metadata.output?.trim() ?? "")) const [expanded, setExpanded] = createSignal(false) const lines = createMemo(() => output().split("\n")) @@ -1665,6 +1666,7 @@ function Bash(props: ToolProps) { setExpanded((prev) => !prev) : undefined} > From 47f00d23b3f1e4ba118b5cfe186b329c4a729d92 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 5 Feb 2026 13:23:48 -0500 Subject: [PATCH 05/31] enable 5.3 codex --- packages/opencode/src/plugin/codex.ts | 1 + packages/opencode/src/plugin/index.ts | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/plugin/codex.ts b/packages/opencode/src/plugin/codex.ts index b6f1a96a9f..7658ad55e5 100644 --- a/packages/opencode/src/plugin/codex.ts +++ b/packages/opencode/src/plugin/codex.ts @@ -361,6 +361,7 @@ export async function CodexAuthPlugin(input: PluginInput): Promise { "gpt-5.1-codex-mini", "gpt-5.2", "gpt-5.2-codex", + "gpt-5.3-codex", "gpt-5.1-codex", ]) for (const modelId of Object.keys(provider.models)) { diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts index 627c6f8cf0..7c55970cd0 100644 --- a/packages/opencode/src/plugin/index.ts +++ b/packages/opencode/src/plugin/index.ts @@ -6,13 +6,18 @@ import { createOpencodeClient } from "@opencode-ai/sdk" import { Server } from "../server/server" import { BunProc } from "../bun" import { Instance } from "../project/instance" +import { Flag } from "../flag/flag" import { CodexAuthPlugin } from "./codex" +import { Session } from "../session" +import { NamedError } from "@opencode-ai/util/error" import { CopilotAuthPlugin } from "./copilot" import { gitlabAuthPlugin as GitlabAuthPlugin } from "@gitlab/opencode-gitlab-auth" export namespace Plugin { const log = Log.create({ service: "plugin" }) + const BUILTIN = ["opencode-anthropic-auth@0.0.13"] + // Built-in plugins that are directly imported (not installed from npm) const INTERNAL_PLUGINS: PluginInstance[] = [CodexAuthPlugin, CopilotAuthPlugin, GitlabAuthPlugin] @@ -41,6 +46,9 @@ export namespace Plugin { const plugins = [...(config.plugin ?? [])] if (plugins.length) await Config.waitForDependencies() + if (!Flag.OPENCODE_DISABLE_DEFAULT_PLUGINS) { + plugins.push(...BUILTIN) + } for (let plugin of plugins) { // ignore old codex plugin since it is supported first party now @@ -50,7 +58,24 @@ export namespace Plugin { const lastAtIndex = plugin.lastIndexOf("@") const pkg = lastAtIndex > 0 ? plugin.substring(0, lastAtIndex) : plugin const version = lastAtIndex > 0 ? plugin.substring(lastAtIndex + 1) : "latest" - plugin = await BunProc.install(pkg, version) + const builtin = BUILTIN.some((x) => x.startsWith(pkg + "@")) + plugin = await BunProc.install(pkg, version).catch((err) => { + if (!builtin) throw err + + const message = err instanceof Error ? err.message : String(err) + log.error("failed to install builtin plugin", { + pkg, + version, + error: message, + }) + Bus.publish(Session.Event.Error, { + error: new NamedError.Unknown({ + message: `Failed to install built-in plugin ${pkg}@${version}: ${message}`, + }).toObject(), + }) + + return "" + }) if (!plugin) continue } const mod = await import(plugin) From a0bc65621532a5dfcd41fa08d62dbcaf093a924d Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 5 Feb 2026 18:48:54 +0000 Subject: [PATCH 06/31] release: v1.1.52 --- bun.lock | 30 +++++++++++++------------- packages/app/package.json | 2 +- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++------ packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/util/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 18 files changed, 37 insertions(+), 37 deletions(-) diff --git a/bun.lock b/bun.lock index dd83ee01ff..798822af55 100644 --- a/bun.lock +++ b/bun.lock @@ -23,7 +23,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -73,7 +73,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -107,7 +107,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -134,7 +134,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -158,7 +158,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -182,7 +182,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -213,7 +213,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -242,7 +242,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -258,7 +258,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.1.51", + "version": "1.1.52", "bin": { "opencode": "./bin/opencode", }, @@ -364,7 +364,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -384,7 +384,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.1.51", + "version": "1.1.52", "devDependencies": { "@hey-api/openapi-ts": "0.90.10", "@tsconfig/node22": "catalog:", @@ -395,7 +395,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -408,7 +408,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -450,7 +450,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "zod": "catalog:", }, @@ -461,7 +461,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/app/package.json b/packages/app/package.json index 3a492ed919..81e589e38b 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.1.51", + "version": "1.1.52", "description": "", "type": "module", "exports": { diff --git a/packages/console/app/package.json b/packages/console/app/package.json index d162f1ab0c..045363ea14 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.1.51", + "version": "1.1.52", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 3f69947016..256a817d0f 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.1.51", + "version": "1.1.52", "private": true, "type": "module", "license": "MIT", diff --git a/packages/console/function/package.json b/packages/console/function/package.json index efe6dc4256..19e9da661f 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.1.51", + "version": "1.1.52", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 9da4390c58..5e328cfb6f 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.1.51", + "version": "1.1.52", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 92676ec596..5991ace378 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "1.1.51", + "version": "1.1.52", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 13008747eb..0663f98ed0 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.1.51", + "version": "1.1.52", "private": true, "type": "module", "license": "MIT", diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index eeadfa04f0..8df70b6434 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.1.51" +version = "1.1.52" 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.1.51/opencode-darwin-arm64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.52/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.51/opencode-darwin-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.52/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.51/opencode-linux-arm64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.52/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.1.51/opencode-linux-x64.tar.gz" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.52/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.1.51/opencode-windows-x64.zip" +archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.52/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 110525c80f..e029196d4c 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.1.51", + "version": "1.1.52", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 7032245acc..9c6644e3ce 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.1.51", + "version": "1.1.52", "name": "opencode", "type": "module", "license": "MIT", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index d8b8733cb3..86275fc775 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.1.51", + "version": "1.1.52", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 19f4401a64..bda7bbe866 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.1.51", + "version": "1.1.52", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/slack/package.json b/packages/slack/package.json index 0c97a26c55..9522f33a20 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.1.51", + "version": "1.1.52", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/ui/package.json b/packages/ui/package.json index 83902a10f9..c2462c4896 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.1.51", + "version": "1.1.52", "type": "module", "license": "MIT", "exports": { diff --git a/packages/util/package.json b/packages/util/package.json index f048583f75..2be458dfb1 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "1.1.51", + "version": "1.1.52", "private": true, "type": "module", "license": "MIT", diff --git a/packages/web/package.json b/packages/web/package.json index 1b405bc6b0..4e0cafc1bd 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -2,7 +2,7 @@ "name": "@opencode-ai/web", "type": "module", "license": "MIT", - "version": "1.1.51", + "version": "1.1.52", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 013caf7dbc..5b36c06ff9 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.1.51", + "version": "1.1.52", "publisher": "sst-dev", "repository": { "type": "git", From 2f78705f6e91b6a775d544460246cea59b2a4068 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:49:40 -0600 Subject: [PATCH 07/31] tweak: update transforms for gpt-5.3 (#12325) --- packages/opencode/src/provider/transform.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index c1846af700..e564c54a1e 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -375,7 +375,8 @@ export namespace ProviderTransform { } } const copilotEfforts = iife(() => { - if (id.includes("5.1-codex-max") || id.includes("5.2")) return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"] + if (id.includes("5.1-codex-max") || id.includes("5.2") || id.includes("5.3")) + return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"] return WIDELY_SUPPORTED_EFFORTS }) return Object.fromEntries( @@ -422,7 +423,7 @@ export namespace ProviderTransform { if (id === "gpt-5-pro") return {} const openaiEfforts = iife(() => { if (id.includes("codex")) { - if (id.includes("5.2")) return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"] + if (id.includes("5.2") || id.includes("5.3")) return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"] return WIDELY_SUPPORTED_EFFORTS } const arr = [...WIDELY_SUPPORTED_EFFORTS] From 8ddef975b729e4c256c880b7813905240fb0d68e Mon Sep 17 00:00:00 2001 From: Steffen Deusch Date: Thu, 5 Feb 2026 19:58:09 +0100 Subject: [PATCH 08/31] feat(acp): add session usage (#12299) Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> --- bun.lock | 4 +- packages/opencode/package.json | 2 +- packages/opencode/src/acp/agent.ts | 129 ++++++++++++++++++++++++++--- 3 files changed, 121 insertions(+), 14 deletions(-) diff --git a/bun.lock b/bun.lock index 798822af55..5b4616ae7d 100644 --- a/bun.lock +++ b/bun.lock @@ -265,7 +265,7 @@ "dependencies": { "@actions/core": "1.11.1", "@actions/github": "6.0.1", - "@agentclientprotocol/sdk": "0.13.0", + "@agentclientprotocol/sdk": "0.14.1", "@ai-sdk/amazon-bedrock": "3.0.74", "@ai-sdk/anthropic": "2.0.58", "@ai-sdk/azure": "2.0.91", @@ -559,7 +559,7 @@ "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], - "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.13.0", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Z6/Fp4cXLbYdMXr5AK752JM5qG2VKb6ShM0Ql6FimBSckMmLyK54OA20UhPYoH4C37FSFwUTARuwQOwQUToYrw=="], + "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.14.1", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-b6r3PS3Nly+Wyw9U+0nOr47bV8tfS476EgyEMhoKvJCZLbgqoDFN7DJwkxL88RR0aiOqOYV1ZnESHqb+RmdH8w=="], "@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@3.0.74", "", { "dependencies": { "@ai-sdk/anthropic": "2.0.58", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-q83HE3FBb/HPIvjXsehrHOgCuGHPorSMFt6BYnzIYZy8gNnSqV1OWX4oXVsCAuYPPMtYW/KMK35hmoIFV8QKoQ=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 9c6644e3ce..6d52c7609a 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -50,7 +50,7 @@ "dependencies": { "@actions/core": "1.11.1", "@actions/github": "6.0.1", - "@agentclientprotocol/sdk": "0.13.0", + "@agentclientprotocol/sdk": "0.14.1", "@ai-sdk/amazon-bedrock": "3.0.74", "@ai-sdk/anthropic": "2.0.58", "@ai-sdk/azure": "2.0.91", diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index cc9a029a04..775acc52a5 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -25,6 +25,7 @@ import { type SetSessionModeResponse, type ToolCallContent, type ToolKind, + type Usage, } from "@agentclientprotocol/sdk" import { Log } from "../util/log" @@ -38,7 +39,7 @@ import { Config } from "@/config/config" import { Todo } from "@/session/todo" import { z } from "zod" import { LoadAPIKeyError } from "ai" -import type { Event, OpencodeClient, SessionMessageResponse } from "@opencode-ai/sdk/v2" +import type { AssistantMessage, Event, OpencodeClient, SessionMessageResponse } from "@opencode-ai/sdk/v2" import { applyPatch } from "diff" type ModeOption = { id: string; name: string; description?: string } @@ -49,6 +50,74 @@ const DEFAULT_VARIANT_VALUE = "default" export namespace ACP { const log = Log.create({ service: "acp-agent" }) + async function getContextLimit( + sdk: OpencodeClient, + providerID: string, + modelID: string, + directory: string, + ): Promise { + const providers = await sdk.config + .providers({ directory }) + .then((x) => x.data?.providers ?? []) + .catch((error) => { + log.error("failed to get providers for context limit", { error }) + return [] + }) + + const provider = providers.find((p) => p.id === providerID) + const model = provider?.models[modelID] + return model?.limit.context ?? null + } + + async function sendUsageUpdate( + connection: AgentSideConnection, + sdk: OpencodeClient, + sessionID: string, + directory: string, + ): Promise { + const messages = await sdk.session + .messages({ sessionID, directory }, { throwOnError: true }) + .then((x) => x.data) + .catch((error) => { + log.error("failed to fetch messages for usage update", { error }) + return undefined + }) + + if (!messages) return + + const assistantMessages = messages.filter( + (m): m is { info: AssistantMessage; parts: SessionMessageResponse["parts"] } => m.info.role === "assistant", + ) + + const lastAssistant = assistantMessages[assistantMessages.length - 1] + if (!lastAssistant) return + + const msg = lastAssistant.info + const size = await getContextLimit(sdk, msg.providerID, msg.modelID, directory) + + if (!size) { + // Cannot calculate usage without known context size + return + } + + const used = msg.tokens.input + (msg.tokens.cache?.read ?? 0) + const totalCost = assistantMessages.reduce((sum, m) => sum + m.info.cost, 0) + + await connection + .sessionUpdate({ + sessionId: sessionID, + update: { + sessionUpdate: "usage_update", + used, + size, + cost: { amount: totalCost, currency: "USD" }, + }, + }) + .catch((error) => { + log.error("failed to send usage update", { error }) + }) + } + export async function init({ sdk: _sdk }: { sdk: OpencodeClient }) { return { create: (connection: AgentSideConnection, fullConfig: ACPConfig) => { @@ -546,6 +615,8 @@ export namespace ACP { await this.processMessage(msg) } + await sendUsageUpdate(this.connection, this.sdk, sessionId, directory) + return result } catch (e) { const error = MessageV2.fromError(e, { @@ -654,6 +725,8 @@ export namespace ACP { await this.processMessage(msg) } + await sendUsageUpdate(this.connection, this.sdk, sessionId, directory) + return mode } catch (e) { const error = MessageV2.fromError(e, { @@ -677,11 +750,15 @@ export namespace ACP { log.info("resume_session", { sessionId, mcpServers: mcpServers.length }) - return this.loadSessionMode({ + const result = await this.loadSessionMode({ cwd: directory, mcpServers, sessionId, }) + + await sendUsageUpdate(this.connection, this.sdk, sessionId, directory) + + return result } catch (e) { const error = MessageV2.fromError(e, { providerID: this.config.defaultModel?.providerID ?? "unknown", @@ -1239,13 +1316,22 @@ export namespace ACP { return { name, args: rest.join(" ").trim() } })() - const done = { - stopReason: "end_turn" as const, - _meta: {}, - } + const buildUsage = (msg: AssistantMessage): Usage => ({ + totalTokens: + msg.tokens.input + + msg.tokens.output + + msg.tokens.reasoning + + (msg.tokens.cache?.read ?? 0) + + (msg.tokens.cache?.write ?? 0), + inputTokens: msg.tokens.input, + outputTokens: msg.tokens.output, + thoughtTokens: msg.tokens.reasoning || undefined, + cachedReadTokens: msg.tokens.cache?.read || undefined, + cachedWriteTokens: msg.tokens.cache?.write || undefined, + }) if (!cmd) { - await this.sdk.session.prompt({ + const response = await this.sdk.session.prompt({ sessionID, model: { providerID: model.providerID, @@ -1256,14 +1342,22 @@ export namespace ACP { agent, directory, }) - return done + const msg = response.data?.info + + await sendUsageUpdate(this.connection, this.sdk, sessionID, directory) + + return { + stopReason: "end_turn" as const, + usage: msg ? buildUsage(msg) : undefined, + _meta: {}, + } } const command = await this.config.sdk.command .list({ directory }, { throwOnError: true }) .then((x) => x.data!.find((c) => c.name === cmd.name)) if (command) { - await this.sdk.session.command({ + const response = await this.sdk.session.command({ sessionID, command: command.name, arguments: cmd.args, @@ -1271,7 +1365,15 @@ export namespace ACP { agent, directory, }) - return done + const msg = response.data?.info + + await sendUsageUpdate(this.connection, this.sdk, sessionID, directory) + + return { + stopReason: "end_turn" as const, + usage: msg ? buildUsage(msg) : undefined, + _meta: {}, + } } switch (cmd.name) { @@ -1288,7 +1390,12 @@ export namespace ACP { break } - return done + await sendUsageUpdate(this.connection, this.sdk, sessionID, directory) + + return { + stopReason: "end_turn" as const, + _meta: {}, + } } async cancel(params: CancelNotification) { From 081f065942e6dc505443f323e0ce78a15838d997 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Thu, 5 Feb 2026 19:09:43 +0000 Subject: [PATCH 09/31] chore: update nix node_modules hashes --- nix/hashes.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix/hashes.json b/nix/hashes.json index e4ef98a0d4..bc06c23d86 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-/wjmXpex5zfBZBfc2Zszh9UurRuKjm8S+gdAkMrWL98=", - "aarch64-linux": "sha256-c254hgVVyLFucacOQlpnJ+3eCw8xIK9+388EigiuKeM=", - "aarch64-darwin": "sha256-A71PII7Ue0uqsH970GPi0XfRKInpSFFom8jD3Q0wrgQ=", - "x86_64-darwin": "sha256-M9q8O0GkiNoDPMW4C3EVvLo+X9mjQYLJTtNZx5AuQCc=" + "x86_64-linux": "sha256-ZH0Rwfh8Sqqcs0dymB8KYqQp3cwiCOHHKMjChm8lyOI=", + "aarch64-linux": "sha256-P8dIIFovBuGvfTKLOPQQbblF7jLpuZTWYkOMyuO3V00=", + "aarch64-darwin": "sha256-EaiJGw0AtlqlDCXo8ygA37asotkxEYXeiMj+wpJb2aU=", + "x86_64-darwin": "sha256-x0dbpIMN3yaJjCpKoK3SmpO24DkTJqUJ+52hBRDXLW4=" } } From b1c44c7e5c70d567404ee0ee3111cd74871c7f20 Mon Sep 17 00:00:00 2001 From: Daniel Polito Date: Thu, 5 Feb 2026 16:38:31 -0300 Subject: [PATCH 10/31] feat(desktop): Set Workspace Name Earlier to Improve Creation / Deletion (#12213) --- packages/app/src/pages/layout.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index 903b9eaa1f..f7771ba76e 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -2574,6 +2574,8 @@ export default function Layout(props: ParentProps) { if (!created?.directory) return + setWorkspaceName(created.directory, created.branch, project.id, created.branch) + const local = project.worktree const key = workspaceKey(created.directory) const root = workspaceKey(local) From c40ce47e92befbe4cb27735e4d870f540e75b646 Mon Sep 17 00:00:00 2001 From: Daniel Polito Date: Thu, 5 Feb 2026 16:46:44 -0300 Subject: [PATCH 11/31] feat(desktop): Stop Showing SessionSkeleton on New Workspace (#12209) --- packages/app/src/pages/layout.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index f7771ba76e..251984d776 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -2055,9 +2055,10 @@ export default function Layout(props: ParentProps) { const open = createMemo(() => store.workspaceExpanded[props.directory] ?? local()) const boot = createMemo(() => open() || active()) const booted = createMemo((prev) => prev || workspaceStore.status === "complete", false) - const loading = createMemo(() => open() && !booted() && sessions().length === 0) const hasMore = createMemo(() => workspaceStore.sessionTotal > sessions().length) const busy = createMemo(() => isBusy(props.directory)) + const wasBusy = createMemo((prev) => prev || busy(), false) + const loading = createMemo(() => open() && !booted() && sessions().length === 0 && !wasBusy()) const loadMore = async () => { setWorkspaceStore("limit", (limit) => limit + 5) await globalSync.project.loadSessions(props.directory) From 83646e0366c47a3bccb5135d40628176a6776f33 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:51:08 -0600 Subject: [PATCH 12/31] fix(app): allow toggling file tree closed independently (#12293) --- .../app/src/components/dialog-select-file.tsx | 2 + packages/app/src/components/prompt-input.tsx | 3 + .../src/components/session-context-usage.tsx | 2 + .../src/components/session/session-header.tsx | 46 +++++++-- packages/app/src/context/layout.tsx | 62 ++++++++++++- packages/app/src/pages/session.tsx | 93 +++++++++++++++++-- 6 files changed, 185 insertions(+), 23 deletions(-) diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx index 167f211953..36448dd3e6 100644 --- a/packages/app/src/components/dialog-select-file.tsx +++ b/packages/app/src/components/dialog-select-file.tsx @@ -47,6 +47,7 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil const filesOnly = () => props.mode === "files" const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const tabs = createMemo(() => layout.tabs(sessionKey)) + const view = createMemo(() => layout.view(sessionKey)) const state = { cleanup: undefined as (() => void) | void, committed: false } const [grouped, setGrouped] = createSignal(false) const common = [ @@ -282,6 +283,7 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil const value = file.tab(path) tabs().open(value) file.load(path) + if (!view().reviewPanel.opened()) view().reviewPanel.open() layout.fileTree.open() layout.fileTree.setTab("all") props.onOpenFile?.(path) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index b897e394aa..f40b61bca5 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -172,6 +172,7 @@ export const PromptInput: Component = (props) => { const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const tabs = createMemo(() => layout.tabs(sessionKey)) + const view = createMemo(() => layout.view(sessionKey)) const commentInReview = (path: string) => { const sessionID = params.id @@ -190,12 +191,14 @@ export const PromptInput: Component = (props) => { const wantsReview = item.commentOrigin === "review" || (item.commentOrigin !== "file" && commentInReview(item.path)) if (wantsReview) { + if (!view().reviewPanel.opened()) view().reviewPanel.open() layout.fileTree.open() layout.fileTree.setTab("changes") requestAnimationFrame(() => comments.setFocus(focus)) return } + if (!view().reviewPanel.opened()) view().reviewPanel.open() layout.fileTree.open() layout.fileTree.setTab("all") const tab = files.tab(item.path) diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx index c5de54cf0f..c6256395fc 100644 --- a/packages/app/src/components/session-context-usage.tsx +++ b/packages/app/src/components/session-context-usage.tsx @@ -23,6 +23,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) { const variant = createMemo(() => props.variant ?? "button") const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const tabs = createMemo(() => layout.tabs(sessionKey)) + const view = createMemo(() => layout.view(sessionKey)) const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : [])) const usd = createMemo( @@ -57,6 +58,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) { const openContext = () => { if (!params.id) return + if (!view().reviewPanel.opened()) view().reviewPanel.open() layout.fileTree.open() layout.fileTree.setTab("all") tabs().open("context") diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index 5b00f80c05..f2bfc8d251 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -283,27 +283,57 @@ export function SessionHeader() { + + + - + {/* Desktop side panel - hidden on mobile */} - +