fix(web): canonicalize fixture plan state

This commit is contained in:
fz
2026-07-24 13:22:33 +08:00
parent 6135393a6b
commit a0748ce560
2 changed files with 13 additions and 9 deletions

View File

@@ -510,7 +510,7 @@ export function createFixtureApi(): ApiProxy {
if (planState?.pending !== undefined) {
const active = planState.pending
planStates.set(id, { active })
if (active !== planState.active) append(id, { type: 'plan/mode', data: { active } })
append(id, { type: 'plan/mode', data: { active } })
}
append(id, { type: 'user/message', surfaceOp: 'append', data: { content, source: { kind: 'user' } } })
startReply(
@@ -551,10 +551,11 @@ export function createFixtureApi(): ApiProxy {
details: { sessionId: request.payload.sessionId },
})
}
const target = state.pending ?? state.active
const next = request.payload.active === target
? state
: { active: state.active, pending: request.payload.active }
const next = request.payload.active === state.active
? { active: state.active }
: request.payload.active === state.pending
? state
: { active: state.active, pending: request.payload.active }
planStates.set(request.payload.sessionId, next)
return ok(request, { ...next })
},

View File

@@ -56,6 +56,9 @@ describe('createFixtureApi', () => {
expect((await client.sessions.setPlanMode({ sessionId: sid('fx-alpha'), active: true })).result).toEqual({
ok: true, value: { active: false, pending: true },
})
expect((await client.sessions.setPlanMode({ sessionId: sid('fx-alpha'), active: true })).result).toEqual({
ok: true, value: { active: false, pending: true },
})
expect((await client.sessions.cancel({ sessionId: sid('fx-alpha') })).result).toEqual({
ok: true, value: { accepted: true },
})
@@ -83,12 +86,12 @@ describe('createFixtureApi', () => {
const createdId = created.result.value.sessionId
await client.sessions.setPlanMode({ sessionId: createdId, active: true })
expect((await client.sessions.setPlanMode({ sessionId: createdId, active: false })).result).toEqual({
ok: true, value: { active: false, pending: false },
ok: true, value: { active: false },
})
// Selecting the effective target again is a no-op, and a net-zero pending
// target clears at the boundary without a redundant plan/mode event.
// Selecting the committed target clears pending immediately, and repeating
// that selection remains a no-op without a redundant plan/mode event.
expect((await client.sessions.setPlanMode({ sessionId: createdId, active: false })).result).toEqual({
ok: true, value: { active: false, pending: false },
ok: true, value: { active: false },
})
await client.sessions.prompt({
sessionId: createdId, mode: 'queue', content: [{ type: 'text', text: 'remain default' }],