feat: add answer extraction replay commands

This commit is contained in:
Erik Kotsiuba
2026-05-02 22:47:55 +02:00
parent 288caf49de
commit 5b70eca306
36 changed files with 1636 additions and 98 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ This folder keeps only the documentation needed to understand and maintain the e
## Files
- `configuration.md` — source of truth for configuring pi-ask keymaps and behaviour
- `configuration.md` — source of truth for configuring pi-ask keymaps, behaviour, and `/answer` extraction
- `contract.md` — external behavior, full tool payload/result details, and UX guarantees
- `architecture.md` — module boundaries and invariants
- `../skills/ask-user/SKILL.md` — auto-bundled agent-side decision-gate guidance; enabled by default, but can be disabled via `pi config`; inspired by https://github.com/edlsh/pi-ask-user
+5 -1
View File
@@ -14,7 +14,10 @@ The codebase is split so the implementation reads through file boundaries and na
### Tool surface
- `src/index.ts` — extension entrypoint
- `src/ask-tool.ts` — tool registration, non-interactive fallback, transcript rendering
- `src/ask-tool.ts` — tool registration, non-interactive fallback, transcript rendering, ask payload capture
- `src/answer-commands.ts` — `/answer`, `/answer:again`, and `/ask:replay` command wiring
- `src/answer-extraction.ts` — configured extraction model selection and raw-JSON extraction retries
- `src/ask-payload-store.ts` — branch-aware persisted ask payload lookup
- `src/schema.ts` — TypeBox schema
- `src/types.ts` — shared types
@@ -72,6 +75,7 @@ The codebase is split so the implementation reads through file boundaries and na
- editor lifecycle stays in the controller, not in the reducers
- persisted ask settings are migrated to the current schema version, validated, and normalized before use
- config schema migrations preserve user-provided values and add new defaults only when fields are absent
- replay payload lookup scans only the current session branch and revalidates payloads before use
- invalid persisted keymaps fall back to default keymaps for the current session without discarding valid behaviour settings
- ask settings behaviour changes persist immediately from the settings list
- when the ask config file is missing, the first ask use writes a default persisted config snapshot under `~/.pi/agent/extensions/`
+44 -3
View File
@@ -28,7 +28,16 @@ Unsupported future versions or invalid files are backed up and defaults are load
```json
{
"schemaVersion": 1,
"schemaVersion": 2,
"answer": {
"extractionModels": [
{ "provider": "openai-codex", "id": "gpt-5.4-mini" },
{ "provider": "github-copilot", "id": "gpt-5.4-mini" },
{ "provider": "anthropic", "id": "claude-haiku-4-5" }
],
"extractionTimeoutMs": 30000,
"extractionRetries": 1
},
"behaviour": {
"autoSubmitWhenAnsweredWithoutNotes": false,
"confirmDismissWhenDirty": true,
@@ -46,6 +55,29 @@ Unsupported future versions or invalid files are backed up and defaults are load
}
```
## Answer extraction
These settings affect only the `/answer` command. Normal `ask_user` tool calls do not use an extraction model.
### `answer.extractionModels`
- type: array of `{ "provider": string, "id": string }`
- default: `openai-codex/gpt-5.4-mini`, `github-copilot/gpt-5.4-mini`, then `anthropic/claude-haiku-4-5`
- effect: `/answer` tries configured models in order and uses the first model with available auth
- fallback: if no configured model is usable, `/answer` tries the current chat model after validating its auth
### `answer.extractionTimeoutMs`
- type: positive number
- default: `30000`
- effect: per-attempt extraction timeout in milliseconds
### `answer.extractionRetries`
- type: integer from `0` to `3`
- default: `1`
- effect: number of retry attempts after raw JSON parsing fails; retries include the parse error and previous response as feedback
## Behaviour
### `behaviour.autoSubmitWhenAnsweredWithoutNotes`
@@ -184,7 +216,14 @@ Invalid keymaps include:
```json
{
"schemaVersion": 1,
"schemaVersion": 2,
"answer": {
"extractionRetries": 1,
"extractionTimeoutMs": 30000,
"extractionModels": [
{ "provider": "openai-codex", "id": "gpt-5.4-mini" }
]
},
"behaviour": {
"autoSubmitWhenAnsweredWithoutNotes": true,
"confirmDismissWhenDirty": true,
@@ -207,7 +246,9 @@ Invalid keymaps include:
When editing this config for a user:
- preserve unrelated fields
- keep `schemaVersion` at `1`
- keep `schemaVersion` at `2`
- preserve `answer.extractionModels` as explicit provider/id pairs
- keep `answer.extractionRetries` between `0` and `3`
- do not assign reserved bindings to configurable actions
- do not create duplicate configurable bindings
- after changing the file, tell the user to run `/reload` or restart pi
+14
View File
@@ -200,6 +200,10 @@ This document defines the stable external behavior. It does not explain internal
- on the review tab, `Submit` and `Cancel` preview notes only for answered questions
- on the review tab, `Elaborate` preview expands to all question notes and all option notes, including notes on unselected options
- transcript-friendly call and result rendering
- `/answer` command to extract a raw-JSON `AskParams` form from the latest completed assistant message and open the ask UI
- `/answer` extraction may use an internal `freeform: true` option for open-ended questions with no explicit choices; these render as user-input-only questions with the label `Type your answer:`, no numbered option row, and no selection caret; this marker is not part of the public `ask_user` tool contract
- `/answer:again` command to replay the latest `/answer`-extracted form on the current branch
- `/ask:replay` command to replay the latest real `ask_user` form on the current branch
- ask settings list with binary behaviour toggles
- `?` in the ask flow and `/ask-settings` in pi open the same lightweight ask settings overlay
- behaviour settings persist immediately when changed: `Auto-submit when answered without notes`, `Confirm dismiss when dirty`, `Double-press review shortcuts`, and `Show footer hints`
@@ -241,6 +245,16 @@ Validation is handled inside the tool so malformed calls produce the same struct
The ask flow subscribes to runtime settings updates while open. In practice, this means changing `Auto-submit when answered without notes`, `Confirm dismiss when dirty`, `Double-press review shortcuts`, `Show footer hints`, or reloading config-backed keymaps can affect the in-progress ask flow immediately instead of only future asks.
## Slash command replay/extraction
- valid `ask_user` payloads are persisted as branch custom entries before the UI opens, so `/ask:replay` can reopen them after cancel, `/resume`, or `/tree`
- `/answer` scans the current branch for the latest assistant message; if that message did not finish with `stop`, extraction is refused
- `/answer` expects the extractor to return raw JSON only; JSON parse failures are retried according to `answer.extractionRetries`, then reported to the user without opening the ask UI
- `{ "questions": [] }` from extraction means no questions were found and is not treated as an invalid ask payload
- command-flow cancellation closes with a notification and does not send a message to the agent
- submitted or elaborated command-flow results are sent back with user-message semantics
- replay commands scan only `ctx.sessionManager.getBranch()`, ignore sibling/future branch payloads, and revalidate stored payloads before opening the UI
The fallback message includes normalized pending questions and options so the caller can re-ask them manually. `details.questions` still contains normalized question metadata, while `details.answers` stays empty until a user responds.
## Skill alignment (advisory)