Roles: refresh the live selection when re-pointing a reused Session
Deploying dee76b1 proved a raw durable append insufficient: the 07:54 dispatch recorded the wandering selection, yet the request assembled half a second later still carried the deepseek header, because prompt assembly reads the Session Controller's in-memory selection and the internal Agent controller caches one per Agent. Call its own selectForNextRequest primitive — append plus cache refresh, still without saving the deployment default — and fall back to the public selectModel if the surface moves. Fixture gains the Controller; two cases pin fast-path and fallback.
This commit is contained in:
@@ -14,12 +14,17 @@ async function fixture() {
|
||||
ctx.reflect.provide('llm', { resolveCallConfig: resolve })
|
||||
ctx.reflect.provide('sessionPersistence', { flush })
|
||||
const session = Session.create(SessionId('role-model'))
|
||||
const agent = { ctx, session } as Agent
|
||||
const selectModel = vi.fn(async (request: { provider: string; model: string; reasoningEffort?: unknown }) => ({
|
||||
selected: { provider: request.provider, model: request.model, ...(request.reasoningEffort === void 0 ? {} : { reasoningEffort: request.reasoningEffort }) } }))
|
||||
const sessionController: { agents?: { selectForNextRequest(agent: Agent, selection: ModelSelection): void }; selectModel: typeof selectModel } = {
|
||||
agents: { selectForNextRequest: (target, selection) => { target.session.append('model/selection', selection) } }, selectModel }
|
||||
ctx.reflect.provide('sessionController', sessionController)
|
||||
const agent = { ctx, session, id: 'role-model' } as unknown as Agent
|
||||
const host: ModelSelectionRef = { get current() { return session.requestHeader()?.config ?? { provider: 'host', model: 'default', reasoningEffort: ReasoningEffortId('high') } }, assembled: undefined }
|
||||
installModelSelection(ctx, host)
|
||||
const request = () => agentEvents(ctx, agent).waterfall('agent/request', { turn: 1, step: 1, signal: new AbortController().signal }, async () => ({ provider: 'seed', model: 'seed' }))
|
||||
const record = (selection: ModelSelection) => { const event = session.append('request/header', { header: { config: selection }, reason: 'initial' }); ctx.emit('session/event', session, event) }
|
||||
return { ctx, agent, host, resolve, flush, request, record }
|
||||
return { ctx, agent, host, resolve, flush, request, record, sessionController }
|
||||
}
|
||||
it('keeps prompt variables and initial routing on the role model without saving the host default', async () => {
|
||||
const { ctx, agent, request, record, flush } = await fixture()
|
||||
@@ -123,4 +128,18 @@ describe('alignRoleModel', () => {
|
||||
expect(events[0]?.data).toEqual({ provider: 'wp', model: 'wm' })
|
||||
expect(flush).toHaveBeenCalledOnce()
|
||||
})
|
||||
it('prefers the internal Controller primitive over the default-saving selectModel', async () => {
|
||||
const { ctx, agent, sessionController } = await fixture()
|
||||
const primitive = vi.fn()
|
||||
sessionController.agents = { selectForNextRequest: primitive }
|
||||
await alignRoleModel(ctx, agent, { provider: 'wp', model: 'wm' })
|
||||
expect(primitive).toHaveBeenCalledWith(agent, { provider: 'wp', model: 'wm' })
|
||||
expect(sessionController.selectModel).not.toHaveBeenCalled()
|
||||
})
|
||||
it('falls back to selectModel when the internal Controller surface is absent', async () => {
|
||||
const { ctx, agent, sessionController } = await fixture()
|
||||
delete sessionController.agents
|
||||
await alignRoleModel(ctx, agent, { provider: 'wp', model: 'wm' })
|
||||
expect(sessionController.selectModel).toHaveBeenCalledWith(expect.objectContaining({ sessionId: 'role-model', provider: 'wp', model: 'wm' }))
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user