From a713809d7cebc5fb0f845daa34322ab31dde0254 Mon Sep 17 00:00:00 2001 From: Michiel De Smet Date: Wed, 8 Apr 2026 22:52:20 +0800 Subject: [PATCH 1/3] feat: default to altimate-backend model when configured When no model is explicitly configured and no recently-used model exists, prefer altimate-backend/altimate-default as the default model if altimate credentials are present. This applies to both the main Provider.defaultModel() and the ACP agent defaultModel() fallback chains. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/src/acp/agent.ts | 10 ++ packages/opencode/src/provider/provider.ts | 10 ++ .../opencode/test/provider/provider.test.ts | 153 ++++++++++++++++++ 3 files changed, 173 insertions(+) diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index f935ab4857..eb45850dc7 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -1577,6 +1577,16 @@ export namespace ACP { if (specified && !providers.length) return specified + // altimate_change start — default to altimate-backend when configured and no model chosen yet + const altimateProvider = providers.find((p) => p.id === "altimate-backend") + if (altimateProvider && altimateProvider.models["altimate-default"]) { + return { + providerID: ProviderID.make("altimate-backend"), + modelID: ModelID.make("altimate-default"), + } + } + // altimate_change end + const opencodeProvider = providers.find((p) => p.id === "opencode") if (opencodeProvider) { if (opencodeProvider.models["big-pickle"]) { diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 9e81a4ff38..4e6def6ff7 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1637,6 +1637,16 @@ export namespace Provider { return { providerID: entry.providerID, modelID: entry.modelID } } + // altimate_change start — default to altimate-backend when configured and no model chosen yet + const altimateProvider = providers[ProviderID.make("altimate-backend")] + if (altimateProvider && altimateProvider.models[ModelID.make("altimate-default")]) { + return { + providerID: ProviderID.make("altimate-backend"), + modelID: ModelID.make("altimate-default"), + } + } + // altimate_change end + const provider = Object.values(providers).find((p) => !cfg.provider || Object.keys(cfg.provider).includes(p.id)) if (!provider) throw new Error("no providers found") const [model] = sort(Object.values(provider.models)) diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts index 05a6064051..d509cddccb 100644 --- a/packages/opencode/test/provider/provider.test.ts +++ b/packages/opencode/test/provider/provider.test.ts @@ -1,11 +1,13 @@ import { test, expect } from "bun:test" import path from "path" +import fs from "fs/promises" import { tmpdir } from "../fixture/fixture" import { Instance } from "../../src/project/instance" import { Provider } from "../../src/provider/provider" import { ProviderID, ModelID } from "../../src/provider/schema" import { Env } from "../../src/env" +import { Global } from "../../src/global" test("provider loaded from env variable", async () => { await using tmp = await tmpdir({ @@ -2330,4 +2332,155 @@ test("github-copilot is excluded when CODESPACES=true and only GITHUB_TOKEN is s }, }) }) + +// altimate_change start — tests for altimate-backend default model preference +test("defaultModel returns altimate-backend when altimate credentials exist and no model configured", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://altimate.ai/config.json", + }), + ) + }, + }) + const originalHome = process.env.OPENCODE_TEST_HOME + process.env.OPENCODE_TEST_HOME = tmp.path + const altimateDir = path.join(tmp.path, ".altimate") + await fs.mkdir(altimateDir, { recursive: true }) + await Bun.write( + path.join(altimateDir, "altimate.json"), + JSON.stringify({ + altimateUrl: "https://test.altimate.ai", + altimateInstanceName: "test-instance", + altimateApiKey: "test-api-key", + }), + ) + try { + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const model = await Provider.defaultModel() + expect(String(model.providerID)).toBe("altimate-backend") + expect(String(model.modelID)).toBe("altimate-default") + }, + }) + } finally { + process.env.OPENCODE_TEST_HOME = originalHome + } +}) + +test("defaultModel prefers altimate-backend over other providers when altimate is configured", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://altimate.ai/config.json", + }), + ) + }, + }) + const originalHome = process.env.OPENCODE_TEST_HOME + process.env.OPENCODE_TEST_HOME = tmp.path + const altimateDir = path.join(tmp.path, ".altimate") + await fs.mkdir(altimateDir, { recursive: true }) + await Bun.write( + path.join(altimateDir, "altimate.json"), + JSON.stringify({ + altimateUrl: "https://test.altimate.ai", + altimateInstanceName: "test-instance", + altimateApiKey: "test-api-key", + }), + ) + try { + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("ANTHROPIC_API_KEY", "test-api-key") + }, + fn: async () => { + const providers = await Provider.list() + // Both providers should be available + expect(providers["anthropic"]).toBeDefined() + expect(providers["altimate-backend"]).toBeDefined() + // But defaultModel should prefer altimate-backend + const model = await Provider.defaultModel() + expect(String(model.providerID)).toBe("altimate-backend") + expect(String(model.modelID)).toBe("altimate-default") + }, + }) + } finally { + process.env.OPENCODE_TEST_HOME = originalHome + } +}) + +test("defaultModel respects explicit config model over altimate-backend", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://altimate.ai/config.json", + model: "anthropic/claude-sonnet-4-20250514", + }), + ) + }, + }) + const originalHome = process.env.OPENCODE_TEST_HOME + process.env.OPENCODE_TEST_HOME = tmp.path + const altimateDir = path.join(tmp.path, ".altimate") + await fs.mkdir(altimateDir, { recursive: true }) + await Bun.write( + path.join(altimateDir, "altimate.json"), + JSON.stringify({ + altimateUrl: "https://test.altimate.ai", + altimateInstanceName: "test-instance", + altimateApiKey: "test-api-key", + }), + ) + try { + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("ANTHROPIC_API_KEY", "test-api-key") + }, + fn: async () => { + const model = await Provider.defaultModel() + expect(String(model.providerID)).toBe("anthropic") + expect(String(model.modelID)).toBe("claude-sonnet-4-20250514") + }, + }) + } finally { + process.env.OPENCODE_TEST_HOME = originalHome + } +}) + +test("defaultModel falls through to other providers when altimate is not configured", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://altimate.ai/config.json", + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("ANTHROPIC_API_KEY", "test-api-key") + }, + fn: async () => { + const providers = await Provider.list() + // altimate-backend should NOT be available (no credentials file) + expect(providers["altimate-backend"]).toBeUndefined() + const model = await Provider.defaultModel() + // Should fall through to anthropic + expect(String(model.providerID)).toBe("anthropic") + }, + }) +}) // altimate_change end From 7d2340196a1a8eefb6a07a00c88f7c8c8e7d3f46 Mon Sep 17 00:00:00 2001 From: Michiel De Smet Date: Wed, 8 Apr 2026 23:18:49 +0800 Subject: [PATCH 2/3] fix: respect cfg.provider filter in altimate-backend default model check The altimate-backend early return was bypassing the cfg.provider constraint that the generic fallback respects. Now the altimate check only triggers if altimate-backend is in the user's configured provider set (or if no provider filter is configured). Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/src/provider/provider.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 4e6def6ff7..6221bec5ff 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1638,10 +1638,15 @@ export namespace Provider { } // altimate_change start — default to altimate-backend when configured and no model chosen yet - const altimateProvider = providers[ProviderID.make("altimate-backend")] - if (altimateProvider && altimateProvider.models[ModelID.make("altimate-default")]) { + const altimateProviderID = ProviderID.make("altimate-backend") + const altimateProvider = providers[altimateProviderID] + if ( + altimateProvider && + altimateProvider.models[ModelID.make("altimate-default")] && + (!cfg.provider || Object.keys(cfg.provider).includes(String(altimateProviderID))) + ) { return { - providerID: ProviderID.make("altimate-backend"), + providerID: altimateProviderID, modelID: ModelID.make("altimate-default"), } } From 5fe8ba5bdf6bf131b332cf31639a4606d7470974 Mon Sep 17 00:00:00 2001 From: Michiel De Smet Date: Wed, 8 Apr 2026 23:19:55 +0800 Subject: [PATCH 3/3] fix: properly restore OPENCODE_TEST_HOME env var in test cleanup Use delete when originalHome is undefined instead of assigning the string "undefined" back to the env var. Also remove unused Global import. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/test/provider/provider.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts index d509cddccb..42dd6c437e 100644 --- a/packages/opencode/test/provider/provider.test.ts +++ b/packages/opencode/test/provider/provider.test.ts @@ -7,7 +7,6 @@ import { Instance } from "../../src/project/instance" import { Provider } from "../../src/provider/provider" import { ProviderID, ModelID } from "../../src/provider/schema" import { Env } from "../../src/env" -import { Global } from "../../src/global" test("provider loaded from env variable", async () => { await using tmp = await tmpdir({ @@ -2367,7 +2366,8 @@ test("defaultModel returns altimate-backend when altimate credentials exist and }, }) } finally { - process.env.OPENCODE_TEST_HOME = originalHome + if (originalHome === undefined) delete process.env.OPENCODE_TEST_HOME + else process.env.OPENCODE_TEST_HOME = originalHome } }) @@ -2412,7 +2412,8 @@ test("defaultModel prefers altimate-backend over other providers when altimate i }, }) } finally { - process.env.OPENCODE_TEST_HOME = originalHome + if (originalHome === undefined) delete process.env.OPENCODE_TEST_HOME + else process.env.OPENCODE_TEST_HOME = originalHome } }) @@ -2453,7 +2454,8 @@ test("defaultModel respects explicit config model over altimate-backend", async }, }) } finally { - process.env.OPENCODE_TEST_HOME = originalHome + if (originalHome === undefined) delete process.env.OPENCODE_TEST_HOME + else process.env.OPENCODE_TEST_HOME = originalHome } })