Feat/interactive agent questions#28
Merged
Merged
Conversation
U1: ask_user extension accepts optional kind (input/select/confirm) and options, feature-detecting ctx.ui.select/confirm with an input fallback. U2: decoder extracts options; kind+options persist on tasks (migration 012) and flow through SetAwaitingInput, the task_awaiting_input WS payload, and the snapshot response so a reconnect reconstructs the typed prompt.
U3: carry pendingQuestionKind + pendingQuestionOptions through the AgentTask / TaskEventPayload types and the agent-runs reducer (live event + snapshot paths). Adds a Vitest-style reducer spec following the repo's tsc-checked convention (no runner wired yet). U4: the thread drawer renders choice buttons for a select question and yes/no for a confirm, with the composer as the free-text / Other fallback; answers route through the existing steer path.
Escalate a failed InstallPiExtension to error level, return the error so the caller can react, and tell the user via logFn that agents in the session cannot ask questions and may guess instead. Provisioning stays non-fatal.
… JSON
When the structured extension_ui_request never fires (extension missing, or the
model narrates the call as text), the reply arrives shaped like
ask_user({"question":"..."}). sanitizeNarratedQuestion rewrites it to the
plain question before persist/broadcast/post, preserving surrounding prose and
degrading a truncated call to a readable floor rather than a JSON fragment
(R9/R11/R12, AE3/AE4).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Agent questions could reach the user as a raw tool-call string in the thread, e.g.
Ask_user({"question":"What file would you like me to create?"}). That's the structured question path failing — theextension_ui_requestevent never fires, so the model's narrated call posts as plain text. Two gaps stacked: even on the happy path the question rendered as bare text with no input affordance, and on the failure path it showed raw JSON.This makes agent questions interactive typed prompts (text / pick-one buttons / yes-no, with a free-text "Other" fallback) and guarantees a question is never shown as raw JSON. Scoped entirely to the Pi harness — no work on the legacy
claudeexecutor (slated for removal).Origin: requirements · plan
How it works
ask_usertakes an optionalkind+options; the extension feature-detectsctx.ui.select/confirmand falls back toinput-with-options when absent.kind+optionsflow through the decoder, persist ontasks(migration 012 — so a reconnect/snapshot reconstructs the prompt), ride thetask_awaiting_inputpayload, and render as buttons / yes-no in the thread drawer. Answers route back through the existing steer →extension_ui_responsepath.return nil). Provisioning stays non-fatal.ask_user({...})into the plain question before persist/broadcast/post, preserving surrounding prose and degrading a truncated call to a readable floor — never a JSON fragment.Scope notes / deviations from the plan
pending_question_kind TEXT,pending_question_options TEXT[], both defaulted) — additive/backward-compatible. The plan assumed no persistence change, but without it a snapshot refetch would drop the buttons mid-question.tsc, type-checked viatsc --noEmituntil a runner lands; seetsconfig.app.json). The reducer spec runs the moment a runner is added.Testing
go build/go vet/go test ./...all green (full DB-backed suite). New tests: decoder options, theagent-runsreducer (incl. snapshot preservation), and the backstop (AE3/AE4 + passthrough negatives).npm run build+tsc+eslintclean.ctx.ui.select/confirmrequest shape and the exact value Pi expects for a confirm answer. The runtime feature-detection +"yes"/"no"text answer ships either way; worth a smoke-test in a real session before merge.🤖 Generated with Claude Code