Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/core/src/v1/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ export const Info = Schema.Struct({
mcp_timeout: Schema.optional(PositiveInt).annotate({
description: "Timeout in milliseconds for model context protocol (MCP) requests",
}),
sampling_defaults: Schema.optional(Schema.Boolean).annotate({
description:
"Apply built-in sampling defaults (temperature, top_p, top_k) for known models. Enabled by default; set to false to leave sampling to provider defaults. Explicit per-agent values and chat.params plugins always apply.",
}),
policies: Schema.optional(Schema.mutable(Schema.Array(ConfigExperimental.Policy))).annotate({
description: "Policy statements applied to supported resources, such as provider access",
}),
Expand Down
5 changes: 5 additions & 0 deletions packages/opencode/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,9 @@ const GEMINI_MODELS_WITH_SAMPLING_DEFAULTS = [
export function temperature(model: Provider.Model) {
const id = model.api.id.toLowerCase()
if (id.includes("north-mini-code")) return 1.0
if (id.includes("qwen3-coder-next") || id.includes("qwen3.8") || id.includes("qwen-3.8")) return 1.0
if (id.includes("qwen3") || id.includes("qwen-3")) return 0.6
if (id.includes("qwen2.5-coder")) return 0.7
if (id.includes("qwen")) return 0.55
if (id.includes("claude")) return undefined
if (id.includes("gemini"))
Expand All @@ -547,6 +550,8 @@ export function temperature(model: Provider.Model) {

export function topP(model: Provider.Model) {
const id = model.api.id.toLowerCase()
if (id.includes("qwen3") || id.includes("qwen-3")) return 0.95
if (id.includes("qwen2.5-coder")) return 0.8
if (id.includes("qwen")) return 1
if (id.includes("gemini"))
return GEMINI_MODELS_WITH_SAMPLING_DEFAULTS.some((model) => model.test(id)) ? 0.95 : undefined
Expand Down
1 change: 1 addition & 0 deletions packages/opencode/src/session/llm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const live: Layer.Layer<
auth: info,
plugin,
flags,
samplingDefaults: cfg.experimental?.sampling_defaults,
isWorkflow,
})

Expand Down
21 changes: 16 additions & 5 deletions packages/opencode/src/session/llm/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type PrepareInput = {
readonly auth: Auth.Info | undefined
readonly plugin: Plugin.Interface
readonly flags: RuntimeFlags.Info
readonly samplingDefaults?: boolean
readonly isWorkflow: boolean
}

Expand Down Expand Up @@ -111,6 +112,18 @@ export const prepare = Effect.fn("LLMRequestPrep.prepare")(function* (input: Pre
...input.messages,
]

const auto = (input.samplingDefaults ?? true)
? {
temperature: ProviderTransform.temperature(input.model),
topP: ProviderTransform.topP(input.model),
topK: ProviderTransform.topK(input.model),
}
: {
temperature: undefined,
topP: undefined,
topK: undefined,
}

const params = yield* input.plugin.trigger(
"chat.params",
{
Expand All @@ -121,11 +134,9 @@ export const prepare = Effect.fn("LLMRequestPrep.prepare")(function* (input: Pre
message: input.user,
},
{
temperature: input.model.capabilities.temperature
? (input.agent.temperature ?? ProviderTransform.temperature(input.model))
: undefined,
topP: input.agent.topP ?? ProviderTransform.topP(input.model),
topK: ProviderTransform.topK(input.model),
temperature: input.model.capabilities.temperature ? (input.agent.temperature ?? auto.temperature) : undefined,
topP: input.agent.topP ?? auto.topP,
topK: auto.topK,
maxOutputTokens: ProviderTransform.maxOutputTokens(input.model, input.flags.outputTokenMax),
options,
},
Expand Down
45 changes: 45 additions & 0 deletions packages/opencode/test/provider/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3215,6 +3215,51 @@ describe("ProviderTransform.temperature - Cohere North", () => {
})
})

describe("ProviderTransform sampling defaults - Qwen", () => {
const model = (id: string) =>
({
id: `alibaba/${id}`,
api: { id },
}) as any

test.each([
"qwen3-coder-next",
"qwen3.8",
"qwen3.8-max",
])("uses 0.95 top_p and 1.0 temperature for %s", (id) => {
expect(ProviderTransform.topP(model(id))).toBe(0.95)
expect(ProviderTransform.temperature(model(id))).toBe(1.0)
})

test.each([
"qwen3",
"qwen-3",
"qwen3-max",
"qwen3.5-plus",
"qwen3.6-plus",
"qwen3.7-max",
])("uses 0.95 top_p and 0.6 temperature for %s", (id) => {
expect(ProviderTransform.topP(model(id))).toBe(0.95)
expect(ProviderTransform.temperature(model(id))).toBe(0.6)
})

test.each([
"qwen2.5-coder",
"qwen2.5-coder-32b-instruct",
])("uses 0.8 top_p and 0.7 temperature for %s", (id) => {
expect(ProviderTransform.topP(model(id))).toBe(0.8)
expect(ProviderTransform.temperature(model(id))).toBe(0.7)
})

test.each([
"qwen-plus",
"qwen-max",
])("keeps 1 top_p and 0.55 temperature for %s", (id) => {
expect(ProviderTransform.topP(model(id))).toBe(1)
expect(ProviderTransform.temperature(model(id))).toBe(0.55)
})
})

describe("ProviderTransform sampling defaults - Gemini", () => {
const model = (id: string) =>
({
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2025,6 +2025,7 @@ export type Config = {
primary_tools?: Array<string>
continue_loop_on_deny?: boolean
mcp_timeout?: number
sampling_defaults?: boolean
policies?: Array<ConfigV2ExperimentalPolicy>
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/sdk/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -21543,6 +21543,9 @@
"type": "integer",
"exclusiveMinimum": 0
},
"sampling_defaults": {
"type": "boolean"
},
"policies": {
"type": "array",
"items": {
Expand Down
Loading