feat(core): honor default session models (#30982)

This commit is contained in:
Kit Langton 2026-06-05 12:10:48 -04:00 committed by GitHub
commit d2204e0ff5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 93 additions and 15 deletions

View file

@ -52,6 +52,20 @@ const provider = {
}
describe("Config", () => {
it.effect("returns the latest defined scalar from priority-ordered documents", () =>
Effect.sync(() => {
const entries = [
new Config.Document({ type: "document", info: new Config.Info({ model: "openrouter/openai/gpt-5" }) }),
new Config.Directory({ type: "directory", path: AbsolutePath.make("/skills") }),
new Config.Document({ type: "document", info: new Config.Info({}) }),
new Config.Document({ type: "document", info: new Config.Info({ model: "openrouter/openai/gpt-5.5" }) }),
]
expect(Config.latest(entries, "model")).toBe("openrouter/openai/gpt-5.5")
expect(Config.latest(entries, "default_agent")).toBeUndefined()
}),
)
it.effect("detects v1 configuration from any v1-only top-level key", () =>
Effect.sync(() => {
expect(ConfigMigrateV1.isV1({ snapshot: false })).toBe(true)

View file

@ -1,5 +1,5 @@
import { describe, expect } from "bun:test"
import { Effect, Schema } from "effect"
import { Effect, Option, Schema } from "effect"
import { Catalog } from "@opencode-ai/core/catalog"
import { Config } from "@opencode-ai/core/config"
import { ConfigProviderPlugin } from "@opencode-ai/core/config/plugin/provider"
@ -30,6 +30,7 @@ describe("ConfigProviderPlugin.Plugin", () => {
new Config.Document({
type: "document",
info: decode({
model: "custom/first",
providers: {
custom: {
name: "Configured",
@ -59,11 +60,15 @@ describe("ConfigProviderPlugin.Plugin", () => {
new Config.Document({
type: "document",
info: decode({
model: "custom/default",
providers: {
custom: {
api: { type: "aisdk", package: "custom-sdk", url: "https://example.test" },
request: request({ last: "last", shared: "last" }),
models: {
default: {
name: "Default",
},
chat: {
api: { id: "api-chat" },
name: "Last",
@ -106,6 +111,7 @@ describe("ConfigProviderPlugin.Plugin", () => {
const provider = yield* catalog.provider.get(providerID)
const model = yield* catalog.model.get(providerID, modelID)
expect(Option.getOrUndefined(yield* catalog.model.default())?.id).toBe(ModelV2.ID.make("default"))
expect(provider.name).toBe("Renamed")
expect(provider.env).toEqual(["CUSTOM_API_KEY"])
expect(provider.enabled).toEqual({ via: "custom", data: {} })

View file

@ -337,14 +337,50 @@ describe("SessionV2.create", () => {
expect(yield* unavailable(session.shell({ sessionID: created.id, command: "pwd" }))).toBe("shell")
expect(yield* unavailable(session.skill({ sessionID: created.id, skill: "review" }))).toBe("skill")
expect(yield* unavailable(session.switchAgent({ sessionID: created.id, agent: "build" }))).toBe("switchAgent")
}),
)
it.effect("switches the selected model through the durable Session event", () =>
Effect.gen(function* () {
const session = yield* SessionV2.Service
const created = yield* session.create({ location })
const model = ModelV2.Ref.make({
id: ModelV2.ID.make("sonnet"),
providerID: ProviderV2.ID.anthropic,
variant: ModelV2.VariantID.make("high"),
})
yield* session.switchModel({ sessionID: created.id, model })
expect(yield* session.get(created.id)).toMatchObject({ model })
expect(
yield* unavailable(
session.switchModel({
sessionID: created.id,
Array.from(yield* session.events({ sessionID: created.id }).pipe(Stream.take(1), Stream.runCollect)),
).toMatchObject([{ event: { type: "session.next.model.switched", data: { model } } }])
yield* session.switchModel({ sessionID: created.id, model })
const { db } = yield* Database.Service
expect(
yield* db.select().from(EventTable).where(eq(EventTable.aggregate_id, created.id)).all().pipe(Effect.orDie),
).toHaveLength(2)
}),
)
it.effect("rejects a model switch for a missing Session", () =>
Effect.gen(function* () {
const session = yield* SessionV2.Service
const missing = SessionV2.ID.make("ses_missing_model_switch")
expect(
yield* session
.switchModel({
sessionID: missing,
model: ModelV2.Ref.make({ id: ModelV2.ID.make("sonnet"), providerID: ProviderV2.ID.anthropic }),
}),
),
).toBe("switchModel")
})
.pipe(
Effect.flip,
Effect.map((error) => error._tag),
),
).toBe("Session.NotFoundError")
}),
)
})