feat(mode): exit_plan_mode + the ACP session-mode picker + scriptable review answers
Plan mode's stage 2 (RFC 2026-07-07-plan-mode). The exit tool: one required plan argument (the durable log artifact), execute re-checks the folded mode, then conducts the review over the user-interaction seam — one single-select question (Approve / Keep planning) with free text open — so an approval appends mode/set back to default in-turn and every other outcome (keep-planning feedback verbatim, aborted, no provider) returns the corrective isError with the mode unchanged. presentCall is a generic card titled by the plan's first heading carrying the plan markdown; over ACP the review rides the ask_user elicitation flow, in the terminal the stdio prompt queue — no approval-seam dependency. The ACP bridge maps the picker 1:1 onto ctx.modes (opportunistic, a type-only peer edge): session/new + session/load advertise availableModes/currentModeId, session/set_mode validates through set() and echoes an optimistic current_mode_update (the pending mode IS the selection; the logged mode/set lands at the boundary and, matching, is not re-sent), and a session/event listener re-notifies on each logged flip that differs from the last sent — the tool-driven exit updates the picker. The feature matrix rows move from 'not modeled' to the picker-to-modes / knobs-to-config-options division, with the ACP v2 removal direction recorded as a mechanical-migration risk. The snapshot harness gains the setMode/setModeExpectError ops and a scripted elicitationAnswers FIFO (cancel on exhaustion; a stray choice string reaches the agent verbatim as a non-consenting custom answer, so a scenario bug fails safe). The suite factory's header-pin requirement now applies only to model-turn scenarios — a protocol-only suite has no header content to anchor. examples/plan-acp-agent is the live composition; its keyless modes-advertise scenario pins the wire surface (advertisement, both set_mode round-trips, unknown-id rejection). The recorded plan-mode approve/reject arc awaits a with-key recording session; its texts are pinned at the unit tier meanwhile. examples/AGENTS.md ceiling 653 → 680: the new example's required smoke row does not fit the old budget.
This commit is contained in:
@@ -140,7 +140,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'mode',
|
||||
title: 'Session-mode policy state',
|
||||
mode: 'core',
|
||||
consumers: ['stdio-agent'],
|
||||
consumers: ['stdio-agent', 'acp'],
|
||||
note: 'Folds the logged per-agent mode (mode/set), flushes user flips at turn boundaries, and enforces the mode through the assemble filter and the tools/pre-execute gate.',
|
||||
},
|
||||
{
|
||||
@@ -444,6 +444,14 @@ const APP_EXAMPLES = [
|
||||
config: 'examples/acp-agent/cordis.yml',
|
||||
summary: 'The ACP demo exposes the same agent spine over JSON-RPC stdio, with no stdout logger and no pre-created agent; clients create sessions through the ACP bridge.',
|
||||
},
|
||||
{
|
||||
id: 'plan-acp',
|
||||
rel: 'examples/plan-acp-agent/composition.md',
|
||||
title: 'Plan-Mode ACP Agent App Composition',
|
||||
label: 'examples/plan-acp-agent',
|
||||
config: 'examples/plan-acp-agent/cordis.yml',
|
||||
summary: 'The plan-mode demo composes session modes onto the ACP server: the editor mode picker drives plan mode, and the model exits through the user-reviewed exit_plan_mode tool.',
|
||||
},
|
||||
]
|
||||
|
||||
type AppExample = typeof APP_EXAMPLES[number]
|
||||
|
||||
Reference in New Issue
Block a user