From 7bb7e5241dee61cac40d945a518ea61a0485341b Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 17 Apr 2026 11:35:09 -0700 Subject: [PATCH] chore(deps): pin opencode CLI + SDK to v1.4.9 (#1471) * chore(deps): pin opencode CLI and SDK to v1.4.9 - Bump constants.json opencodeVersion v1.2.27 -> v1.4.9 (CI source of truth consumed by ci-tests, build-desktop, alpha/prerelease/release workflows, and opencode-agents). - Bump @opencode-ai/sdk across app, story-book, orchestrator, opencode-router, server-v2, and refresh the lockfile so all workspaces resolve to 1.4.9. * refactor(app): adapt to @opencode-ai/sdk 1.4.9 type changes - Move Model.reasoning reads to Model.capabilities.reasoning in model-config.ts and model-behavior.ts (SDK flattened capabilities). - Simplify utils/providers.ts to a pass-through; Provider now carries source/options and Model.cost reshapes to {input, output, cache, experimentalOver200K}, which the mapper no longer needs to translate. - Cast session.todo() result to TodoItem[] (SDK Todo has no id). - Update server-v2 test fixtures from 1.2.27 to 1.4.9. --- apps/app/package.json | 2 +- apps/app/src/app/context/model-config.ts | 2 +- apps/app/src/app/context/session.ts | 2 +- apps/app/src/app/lib/model-behavior.ts | 4 +- apps/app/src/app/utils/providers.ts | 86 +++---------------- apps/opencode-router/package.json | 2 +- apps/orchestrator/package.json | 2 +- apps/server-v2/package.json | 2 +- apps/server-v2/src/runtime/assets.test.ts | 14 +-- .../src/services/runtime-service.test.ts | 6 +- apps/story-book/package.json | 2 +- constants.json | 2 +- pnpm-lock.yaml | 33 ++++--- 13 files changed, 47 insertions(+), 112 deletions(-) diff --git a/apps/app/package.json b/apps/app/package.json index ccea32dc..dda5a51f 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -42,7 +42,7 @@ "@codemirror/state": "^6.5.2", "@codemirror/view": "^6.38.0", "@lexical/react": "^0.35.0", - "@opencode-ai/sdk": "^1.1.31", + "@opencode-ai/sdk": "^1.4.9", "@openwork/ui": "workspace:*", "@radix-ui/colors": "^3.0.0", "@solid-primitives/event-bus": "^1.1.2", diff --git a/apps/app/src/app/context/model-config.ts b/apps/app/src/app/context/model-config.ts index 4e1d73ed..9134a61c 100644 --- a/apps/app/src/app/context/model-config.ts +++ b/apps/app/src/app/context/model-config.ts @@ -639,7 +639,7 @@ export function createModelConfigStore(options: { if (defaultModelID === model.id || isDefault) { footerBits.push(t("settings.model_default", currentLocale())); } - if (model.reasoning) footerBits.push(t("settings.model_reasoning", currentLocale())); + if (model.capabilities?.reasoning) footerBits.push(t("settings.model_reasoning", currentLocale())); next.push({ providerID: provider.id, diff --git a/apps/app/src/app/context/session.ts b/apps/app/src/app/context/session.ts index 120ab6f9..7e7ad83c 100644 --- a/apps/app/src/app/context/session.ts +++ b/apps/app/src/app/context/session.ts @@ -1264,7 +1264,7 @@ export function createSessionStore(options: { const list = unwrap(await withTimeout(c.session.todo({ sessionID }), 8000, "session.todo")); mark("session.todo done"); if (abortIfStale("selection changed before todos applied")) return; - setStore("todos", sessionID, list); + setStore("todos", sessionID, list as TodoItem[]); } catch (error) { mark("session.todo failed/timeout", { error: error instanceof Error ? error.message : safeStringify(error), diff --git a/apps/app/src/app/lib/model-behavior.ts b/apps/app/src/app/lib/model-behavior.ts index 287deb3c..41553d2c 100644 --- a/apps/app/src/app/lib/model-behavior.ts +++ b/apps/app/src/app/lib/model-behavior.ts @@ -83,7 +83,7 @@ const getBehaviorTitle = (providerID: string, model: ProviderModel, variantKeys: } return t("app.model_behavior_title"); } - if (model.reasoning) return t("model_behavior.title_builtin_reasoning"); + if (model.capabilities?.reasoning) return t("model_behavior.title_builtin_reasoning"); return t("model_behavior.title_standard_generation"); }; @@ -169,7 +169,7 @@ export const getModelBehaviorSummary = ( }; } - if (model.reasoning) { + if (model.capabilities?.reasoning) { return { title, label: t("model_behavior.label_builtin"), diff --git a/apps/app/src/app/utils/providers.ts b/apps/app/src/app/utils/providers.ts index 4ed3b312..966c0822 100644 --- a/apps/app/src/app/utils/providers.ts +++ b/apps/app/src/app/utils/providers.ts @@ -1,8 +1,5 @@ import type { Provider as ConfigProvider, ProviderListResponse } from "@opencode-ai/sdk/v2/client"; -type ProviderListItem = ProviderListResponse["all"][number]; -type ProviderListModel = ProviderListItem["models"][string]; - const PINNED_PROVIDER_ORDER = ["opencode", "openai", "anthropic"] as const; export const providerPriorityRank = (id: string) => { @@ -25,77 +22,18 @@ export const compareProviders = ( return aName.localeCompare(bName); }; -const buildModalities = (caps?: ConfigProvider["models"][string]["capabilities"]) => { - if (!caps) return undefined; - - const input = Object.entries(caps.input) - .filter(([, enabled]) => enabled) - .map(([key]) => key as "text" | "audio" | "image" | "video" | "pdf"); - const output = Object.entries(caps.output) - .filter(([, enabled]) => enabled) - .map(([key]) => key as "text" | "audio" | "image" | "video" | "pdf"); - - if (!input.length && !output.length) return undefined; - return { input, output }; -}; - -const mapModel = (model: ConfigProvider["models"][string]): ProviderListModel => { - const interleaved = model.capabilities?.interleaved; - const modalities = buildModalities(model.capabilities); - const status = model.status === "alpha" || model.status === "beta" || model.status === "deprecated" - ? model.status - : undefined; - - return { - id: model.id, - name: model.name ?? model.id, - family: model.family, - release_date: model.release_date ?? "", - attachment: model.capabilities?.attachment ?? false, - reasoning: model.capabilities?.reasoning ?? false, - temperature: model.capabilities?.temperature ?? false, - tool_call: model.capabilities?.toolcall ?? false, - interleaved: interleaved === false ? undefined : interleaved, - cost: model.cost - ? { - input: model.cost.input, - output: model.cost.output, - cache_read: model.cost.cache.read, - cache_write: model.cost.cache.write, - context_over_200k: model.cost.experimentalOver200K - ? { - input: model.cost.experimentalOver200K.input, - output: model.cost.experimentalOver200K.output, - cache_read: model.cost.experimentalOver200K.cache.read, - cache_write: model.cost.experimentalOver200K.cache.write, - } - : undefined, - } - : undefined, - limit: model.limit, - modalities, - experimental: status === "alpha" ? true : undefined, - status, - options: model.options ?? {}, - headers: model.headers ?? undefined, - provider: model.api?.npm ? { npm: model.api.npm } : undefined, - variants: model.variants, - }; -}; - -export const mapConfigProvidersToList = (providers: ConfigProvider[]): ProviderListResponse["all"] => - providers.map((provider) => { - const models = Object.fromEntries( - Object.entries(provider.models ?? {}).map(([key, model]) => [key, mapModel(model)]), - ); - - return { - id: provider.id, - name: provider.name ?? provider.id, - env: provider.env ?? [], - models, - }; - }); +// Starting with @opencode-ai/sdk@1.4.x, `ConfigProvider` (from `config.providers()`) +// and the provider items in `ProviderListResponse.all` share the same shape, so +// this mapper is effectively an identity function. It is kept for call-site +// stability and to normalize optional fields (`name`, `env`). +export const mapConfigProvidersToList = ( + providers: ConfigProvider[], +): ProviderListResponse["all"] => + providers.map((provider) => ({ + ...provider, + name: provider.name ?? provider.id, + env: provider.env ?? [], + })); export const filterProviderList = ( value: ProviderListResponse, diff --git a/apps/opencode-router/package.json b/apps/opencode-router/package.json index 28fee4ab..29506753 100644 --- a/apps/opencode-router/package.json +++ b/apps/opencode-router/package.json @@ -44,7 +44,7 @@ "test:npx": "bun scripts/test-npx.mjs" }, "dependencies": { - "@opencode-ai/sdk": "^1.1.31", + "@opencode-ai/sdk": "^1.4.9", "@slack/socket-mode": "^2.0.5", "@slack/web-api": "^7.13.0", "commander": "^12.1.0", diff --git a/apps/orchestrator/package.json b/apps/orchestrator/package.json index f34a3289..89949eb2 100644 --- a/apps/orchestrator/package.json +++ b/apps/orchestrator/package.json @@ -44,7 +44,7 @@ "access": "public" }, "dependencies": { - "@opencode-ai/sdk": "^1.1.31", + "@opencode-ai/sdk": "^1.4.9", "@opentui/core": "0.1.77", "@opentui/solid": "0.1.77", "opencode-router": "0.11.207", diff --git a/apps/server-v2/package.json b/apps/server-v2/package.json index b178f19d..fc59bbd2 100644 --- a/apps/server-v2/package.json +++ b/apps/server-v2/package.json @@ -27,7 +27,7 @@ "src" ], "dependencies": { - "@opencode-ai/sdk": "1.2.27", + "@opencode-ai/sdk": "1.4.9", "hono": "4.12.12", "hono-openapi": "1.3.0", "jsonc-parser": "^3.3.1", diff --git a/apps/server-v2/src/runtime/assets.test.ts b/apps/server-v2/src/runtime/assets.test.ts index c1045c0e..c374fcff 100644 --- a/apps/server-v2/src/runtime/assets.test.ts +++ b/apps/server-v2/src/runtime/assets.test.ts @@ -67,7 +67,7 @@ test("release runtime assets use manifest versions without reading repo metadata const releaseRoot = makeTempDir("openwork-server-v2-release-assets"); const opencodePath = path.join(releaseRoot, process.platform === "win32" ? "opencode.exe" : "opencode"); const routerPath = path.join(releaseRoot, process.platform === "win32" ? "opencode-router.exe" : "opencode-router"); - writeVersionedBinary(opencodePath, "1.2.27"); + writeVersionedBinary(opencodePath, "1.4.9"); writeVersionedBinary(routerPath, "0.11.206"); const manifest: RuntimeManifest = { @@ -85,7 +85,7 @@ test("release runtime assets use manifest versions without reading repo metadata }, generatedAt: new Date().toISOString(), manifestVersion: 1, - opencodeVersion: "1.2.27", + opencodeVersion: "1.4.9", rootDir: releaseRoot, routerVersion: "0.11.206", serverVersion: "0.0.0-test", @@ -118,7 +118,7 @@ test("release runtime assets use manifest versions without reading repo metadata }); const bundle = await service.resolveRuntimeBundle(); - expect(bundle.opencode.version).toBe("1.2.27"); + expect(bundle.opencode.version).toBe("1.4.9"); expect(bundle.router.version).toBe("0.11.206"); expect(bundle.manifest.source).toBe("release"); }); @@ -136,7 +136,7 @@ test("release runtime assets extract into the managed runtime directory and surv const opencodePath = path.join(bundleRoot, process.platform === "win32" ? "opencode.exe" : "opencode"); const routerPath = path.join(bundleRoot, process.platform === "win32" ? "opencode-router.exe" : "opencode-router"); - writeVersionedBinary(opencodePath, "1.2.27"); + writeVersionedBinary(opencodePath, "1.4.9"); writeVersionedBinary(routerPath, "0.11.206"); const manifest: RuntimeManifest = { @@ -154,7 +154,7 @@ test("release runtime assets extract into the managed runtime directory and surv }, generatedAt: new Date().toISOString(), manifestVersion: 1, - opencodeVersion: "1.2.27", + opencodeVersion: "1.4.9", rootDir: bundleRoot, routerVersion: "0.11.206", serverVersion: "0.0.0-test", @@ -213,7 +213,7 @@ test("release runtime assets can extract from an embedded runtime bundle", async const opencodePath = path.join(bundleRoot, process.platform === "win32" ? "opencode.exe" : "opencode"); const routerPath = path.join(bundleRoot, process.platform === "win32" ? "opencode-router.exe" : "opencode-router"); const manifestPath = path.join(bundleRoot, "manifest.json"); - writeVersionedBinary(opencodePath, "1.2.27"); + writeVersionedBinary(opencodePath, "1.4.9"); writeVersionedBinary(routerPath, "0.11.206"); const manifest: RuntimeManifest = { @@ -231,7 +231,7 @@ test("release runtime assets can extract from an embedded runtime bundle", async }, generatedAt: new Date().toISOString(), manifestVersion: 1, - opencodeVersion: "1.2.27", + opencodeVersion: "1.4.9", rootDir: bundleRoot, routerVersion: "0.11.206", serverVersion: "0.0.0-test", diff --git a/apps/server-v2/src/services/runtime-service.test.ts b/apps/server-v2/src/services/runtime-service.test.ts index a56f2d2d..129ba84b 100644 --- a/apps/server-v2/src/services/runtime-service.test.ts +++ b/apps/server-v2/src/services/runtime-service.test.ts @@ -71,7 +71,7 @@ async function createFakeAssetService(opencodePath: string, routerPath: string) }, generatedAt: new Date().toISOString(), manifestVersion: 1, - opencodeVersion: "1.2.27", + opencodeVersion: "1.4.9", rootDir: path.dirname(opencodePath), routerVersion: "0.11.206", serverVersion: "0.0.0-test", @@ -87,7 +87,7 @@ async function createFakeAssetService(opencodePath: string, routerPath: string) source: "development" as const, stagedRoot: path.dirname(opencodePath), target, - version: "1.2.27", + version: "1.4.9", }; const routerBinary = { absolutePath: routerPath, @@ -104,7 +104,7 @@ async function createFakeAssetService(opencodePath: string, routerPath: string) ensureOpencodeBinary: async () => opencodeBinary, ensureRouterBinary: async () => routerBinary, getDevelopmentRoot: () => path.dirname(opencodePath), - getPinnedOpencodeVersion: async () => "1.2.27", + getPinnedOpencodeVersion: async () => "1.4.9", getReleaseRoot: () => path.dirname(opencodePath), getRouterVersion: async () => "0.11.206", getSource: () => "development" as const, diff --git a/apps/story-book/package.json b/apps/story-book/package.json index 67db0e04..fa2c0de8 100644 --- a/apps/story-book/package.json +++ b/apps/story-book/package.json @@ -23,7 +23,7 @@ "@codemirror/language": "^6.11.0", "@codemirror/state": "^6.5.2", "@codemirror/view": "^6.38.0", - "@opencode-ai/sdk": "^1.1.31", + "@opencode-ai/sdk": "^1.4.9", "@radix-ui/colors": "^3.0.0", "@solid-primitives/event-bus": "^1.1.2", "@solid-primitives/storage": "^4.3.3", diff --git a/constants.json b/constants.json index 37b2d934..aca25f3a 100644 --- a/constants.json +++ b/constants.json @@ -1,3 +1,3 @@ { - "opencodeVersion": "v1.2.27" + "opencodeVersion": "v1.4.9" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9672c0c0..f36c373e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,8 +41,8 @@ importers: specifier: ^0.35.0 version: 0.35.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yjs@13.6.30) '@opencode-ai/sdk': - specifier: ^1.1.31 - version: 1.1.39 + specifier: ^1.4.9 + version: 1.4.9 '@openwork/ui': specifier: workspace:* version: link:../../packages/ui @@ -162,8 +162,8 @@ importers: apps/opencode-router: dependencies: '@opencode-ai/sdk': - specifier: ^1.1.31 - version: 1.1.39 + specifier: ^1.4.9 + version: 1.4.9 '@slack/socket-mode': specifier: ^2.0.5 version: 2.0.5 @@ -196,8 +196,8 @@ importers: apps/orchestrator: dependencies: '@opencode-ai/sdk': - specifier: ^1.1.31 - version: 1.1.39 + specifier: ^1.4.9 + version: 1.4.9 '@opentui/core': specifier: 0.1.77 version: 0.1.77(stage-js@1.0.0-alpha.17)(typescript@5.9.3)(web-tree-sitter@0.25.10) @@ -270,8 +270,8 @@ importers: apps/server-v2: dependencies: '@opencode-ai/sdk': - specifier: 1.2.27 - version: 1.2.27 + specifier: 1.4.9 + version: 1.4.9 hono: specifier: 4.12.12 version: 4.12.12 @@ -362,8 +362,8 @@ importers: specifier: ^6.38.0 version: 6.39.14 '@opencode-ai/sdk': - specifier: ^1.1.31 - version: 1.1.39 + specifier: ^1.4.9 + version: 1.4.9 '@radix-ui/colors': specifier: ^3.0.0 version: 3.0.0 @@ -2385,11 +2385,8 @@ packages: '@nothing-but/utils@0.17.0': resolution: {integrity: sha512-TuCHcHLOqDL0SnaAxACfuRHBNRgNJcNn9X0GiH5H3YSDBVquCr3qEIG3FOQAuMyZCbu9w8nk2CHhOsn7IvhIwQ==} - '@opencode-ai/sdk@1.1.39': - resolution: {integrity: sha512-EUYBZAci0bzG9+a7JVINmqAqis71ipG2/D3juvmvvKFyu0YBIT/6b+g3+p82Eb5CU2dujxpPdJJCaexZ1389eQ==} - - '@opencode-ai/sdk@1.2.27': - resolution: {integrity: sha512-Wk0o/I+Fo+wE3zgvlJDs8Fb67KlKqX0PrV8dK5adSDkANq6r4Z25zXJg2iOir+a8ntg3rAcpel1OY4FV/TwRUA==} + '@opencode-ai/sdk@1.4.9': + resolution: {integrity: sha512-S8WQLuBFu2WwvSc1wupsV4qskniBA+JN1VaZZs52BPWwiN2zQFTD5/6dMh6oiYOMDtPjKsTFZ6qLFxDvVPNggQ==} '@opentelemetry/api-logs@0.207.0': resolution: {integrity: sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==} @@ -8429,9 +8426,9 @@ snapshots: '@nothing-but/utils@0.17.0': {} - '@opencode-ai/sdk@1.1.39': {} - - '@opencode-ai/sdk@1.2.27': {} + '@opencode-ai/sdk@1.4.9': + dependencies: + cross-spawn: 7.0.6 '@opentelemetry/api-logs@0.207.0': dependencies: