Compare commits

..

1 Commits

Author SHA1 Message Date
opencode a3647eb025 release: v1.18.16 2026-08-10 06:06:53 +00:00
13 changed files with 23 additions and 75 deletions
@@ -103,7 +103,6 @@ describe("normalizeProviderList", () => {
) )
expect(result.connected).toEqual(["openai"]) expect(result.connected).toEqual(["openai"])
expect(result.defaultModel).toEqual({ providerID: "openai", modelID: "gpt-5" })
expect(result.default).toEqual({ openai: "gpt-5" }) expect(result.default).toEqual({ openai: "gpt-5" })
expect(result.all.get("openai")?.models["gpt-old"]).toBeUndefined() expect(result.all.get("openai")?.models["gpt-old"]).toBeUndefined()
expect(result.all.get("openai")?.models["gpt-5"]).toMatchObject({ expect(result.all.get("openai")?.models["gpt-5"]).toMatchObject({
@@ -114,10 +113,6 @@ describe("normalizeProviderList", () => {
variants: { high: {} }, variants: { high: {} },
}) })
}) })
test("preserves an empty current default", () => {
expect(normalizeProviderList([] as ProviderListOutput["data"], [], null).defaultModel).toBeNull()
})
}) })
describe("directoryKey", () => { describe("directoryKey", () => {
@@ -139,7 +139,6 @@ export function normalizeProviderList(
return { return {
all, all,
connected: providers.map((provider) => provider.id), connected: providers.map((provider) => provider.id),
defaultModel: defaultModel ? { providerID: defaultModel.providerID, modelID: defaultModel.id } : null,
default: Object.fromEntries( default: Object.fromEntries(
providers.flatMap((provider) => { providers.flatMap((provider) => {
const model = const model =
+4 -3
View File
@@ -6,7 +6,6 @@ import { createStore } from "solid-js/store"
import { useModels } from "@/context/models" import { useModels } from "@/context/models"
import { useSettings } from "@/context/settings" import { useSettings } from "@/context/settings"
import { useProviders } from "@/hooks/use-providers" import { useProviders } from "@/hooks/use-providers"
import { resolveDefaultModel } from "@/hooks/provider-catalog"
import { Persist, persisted } from "@/utils/persist" import { Persist, persisted } from "@/utils/persist"
import { hasCustomAgent, resolveAgent } from "./local-agent" import { hasCustomAgent, resolveAgent } from "./local-agent"
import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant" import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant"
@@ -150,8 +149,10 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
}) })
const configuredModel = () => { const configuredModel = () => {
const model = resolveDefaultModel(providers.defaultModel(), sync().data.config.model) const configured = sync().data.config.model
if (!model) return if (!configured) return
const [providerID, modelID] = configured.split("/")
const model = { providerID, modelID }
if (validModel(model)) return model if (validModel(model)) return model
} }
@@ -1,6 +1,6 @@
import { expect, test } from "bun:test" import { expect, test } from "bun:test"
import type { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context" import type { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context"
import { resolveDefaultModel, selectProviderCatalog } from "./provider-catalog" import { selectProviderCatalog } from "./provider-catalog"
const catalog = (id: string): NormalizedProviderListResponse => ({ const catalog = (id: string): NormalizedProviderListResponse => ({
all: new Map([[id, { id, name: id, source: "api", env: [], options: {}, models: {} }]]), all: new Map([[id, { id, name: id, source: "api", env: [], options: {}, models: {} }]]),
@@ -57,21 +57,3 @@ test("falls back to the global catalog for route consumers", () => {
}), }),
).toBe(global) ).toBe(global)
}) })
test("uses the current server default model", () => {
expect(resolveDefaultModel({ providerID: "openai", modelID: "gpt-5" }, "anthropic/claude")).toEqual({
providerID: "openai",
modelID: "gpt-5",
})
})
test("does not use legacy config when the current server has no default", () => {
expect(resolveDefaultModel(null, "anthropic/claude")).toBeUndefined()
})
test("uses config for legacy servers", () => {
expect(resolveDefaultModel(undefined, "anthropic/claude")).toEqual({
providerID: "anthropic",
modelID: "claude",
})
})
@@ -25,13 +25,3 @@ export function selectProviderCatalog(input: ProviderCatalogInput) {
if (input.explicit) return emptyProviderCatalog if (input.explicit) return emptyProviderCatalog
return input.global return input.global
} }
export function resolveDefaultModel(
current: NormalizedProviderListResponse["defaultModel"],
legacy: string | undefined,
) {
if (current !== undefined) return current ?? undefined
if (!legacy) return undefined
const [providerID, modelID] = legacy.split("/")
return { providerID, modelID }
}
-1
View File
@@ -41,7 +41,6 @@ export function useProviders(directory: Accessor<string | undefined>) {
return { return {
all: () => providers().all, all: () => providers().all,
default: () => providers().default, default: () => providers().default,
defaultModel: () => providers().defaultModel,
popular: () => popular: () =>
pipe( pipe(
providers().all, providers().all,
+7 -7
View File
@@ -583,7 +583,7 @@ export const dict = {
"dialog.usageExceeded.dontShowAgain": "不再显示", "dialog.usageExceeded.dontShowAgain": "不再显示",
"context.breakdown.title": "上下文细分", "context.breakdown.title": "上下文细分",
"context.breakdown.note": "输入 token 的大致细分。“其他”包含工具定义和开销。", "context.breakdown.note": "输入词元的大致细分。“其他”包含工具定义和开销。",
"context.breakdown.system": "系统", "context.breakdown.system": "系统",
"context.breakdown.user": "用户", "context.breakdown.user": "用户",
"context.breakdown.assistant": "助手", "context.breakdown.assistant": "助手",
@@ -598,18 +598,18 @@ export const dict = {
"context.stats.provider": "提供商", "context.stats.provider": "提供商",
"context.stats.model": "模型", "context.stats.model": "模型",
"context.stats.limit": "上下文限制", "context.stats.limit": "上下文限制",
"context.stats.totalTokens": "总 token", "context.stats.totalTokens": "词元总数",
"context.stats.usage": "使用率", "context.stats.usage": "使用率",
"context.stats.inputTokens": "输入 token", "context.stats.inputTokens": "输入词元",
"context.stats.outputTokens": "输出 token", "context.stats.outputTokens": "输出词元",
"context.stats.reasoningTokens": "推理 token", "context.stats.reasoningTokens": "推理词元",
"context.stats.cacheTokens": "缓存 token(读/写)", "context.stats.cacheTokens": "缓存词元(读/写)",
"context.stats.userMessages": "用户消息", "context.stats.userMessages": "用户消息",
"context.stats.assistantMessages": "助手消息", "context.stats.assistantMessages": "助手消息",
"context.stats.totalCost": "总成本", "context.stats.totalCost": "总成本",
"context.stats.sessionCreated": "创建时间", "context.stats.sessionCreated": "创建时间",
"context.stats.lastActivity": "最后活动", "context.stats.lastActivity": "最后活动",
"context.usage.tokens": "Token", "context.usage.tokens": "词元数",
"context.usage.usage": "使用率", "context.usage.usage": "使用率",
"context.usage.cost": "成本", "context.usage.cost": "成本",
"context.usage.clickToView": "点击查看上下文", "context.usage.clickToView": "点击查看上下文",
@@ -6,7 +6,6 @@ import { usePrompt } from "@/context/prompt"
import { useSDK } from "@/context/sdk" import { useSDK } from "@/context/sdk"
import { useSync } from "@/context/sync" import { useSync } from "@/context/sync"
import { useProviders } from "@/hooks/use-providers" import { useProviders } from "@/hooks/use-providers"
import { resolveDefaultModel } from "@/hooks/provider-catalog"
export function createPromptModelSelection(input: { agent: () => { model?: ModelKey; variant?: string } | undefined }) { export function createPromptModelSelection(input: { agent: () => { model?: ModelKey; variant?: string } | undefined }) {
const sdk = useSDK() const sdk = useSDK()
@@ -22,8 +21,10 @@ export function createPromptModelSelection(input: { agent: () => { model?: Model
} }
const configured = () => { const configured = () => {
const model = resolveDefaultModel(providers.defaultModel(), sync().data.config.model) const value = sync().data.config.model
if (!model) return if (!value) return
const [providerID, modelID] = value.split("/")
const model = { providerID, modelID }
if (valid(model)) return model if (valid(model)) return model
} }
@@ -1,4 +1,4 @@
You are OpenCode, a coding agent that helps users with software engineering tasks. You are powered by {{MODEL_NAME}}, a large language model trained by Meta MSL. You are OpenCode, a coding agent that helps users with software engineering tasks. You are powered by Muse Spark, a large language model trained by Meta MSL.
Use the instructions below and the tools available to assist the user. Use the instructions below and the tools available to assist the user.
@@ -61,5 +61,5 @@ Use the instructions below and the tools available to assist the user.
- NEVER use comments as a place for long-winded chain-of-thought. Long thinking texts must be generated as private reasoning. Comments in code must be appropriately concise. - NEVER use comments as a place for long-winded chain-of-thought. Long thinking texts must be generated as private reasoning. Comments in code must be appropriately concise.
# User Help & Feedback # User Help & Feedback
- Users can give feedback or report issues at https://github.com/anomalyco/opencode and mention that they are using Meta {{MODEL_NAME}}. - Users can give feedback or report issues at https://github.com/anomalyco/opencode and mention that they are using Meta Muse Spark.
- When users ask directly about OpenCode (eg. "can OpenCode do...", "are you able to do...") or its features (eg. implement a hook, write a slash command, or install an MCP server), use the WebFetch tool to gather information to answer the question from the OpenCode docs at https://opencode.ai/docs. - When users ask directly about OpenCode (eg. "can OpenCode do...", "are you able to do...") or its features (eg. implement a hook, write a slash command, or install an MCP server), use the WebFetch tool to gather information to answer the question from the OpenCode docs at https://opencode.ai/docs.
+1 -4
View File
@@ -25,10 +25,7 @@ import { MCP } from "@/mcp"
import { PermissionV1 } from "@opencode-ai/core/v1/permission" import { PermissionV1 } from "@opencode-ai/core/v1/permission"
export function provider(model: Provider.Model) { export function provider(model: Provider.Model) {
if (model.api.id.includes("muse")) { if (model.api.id.includes("muse-spark")) return [PROMPT_META]
const name = model.api.id.includes("muse-glimmer") ? "Muse Glimmer" : "Muse Spark"
return [PROMPT_META.replaceAll("{{MODEL_NAME}}", name)]
}
if (model.api.id.includes("gpt-4") || model.api.id.includes("o1") || model.api.id.includes("o3")) if (model.api.id.includes("gpt-4") || model.api.id.includes("o1") || model.api.id.includes("o3"))
return [PROMPT_BEAST] return [PROMPT_BEAST]
if (model.api.id.includes("gpt")) { if (model.api.id.includes("gpt")) {
+3 -15
View File
@@ -85,21 +85,9 @@ const it = testEffect(
describe("session.system", () => { describe("session.system", () => {
test("selects the Meta prompt for Muse Spark model IDs", () => { test("selects the Meta prompt for Muse Spark model IDs", () => {
for (const id of ["meta/muse-spark-preview", "muse-spark-1.1", "muse-spark-1.2"]) { expect(SystemPrompt.provider({ api: { id: "meta/muse-spark-preview" } } as Provider.Model)[0]).toContain(
const prompt = SystemPrompt.provider({ api: { id } } as Provider.Model)[0] "Meta Muse Spark",
expect(prompt).toContain("powered by Muse Spark,") )
expect(prompt).toContain("using Meta Muse Spark.")
expect(prompt).not.toContain("{{MODEL_NAME}}")
}
})
test("selects the Meta prompt for Muse Glimmer model IDs", () => {
for (const id of ["meta/muse-glimmer", "meta/muse-glimmer-30b", "muse-glimmer-30b"]) {
const prompt = SystemPrompt.provider({ api: { id } } as Provider.Model)[0]
expect(prompt).toContain("powered by Muse Glimmer,")
expect(prompt).toContain("using Meta Muse Glimmer.")
expect(prompt).not.toContain("{{MODEL_NAME}}")
}
}) })
it.effect("skills output is sorted by name and stable across calls", () => it.effect("skills output is sorted by name and stable across calls", () =>
-4
View File
@@ -5,10 +5,6 @@ import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
export type NormalizedProviderListResponse = { export type NormalizedProviderListResponse = {
all: Map<string, Provider> all: Map<string, Provider>
defaultModel?: {
providerID: string
modelID: string
} | null
default: { default: {
[key: string]: string [key: string]: string
} }
+1 -1
View File
@@ -25,7 +25,7 @@
"border-weak-base": "#DBDBDB", "border-weak-base": "#DBDBDB",
"border-weaker-base": "#E8E8E8", "border-weaker-base": "#E8E8E8",
"icon-base": "#8F8F8F", "icon-base": "#8F8F8F",
"icon-weak-base": "#C7C7C7", "icon-weak-base": "C7C7C7",
"surface-raised-base": "#F3F3F3", "surface-raised-base": "#F3F3F3",
"surface-raised-base-hover": "#EDEDED", "surface-raised-base-hover": "#EDEDED",
"surface-base": "#F8F8F8", "surface-base": "#F8F8F8",