diff --git a/.opencode/agent/test-max-thinking.md b/.opencode/agent/test-max-thinking.md new file mode 100644 index 00000000000..0dc5e9ab6b2 --- /dev/null +++ b/.opencode/agent/test-max-thinking.md @@ -0,0 +1,9 @@ +--- +description: Test agent with max thinking. +model: zai-coding-plan/glm-4.7 +variant: max +--- + +You are a test agent for GLM-4.7 with max thinking enabled. + +Your purpose is to test model variants in this codebase. Keep responses brief and direct. diff --git a/.opencode/agent/test-no-thinking.md b/.opencode/agent/test-no-thinking.md new file mode 100644 index 00000000000..7e7166cc9bc --- /dev/null +++ b/.opencode/agent/test-no-thinking.md @@ -0,0 +1,9 @@ +--- +description: Test agent with no thinking. +model: zai-coding-plan/glm-4.7 +variant: none +--- + +You are a test agent for GLM-4.7 with thinking disabled. + +Your purpose is to test model variants in this codebase. Keep responses brief and direct. diff --git a/.opencode/remember.jsonc b/.opencode/remember.jsonc new file mode 100644 index 00000000000..42d86610f85 --- /dev/null +++ b/.opencode/remember.jsonc @@ -0,0 +1,16 @@ +{ + // Enable or disable the plugin + "enabled": true, + // Where to store memories: "global", "project", or "both" + // - "global": ~/.config/opencode/memory/memories.sqlite (shared across projects) + // - "project": .opencode/memory/memories.sqlite (project-specific) + // - "both": search both, save to project + "scope": "project", + // Memory injection settings + "inject": { + // Number of memories to inject after user messages (default: 5) + "count": 5, + // Score threshold for [important] vs [related] tag (default: 0.6) + "highThreshold": 0.6 + } +} diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx index 43d47e1b1bc..0423186becb 100644 --- a/packages/app/src/context/local.tsx +++ b/packages/app/src/context/local.tsx @@ -300,7 +300,11 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const m = current() if (!m) return undefined const key = `${m.provider.id}/${m.id}` - return store.variant?.[key] + const a = agent.current() + return ( + store.variant?.[key] ?? + (a?.model && `${a.model.providerID}/${a.model.modelID}` === key ? a.variant : undefined) + ) }, list() { const m = current() diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index 2b44308f130..16d119f2f0e 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -29,6 +29,7 @@ export namespace Agent { topP: z.number().optional(), temperature: z.number().optional(), color: z.string().optional(), + variant: z.string().optional(), permission: PermissionNext.Ruleset, model: z .object({ @@ -217,6 +218,7 @@ export namespace Agent { item.topP = value.top_p ?? item.topP item.mode = value.mode ?? item.mode item.color = value.color ?? item.color + item.variant = value.variant ?? item.variant item.hidden = value.hidden ?? item.hidden item.name = value.name ?? item.name item.steps = value.steps ?? item.steps diff --git a/packages/opencode/src/cli/cmd/debug/agent.ts b/packages/opencode/src/cli/cmd/debug/agent.ts index d1236ff40bc..4877d948a62 100644 --- a/packages/opencode/src/cli/cmd/debug/agent.ts +++ b/packages/opencode/src/cli/cmd/debug/agent.ts @@ -126,6 +126,7 @@ async function createToolContext(agent: Agent.Info) { parentID: messageID, modelID: model.modelID, providerID: model.providerID, + variant: agent.variant, mode: "debug", agent: agent.name, path: { diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 020e626cba8..8f51f362430 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -579,6 +579,7 @@ export namespace Config { .regex(/^#[0-9a-fA-F]{6}$/, "Invalid hex color format") .optional() .describe("Hex color code for the agent (e.g., #FF5733)"), + variant: z.string().optional().describe("Default model variant to use for this agent (e.g., 'high')"), steps: z .number() .int() @@ -600,6 +601,7 @@ export namespace Config { "mode", "hidden", "color", + "variant", "steps", "maxSteps", "options", @@ -630,10 +632,11 @@ export namespace Config { // Convert legacy maxSteps to steps const steps = agent.steps ?? agent.maxSteps - return { ...agent, options, permission, steps } as typeof agent & { + return { ...agent, options, permission, steps, variant: agent.variant } as typeof agent & { options?: Record permission?: Permission steps?: number + variant?: string } }) .meta({ diff --git a/packages/opencode/src/session/llm.ts b/packages/opencode/src/session/llm.ts index 55c9c452473..f03ae005e7a 100644 --- a/packages/opencode/src/session/llm.ts +++ b/packages/opencode/src/session/llm.ts @@ -94,8 +94,14 @@ export namespace LLM { system.push(header, rest.join("\n")) } - const variant = - !input.small && input.model.variants && input.user.variant ? input.model.variants[input.user.variant] : {} + const selectedVariant = input.user.variant || input.agent.variant + const variant = !input.small && input.model.variants && selectedVariant ? input.model.variants[selectedVariant] : {} + l.info("variant selection", { + selectedVariant, + hasModelVariants: !!input.model.variants, + availableVariants: input.model.variants ? Object.keys(input.model.variants) : [], + variantOptions: variant, + }) const base = input.small ? ProviderTransform.smallOptions(input.model) : ProviderTransform.options({ @@ -109,6 +115,7 @@ export namespace LLM { mergeDeep(input.agent.options), mergeDeep(variant), ) + l.info("merged options", { options }) if (isCodex) { options.instructions = SystemPrompt.instructions() } @@ -121,6 +128,7 @@ export namespace LLM { model: input.model, provider, message: input.user, + variant: selectedVariant, }, { temperature: input.model.capabilities.temperature @@ -140,6 +148,7 @@ export namespace LLM { model: input.model, provider, message: input.user, + variant: selectedVariant, }, { headers: {}, diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 83ca72addb1..162c94a3410 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -365,6 +365,7 @@ export namespace MessageV2 { parentID: z.string(), modelID: z.string(), providerID: z.string(), + variant: z.string().optional(), /** * @deprecated */ diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 8554b44a727..c935dd9981d 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -832,7 +832,7 @@ export namespace SessionPrompt { agent: agent.name, model: input.model ?? agent.model ?? (await lastModel(input.sessionID)), system: input.system, - variant: input.variant, + variant: input.variant ?? agent.variant, } const parts = await Promise.all( diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index c87add638aa..b98e14f4850 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -103,12 +103,14 @@ export const TaskTool = Tool.define("task", async (ctx) => { modelID: msg.info.modelID, providerID: msg.info.providerID, } + const variant = agent.variant ?? msg.info.variant ctx.metadata({ title: params.description, metadata: { sessionId: session.id, model, + variant, }, }) @@ -133,6 +135,7 @@ export const TaskTool = Tool.define("task", async (ctx) => { summary: Object.values(parts).sort((a, b) => a.id.localeCompare(b.id)), sessionId: session.id, model, + variant, }, }) }) @@ -151,6 +154,7 @@ export const TaskTool = Tool.define("task", async (ctx) => { modelID: model.modelID, providerID: model.providerID, }, + variant, agent: agent.name, tools: { todowrite: false, @@ -183,6 +187,7 @@ export const TaskTool = Tool.define("task", async (ctx) => { summary, sessionId: session.id, model, + variant, }, output, } diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index ca13e5e93cf..85bd272e1bb 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -121,6 +121,7 @@ export type AssistantMessage = { parentID: string modelID: string providerID: string + variant?: string mode: string path: { cwd: string @@ -990,6 +991,10 @@ export type AgentConfig = { * Hex color code for the agent (e.g., #FF5733) */ color?: string + /** + * Default model variant to use for this agent (e.g., 'high') + */ + variant?: string /** * Maximum number of agentic iterations before forcing text-only response */ @@ -1590,6 +1595,7 @@ export type Agent = { topP?: number temperature?: number color?: string + variant?: string permission: { edit: "ask" | "allow" | "deny" bash: { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 38a52b325ad..aecb606ec0d 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -179,6 +179,7 @@ export type AssistantMessage = { parentID: string modelID: string providerID: string + variant?: string mode: string agent: string path: { @@ -1409,6 +1410,10 @@ export type AgentConfig = { * Hex color code for the agent (e.g., #FF5733) */ color?: string + /** + * Default model variant to use for this agent (e.g., 'high') + */ + variant?: string /** * Maximum number of agentic iterations before forcing text-only response */ @@ -2117,6 +2122,7 @@ export type Agent = { topP?: number temperature?: number color?: string + variant?: string permission: PermissionRuleset model?: { modelID: string