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.
This commit is contained in:
ben
2026-04-17 11:35:09 -07:00
committed by GitHub
parent 12900a0b9e
commit 7bb7e5241d
13 changed files with 47 additions and 112 deletions

View File

@@ -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",

View File

@@ -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,

View File

@@ -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),

View File

@@ -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"),

View File

@@ -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,

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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,

View File

@@ -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",

View File

@@ -1,3 +1,3 @@
{
"opencodeVersion": "v1.2.27"
"opencodeVersion": "v1.4.9"
}

33
pnpm-lock.yaml generated
View File

@@ -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: