Skip to content

Reaperrhs/a0-plugin-ask-user-question

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ™‹ Ask User Question β€” Agent Zero Plugin

Version License: MIT Agent Zero

Lets AI agents ask structured clarifying questions with a beautiful tabbed modal UI.

Instead of guessing what the user wants, the agent presents clear options and lets the user choose β€” directly inside the Agent Zero web interface.


✨ Features

  • Structured Questions β€” Agent presents 1–4 questions, each with 2–4 predefined options
  • Tabbed Modal UI β€” Clean, animated tabbed interface that fits the Agent Zero dark theme
  • Markdown Previews β€” Options can include markdown preview panes for rich context
  • Multi-Select Support β€” Allow users to pick multiple options per question
  • Free-Text "Other" β€” Users can always type a custom answer beyond the provided options
  • Optional Notes β€” Each question has a notes field for additional context
  • Review & Submit β€” Final review tab shows all answers before submission
  • Non-Blocking β€” The tool waits for user input without breaking the agent loop
  • Timeout Handling β€” Configurable timeout (default 300s) with graceful fallback
  • Notification Integration β€” Pushes a notification when questions are pending
  • Responsive Design β€” Works on desktop and mobile viewports

πŸ”„ How It Works

Agent-Side

  1. The agent calls the ask_user_question tool with a JSON payload of questions
  2. The tool creates a pending session and fires a notification
  3. It blocks (async) until the user answers or the timeout expires
  4. The structured answers are returned to the agent as a formatted message

User-Side

  1. The frontend polls for pending questions every 2 seconds
  2. When a question is detected, a modal appears with tabbed questions
  3. The user selects options, adds notes, and submits
  4. The answer is sent to the backend API, which signals the waiting tool

πŸ“¦ Installation

From Plugin Hub (Recommended)

In your Agent Zero instance, go to Settings β†’ Plugins β†’ Browse and search for "Ask User Question".

Manual Installation

  1. Clone this repository into your Agent Zero plugins directory:
cd /path/to/agent-zero/usr/plugins
git clone https://github.com/Reaperrhs/a0-plugin-ask-user-question.git ask_user_question
  1. Restart Agent Zero (or reload plugins from settings).

  2. The plugin auto-registers:

    • Tool: ask_user_question (available to the agent)
    • API endpoints: /plugins/ask_user_question/get_pending and /plugins/ask_user_question/submit_answer
    • WebUI extension: Modal component injected into the chat page

πŸš€ Usage

Basic Example β€” Single Question

{
  "questions": [
    {
      "question": "Which database would you like to use?",
      "header": "Database",
      "options": [
        { "label": "PostgreSQL", "description": "Robust relational database" },
        { "label": "MongoDB", "description": "Flexible document store" },
        { "label": "SQLite", "description": "Lightweight, file-based" }
      ]
    }
  ]
}

Advanced Example β€” Multiple Questions with Previews

{
  "questions": [
    {
      "question": "Which architecture style do you prefer?",
      "header": "Architecture",
      "options": [
        {
          "label": "Microservices",
          "description": "Distributed services with independent deployment",
          "preview": "## Microservices\n\n- Independent deploy\n- Service mesh\n- Event-driven"
        },
        {
          "label": "Modular Monolith",
          "description": "Single deployable with module boundaries"
        },
        {
          "label": "Serverless",
          "description": "Functions-as-a-service, auto-scaling"
        }
      ]
    },
    {
      "question": "What is the priority for this project?",
      "header": "Priority",
      "multiSelect": false,
      "options": [
        { "label": "Speed", "description": "Ship fast, iterate later" },
        { "label": "Quality", "description": "Production-grade from the start" },
        { "label": "Cost-efficient", "description": "Minimize infrastructure and dev time" }
      ]
    }
  ],
  "timeout": 120
}

Tool Response

When the user answers, the agent receives:

User answered the following questions:

Q1: Which architecture style do you prefer?
  Selected: Microservices

Q2: What is the priority for this project?
  Selected: Speed
  Notes: We need MVP in 2 weeks

πŸ“‹ Parameters

Parameter Type Required Default Description
questions array βœ… β€” 1–4 structured question objects
timeout integer ❌ 300 Seconds to wait for user response

Question Object

Field Type Required Description
question string βœ… Question text (must end with ?)
header string βœ… Tab label, max 16 characters
options array βœ… 2–4 option objects
multiSelect boolean ❌ Allow multiple selections (default: false)

Option Object

Field Type Required Description
label string βœ… Display text (max 60 chars)
description string ❌ Brief explanation
preview string ❌ Markdown shown in a preview pane

Reserved Labels

These labels are auto-provided and cannot be used:

  • Other β€” Always shown with a free-text input
  • Type something.
  • Chat about this
  • Next β†’

πŸ”Œ API Reference

GET/POST /plugins/ask_user_question/get_pending

