Skip to content

feature/chat questionaire - #377

Merged
ahmad-ajmal merged 3 commits into
feature/multi-account-integrationsfrom
feature/agent-clarifying-questions
Jul 10, 2026
Merged

ahmad-ajmal merged 3 commits into
feature/multi-account-integrationsfrom
feature/agent-clarifying-questions

Conversation

@AlanAAG

@AlanAAG AlanAAG commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds ask_user_questions, an agent-driven clarifying-question UI for chat. Instead of the agent asking for missing/ambiguous info as a plain text message, it can now ask via an interactive stepper — multiple-choice (single- or multi-select) or open-ended, batched with a review step when there's more than one question, with a free-text override and an Esc-to-decline escape hatch.

  • New ask_user_questions action (app/data/action/ask_user_questions.py): batch of questions, each with optional choices and multi-select; resumes the parked task through the existing reply-to-task path (submit_message + reply_context) rather than adding new resume machinery.
  • Refuses to ask (returns an error to the agent instead of parking) when nobody is connected to the interface, so a proactive/scheduled run doesn't stall indefinitely waiting on a reply that may never come.new resume machinery.
  • Refuses to ask (returns an error to the agent instead of parking) when nobody is connected to the interface, so a proactive/scheduled run doesn't stall indefinitely waiting on a reply that may never come.
  • Prompt guidance is deliberately scoped: use it when there are concrete choices to offer, or when batching several related questions together — a single standalone open-ended question stays a normal conversational send_message reply, so the UI isn't popping a form for every question.
  • QuestionStepper frontend component: nav/back for multi-question batches (collapses to a bare question when there's just one), checkboxes for multi-select, an always-visible free-text fallback, decline via Esc.

Why this PR's base is feature/multi-account-integrations, not V1.4.1

This branch was created off feature/multi-account-integrations rather than V1.4.1 because of a real dependency: the first concrete trigger for ask_user_questions is the Gmail account-ambiguity case, where resolve_account() (only present on that branch) returns an error listing candidate accounts, and prompt guidance here teaches the agent to turn that into an ask_user_questions call with those accounts as choices. Without multi-account support already in place, that trigger path doesn't exist to test against.

Against this base, the diff is scoped to just this feature's commit, the multi-account commits aren't part of what's under review here, they're the prerequisite this branch builds on. No changes are made in this PR to account-resolution logic itself (accounts.py, gmail_actions.py, _helpers.py); that work continues separately.

Test plan

  • ruff check on touched Python files
  • pytest tests/
  • Frontend production build (vite build)
  • Manual pass: single-question MCQ, open-ended question, multi-select checkboxes, multi-question batch (nav/back/review), decline via Esc, free-text override on an MCQ, single-question stripped-down UI, interrupting a pending question with an unrelated message, empty-input disabled state, edit-before-submit on review
    Tip: Open the Command Palette (Cmd+Shift+P) and run "Shell Command: Install 'code' command in PATH" to enable IDE integration

Comment thread app/data/action/ask_user_questions.py Outdated
)

status = "success" if simulated_mode else "ok"
return {"status": status, "fire_at_delay": 10800}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agent_base needs wait_for_user_reply in order to pause the trigger continuation. This does not return that and hence does not pause the flow. Currently it will fire the next trigger after 10800 even if the user never replies.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed: return "wait_for_user_reply": True (always pauses by design), matching send_message.py.

// Esc abandons the whole batch — only while it's still unanswered.
useEffect(() => {
if (resolved) return
const handler = (e: KeyboardEvent) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to make this specific to tasks rather than a global key check? This would basically decline every question batch no matter where you press the escape key since its just a base keydown listener

@AlanAAG AlanAAG Jul 9, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed: moved to onKeyDown on the stepper's own root div, so it only fires via DOM bubbling from that stepper's own focused controls.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure but please validate if scroll up pagination works. Do not want this questionnaire to be removed from the rendered messages history if you scroll up after a while

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed both to match the live-broadcast serialization.

const isReview = !single && step === questions.length
const current = questions[step]

const goToStep = (i: number) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sometimes when I navigate back and forth - it wipes the values

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed: goToStep now rehydrates from the stored answer, and answerCurrent's forward step routes through it too for consistency.

@AlanAAG
AlanAAG requested a review from ahmad-ajmal July 9, 2026 06:49
- Error instead of parking 3h when no UI can answer (CLI mode / no
  clients), via new InterfaceAdapter.can_prompt_user()
- Drop duplicate submits from stale tabs (atomic first-submission-wins
  in storage) and broadcast resolution to all clients
- QuestionStepper: structured per-question drafts (comma values no longer
  corrupt on back-nav), selected-choice highlight, Dismiss button, Esc in
  free-text clears instead of declining
- Resume text falls back to storage after restart (no more raw "q1" ids)
- Dedupe question serializers into ChatMessageQuestion to_dict/from_dict
- Extract WAIT_FOR_REPLY_PARK_DELAY_SECONDS (imported inside action bodies - executor exec()s function source only)
@ahmad-ajmal
ahmad-ajmal merged commit f729fc0 into feature/multi-account-integrations Jul 10, 2026
@ahmad-ajmal
ahmad-ajmal deleted the feature/agent-clarifying-questions branch August 10, 2026 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants