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) { if (planState?.pending !== undefined) {
const active = planState.pending const active = planState.pending
planStates.set(id, { active }) 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' } } }) append(id, { type: 'user/message', surfaceOp: 'append', data: { content, source: { kind: 'user' } } })
startReply( startReply(
@@ -551,10 +551,11 @@ export function createFixtureApi(): ApiProxy {
details: { sessionId: request.payload.sessionId }, details: { sessionId: request.payload.sessionId },
}) })
} }
const target = state.pending ?? state.active const next = request.payload.active === state.active
const next = request.payload.active === target ? { active: state.active }
? state : request.payload.active === state.pending
: { active: state.active, pending: request.payload.active } ? state
: { active: state.active, pending: request.payload.active }
planStates.set(request.payload.sessionId, next) planStates.set(request.payload.sessionId, next)
return ok(request, { ...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({ expect((await client.sessions.setPlanMode({ sessionId: sid('fx-alpha'), active: true })).result).toEqual({
ok: true, value: { active: false, pending: true }, 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({ expect((await client.sessions.cancel({ sessionId: sid('fx-alpha') })).result).toEqual({
ok: true, value: { accepted: true }, ok: true, value: { accepted: true },
}) })
@@ -83,12 +86,12 @@ describe('createFixtureApi', () => {
const createdId = created.result.value.sessionId const createdId = created.result.value.sessionId
await client.sessions.setPlanMode({ sessionId: createdId, active: true }) await client.sessions.setPlanMode({ sessionId: createdId, active: true })
expect((await client.sessions.setPlanMode({ sessionId: createdId, active: false })).result).toEqual({ 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 // Selecting the committed target clears pending immediately, and repeating
// target clears at the boundary without a redundant plan/mode event. // that selection remains a no-op without a redundant plan/mode event.
expect((await client.sessions.setPlanMode({ sessionId: createdId, active: false })).result).toEqual({ 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({ await client.sessions.prompt({
sessionId: createdId, mode: 'queue', content: [{ type: 'text', text: 'remain default' }], sessionId: createdId, mode: 'queue', content: [{ type: 'text', text: 'remain default' }],