fix(core): record selected catalog model identity on assistant steps (#34911)

This commit is contained in:
Kit Langton 2026-07-02 16:09:33 -04:00 committed by GitHub
commit cff2345c12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 106 additions and 21 deletions

View file

@ -174,6 +174,58 @@ describe("LocationServiceMap", () => {
),
)
it.live("preserves the selected catalog identity when the api model id differs", () =>
Effect.acquireRelease(
Effect.promise(() => tmpdir()),
(dir) => Effect.promise(() => dir[Symbol.asyncDispose]()),
).pipe(
Effect.flatMap((dir) =>
Effect.gen(function* () {
const location = Location.Ref.make({ directory: AbsolutePath.make(dir.path) })
const resolved = yield* Effect.gen(function* () {
const catalog = yield* Catalog.Service
yield* catalog.transform((editor) => {
editor.provider.update(ProviderV2.ID.make("aliased"), (provider) => {
provider.api = { type: "aisdk", package: "@ai-sdk/openai", settings: {} }
})
editor.model.update(ProviderV2.ID.make("aliased"), ModelV2.ID.make("fast"), (model) => {
// Catalog id and provider API id intentionally differ, like gpt-5.5-fast -> gpt-5.5.
model.api = { ...model.api, id: ModelV2.ID.make("base") }
model.variants.push({ id: ModelV2.VariantID.make("high"), settings: {}, headers: {}, body: {} })
})
})
const models = yield* SessionRunnerModel.Service
return yield* models.resolve(
SessionV2.Info.make({
id: SessionV2.ID.make("ses_aliased_model"),
projectID: ProjectV2.ID.global,
title: "test",
model: {
id: ModelV2.ID.make("fast"),
providerID: ProviderV2.ID.make("aliased"),
variant: ModelV2.VariantID.make("high"),
},
cost: 0,
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
time: { created: DateTime.makeUnsafe(0), updated: DateTime.makeUnsafe(0) },
location,
}),
)
}).pipe(Effect.provide(LocationServiceMap.Service.get(location)))
expect(resolved.ref).toEqual(
ModelV2.Ref.make({
id: ModelV2.ID.make("fast"),
providerID: ProviderV2.ID.make("aliased"),
variant: ModelV2.VariantID.make("high"),
}),
)
expect(String(resolved.model.id)).toBe("base")
}),
),
),
)
it.live("installs public plugins into a location", () =>
Effect.acquireRelease(
Effect.promise(() => tmpdir()),

View file

@ -48,7 +48,7 @@ const client = Layer.mock(LLMClient.Service)({
generate: () => Effect.die("unused"),
})
const config = Layer.mock(Config.Service)({ entries: () => Effect.succeed([]) })
const models = SessionRunnerModel.layerWith(() => Effect.succeed(model))
const models = SessionRunnerModel.layerWith(() => Effect.succeed(SessionRunnerModel.resolved(model)))
const locations = Layer.effect(
LocationServiceMap.Service,
LayerMap.make(

View file

@ -38,7 +38,9 @@ const client = Layer.mock(LLMClient.Service)({
generate: () => Effect.die("unused"),
})
const config = Layer.mock(Config.Service)({ entries: () => Effect.succeed([]) })
const models = Layer.mock(SessionRunnerModel.Service)({ resolve: () => Effect.succeed(model) })
const models = Layer.mock(SessionRunnerModel.Service)({
resolve: () => Effect.succeed(SessionRunnerModel.resolved(model)),
})
const it = testEffect(
AppNodeBuilder.build(
LayerNode.group([Database.node, EventV2.node, SessionProjector.node, SessionStore.node, SessionCompaction.node]),

View file

@ -72,7 +72,7 @@ const model = OpenAIChat.route
generation: { maxTokens: 20, temperature: 0 },
})
.model({ id: "gpt-4o-mini" })
const models = SessionRunnerModel.layerWith(() => Effect.succeed(model))
const models = SessionRunnerModel.layerWith(() => Effect.succeed(SessionRunnerModel.resolved(model)))
const systemContext = Layer.mock(SystemContextBuiltIns.Service, { load: () => Effect.succeed(SystemContext.empty) })
const instructionContext = Layer.mock(InstructionContext.Service, { load: () => Effect.succeed(SystemContext.empty) })
const skillGuidance = Layer.mock(SkillGuidance.Service, { load: () => Effect.succeed(SystemContext.empty) })

View file

@ -162,7 +162,14 @@ const echoNode = makeLocationNode({ name: "test/session-runner-tools", layer: ec
let modelResolveHook = Effect.void
let currentModel = model
const models = SessionRunnerModel.layerWith((session) =>
modelResolveHook.pipe(Effect.as(session.model?.id === "replacement" ? replacementModel : currentModel)),
modelResolveHook.pipe(
Effect.as(
SessionRunnerModel.resolved(
session.model?.id === "replacement" ? replacementModel : currentModel,
session.model?.variant,
),
),
),
)
const systemContextKey = SystemContext.Key.make("test/context")
let systemBaseline = "Initial context"

View file

@ -36,7 +36,9 @@ const client = Layer.mock(LLMClient.Service)({
},
generate: () => Effect.die("unused"),
})
const models = Layer.mock(SessionRunnerModel.Service)({ resolve: () => Effect.succeed(model) })
const models = Layer.mock(SessionRunnerModel.Service)({
resolve: () => Effect.succeed(SessionRunnerModel.resolved(model)),
})
const it = testEffect(
AppNodeBuilder.build(
LayerNode.group([Database.node, EventV2.node, SessionProjector.node, SessionStore.node, AgentV2.node, SessionTitle.node]),