fix(plan): commit an idle selection immediately
set() on an idle agent appends plan/mode at once — no request boundary would arrive until the next prompt, so a queued intent used to hang as pending forever (the composer showed a dead pending target). A running agent keeps the boundary-flush path unchanged. set() now reports which branch ran (committed/queued/cancelled/noop); the /plan handler's copy follows the branch (idle: "Plan mode on/off", mid-turn: the next-step wording), and both commit paths share the header-delta narration. The invariant drops turn enclosure: plan/mode is a standalone whole-value event (the synthetic log-only turns removal already established the between-turns append shape). The fixture mirrors the idle commit.
This commit is contained in:
@@ -998,19 +998,30 @@ export function createFixtureApi(options: FixtureOptions = {}): ApiProxy {
|
||||
const match = /^\/(\S+)((?:\s.*)?)$/.exec(request.payload.line.trim())
|
||||
const name = match?.[1]
|
||||
const args = match?.[2] ?? ''
|
||||
// Host parallel: /plan on an idle fixture session commits plan/mode
|
||||
// immediately (the boundary flush covers only a running turn), so the
|
||||
// outcome copy matches the immediate branch of the host handler.
|
||||
const running = summaryOf(id)?.running === true
|
||||
const outcomes: Record<string, string> = {
|
||||
compact: 'fixture:已压缩(假动作)',
|
||||
echo: args.trim(),
|
||||
'goal-fixture': `fixture:goal 已设置(${id})`,
|
||||
// Mirrors the host handler's wording; the projection frame carries the state.
|
||||
plan: args.trim() === 'off'
|
||||
? 'Leaving plan mode (applies from the next step).'
|
||||
: 'Entering plan mode (applies from the next step). Use /plan off to leave.',
|
||||
? (running ? 'Leaving plan mode (applies from the next step).' : 'Plan mode off.')
|
||||
: (running
|
||||
? 'Entering plan mode (applies from the next step). Use /plan off to leave.'
|
||||
: 'Plan mode on. Use /plan off to leave.'),
|
||||
}
|
||||
const text = name === undefined ? undefined : outcomes[name]
|
||||
if (name === undefined || text === undefined) return ok(request, { matched: false as const })
|
||||
const commandId = `fx-cmd-${logOf(id).length}` as CommandId
|
||||
append(id, { type: 'command/run', data: { commandId, name, args, source: { kind: 'user' } } })
|
||||
if (name === 'plan' && !running) {
|
||||
const plan = foldPlan(logOf(id))
|
||||
if (plan.wanted !== null && plan.wanted !== plan.active) {
|
||||
append(id, { type: 'plan/mode', data: { active: plan.wanted } })
|
||||
}
|
||||
}
|
||||
append(id, { type: 'command/done', data: { commandId, kind: 'success', ...text === '' ? {} : { text } } })
|
||||
return ok(request, { matched: true as const, commandId })
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user