Check if there are pending questions for a context.

Parameters:

  • context_id (string, required) β€” The chat context ID

Response (pending):

{
  "ok": true,
  "pending": true,
  "session_id": "uuid",
  "questions": [...],
  "created_at": 1234567890.123
}

Response (no pending):

{
  "ok": true,
  "pending": false
}

POST /plugins/ask_user_question/submit_answer

Submit answers or cancel a pending session.

Parameters:

  • session_id (string, required) β€” The session ID from get_pending
  • answers (array, required unless cancelled) β€” Array of answer objects
  • cancelled (boolean) β€” Set to true to decline answering

Answer Object:

{
  "question_index": 0,
  "selected": ["Option Label"],
  "other_text": "",
  "notes": ""
}

Response:

{ "ok": true }

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Agent Zero Framework                      β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚   Agent (LLM)   │────────▢│  tools/ask_user_question   β”‚ β”‚
β”‚  β”‚                 β”‚         β”‚  - Validates questions      β”‚ β”‚
β”‚  β”‚                 │◀────────│  - Creates session          β”‚ β”‚
β”‚  β”‚                 β”‚         β”‚  - Waits on asyncio.Event   β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                         β”‚                    β”‚
β”‚                                         β”‚ create_session()   β”‚
β”‚                                         β–Ό                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚               helpers/state.py (In-Memory)               β”‚β”‚
β”‚  β”‚  _pending: Dict[context_id β†’ PendingSession]             β”‚β”‚
β”‚  β”‚  - create_session()  - submit_answer()                   β”‚β”‚
β”‚  β”‚  - get_pending()     - cancel_session()                  β”‚β”‚
β”‚  β”‚  - cleanup_old_sessions() (10min TTL)                    β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–²β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚             β”‚                              β”‚                  β”‚
β”‚             β”‚ API                          β”‚ event.set()      β”‚
β”‚             β–Ό                              β”‚                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  api/get_pending.py  β”‚   β”‚  api/submit_answer.py       β”‚  β”‚
β”‚  β”‚  GET/POST            β”‚   β”‚  POST                       β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚             β”‚                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚ HTTP
              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    WebUI (Browser)                            β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚  webui/ask-store.js (Alpine.js Store)                    β”‚β”‚
β”‚  β”‚  - Polls /get_pending every 2s                           β”‚β”‚
β”‚  β”‚  - Manages modal state, answers, navigation              β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚  extensions/webui/page-head/ask-question-setup.html      β”‚β”‚
β”‚  β”‚  - Injected into page <head>                              β”‚β”‚
β”‚  β”‚  - Contains CSS + Alpine.js modal template                β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

State Management

  • In-Memory: Sessions are stored in a Python dictionary, keyed by context_id
  • TTL: Sessions expire after 10 minutes (_MAX_AGE = 600)
  • Supersession: New questions for the same context cancel previous pending ones
  • Asyncio.Event: The tool blocks on an asyncio.Event that is set when the user submits or cancels

Frontend Polling

  • The Alpine.js store polls get_pending every 2 seconds
  • When a pending session is detected, the modal appears automatically
  • After submission, the modal closes and polling resumes

πŸ› οΈ Development

File Structure

ask_user_question/
β”œβ”€β”€ plugin.yaml              # Plugin metadata
β”œβ”€β”€ api/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ get_pending.py       # GET/POST endpoint for pending questions
β”‚   └── submit_answer.py     # POST endpoint for submitting answers
β”œβ”€β”€ helpers/
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── state.py             # In-memory session state management
β”œβ”€β”€ tools/
β”‚   β”œβ”€β”€ __init__.py
β”‚   └── ask_user_question.py # Agent tool (async, blocking wait)
β”œβ”€β”€ prompts/
β”‚   └── agent.system.tool.ask_user_question.md  # Agent prompt instructions
β”œβ”€β”€ extensions/
β”‚   └── webui/
β”‚       └── page-head/
β”‚           └── ask-question-setup.html  # CSS + Alpine modal template
└── webui/
    └── ask-store.js         # Alpine.js reactive store

Running Locally

  1. Symlink or copy the plugin into your Agent Zero usr/plugins/ directory
  2. Restart Agent Zero
  3. In a chat, the agent can invoke the tool when it needs clarification

Modifying the UI

  • Styles: Edit the <style> block in extensions/webui/page-head/ask-question-setup.html
  • Modal Template: Edit the Alpine.js x-data template in the same file
  • Store Logic: Edit webui/ask-store.js for polling, state, and API calls
  • All CSS variables reference the Agent Zero theme (--color-primary, --color-background-elevated, etc.)

πŸ“„ License

This project is licensed under the MIT License.

Copyright Β© 2025 Agent Zero Community

About

Agent Zero plugin: Lets AI agents ask structured clarifying questions with a beautiful tabbed modal UI

Resources

License

Stars

4 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors