Skip to content

Conversation

@cdakotabrown
Copy link
Contributor

@cdakotabrown cdakotabrown commented Jan 13, 2026

Summary

Introduces a new ask_user_question tool that allows agents to ask users interactive multiple-choice questions through a split-panel terminal TUI. This feature is similar to Claude Code's AskUserQuestion tool, enabling agents to gather user input, preferences, and confirmations during task execution.

ask.mp4

Changes Made

New Tool Package: code_puppy/tools/ask_user_question/

  • __init__.py - Package exports with public API (ask_user_question, register_ask_user_question, and Pydantic models)
  • constants.py - Configuration constants including limits, timeouts, UI settings, and Unicode symbols
  • models.py - Comprehensive Pydantic models with validation:
    • QuestionOption - Individual selectable option with label and description
    • Question - Question with header, options (2-6), and multi-select support
    • AskUserQuestionInput - Input schema supporting 1-10 questions
    • QuestionAnswer - Answer container with selected options and "Other" text
    • AskUserQuestionOutput - Output with answers, cancelled/timed_out/error states
  • handler.py - Main entry point with:
    • Interactive environment detection (TTY check, CI detection)
    • Async context handling with helpful error messages
    • Input validation and error formatting
  • registration.py - Tool registration with comprehensive docstring and usage examples
  • terminal_ui.py - Core UI state management (QuestionUIState class) with:
    • Navigation state (cursor positions, selections)
    • Timeout tracking with monotonic time
    • Answer building logic
  • tui_loop.py - Async TUI event loop with prompt_toolkit integration
  • renderers.py - Panel rendering (left question tabs, right question details)
  • theme.py - Themeable color schemes with code-puppy config integration
  • demo_tui.py - Standalone demo script for testing the TUI

Integration Points

  • code_puppy/tools/__init__.py

    • Added import: from code_puppy.tools.ask_user_question import register_ask_user_question
    • Added to TOOL_REGISTRY: "ask_user_question": register_ask_user_question
  • code_puppy/agents/agent_code_puppy.py

    • Added "ask_user_question" to get_available_tools() list
    • Added comprehensive User Interaction documentation in system prompt

Technical Details

Architecture

ask_user_question/
├── models.py          # Pydantic schemas (input/output validation)
├── handler.py         # Entry point, environment detection
├── registration.py    # pydantic-ai tool registration
├── terminal_ui.py     # UI state management
├── tui_loop.py        # Async event loop (prompt_toolkit)
├── renderers.py       # Panel rendering
├── theme.py           # Color configuration
└── constants.py       # All magic numbers centralized

Design Decisions

  1. Split-panel TUI: Left panel shows question headers (tabs), right panel shows current question with options. Similar to /colors command UX.

  2. Pydantic validation: All input is validated with sanitization (ANSI stripping, whitespace trimming) and constraints (max lengths, option counts).

  3. Async-first with sync wrapper: Core TUI runs async with prompt_toolkit. The ask_user_question() function wraps with asyncio.run() for sync callers, with helpful error if called from async context.

  4. Inactivity timeout: Default 5-minute timeout with warning at 60 seconds remaining. Uses time.monotonic() to avoid clock drift issues.

  5. CI environment detection: Automatically returns error in CI environments (GitHub Actions, GitLab CI, Jenkins, etc.) rather than hanging.

  6. Alternate screen buffer: Uses terminal escape sequences to preserve existing terminal content during interaction.

  7. "Other" option: Automatically adds "Other" option for custom user input, with dedicated text entry mode.

  8. Theming integration: Colors can be customized via code-puppy's config system.

Keyboard Navigation

Key Action
←→ Switch between questions
↑↓ Navigate options
Space Toggle option (multi-select)
Enter Select/Next/Submit
Ctrl+S Submit all answers
Esc/Ctrl+C Cancel
? Show help overlay

Validation Rules

  • 1-10 questions per call
  • 2-6 options per question
  • Header: max 12 chars, spaces → hyphens
  • Label: max 50 chars
  • Description: max 200 chars
  • Question text: max 500 chars
  • Unique headers and labels required

Files Modified

File Changes
code_puppy/tools/__init__.py +3 lines (import + registry entry)
code_puppy/agents/agent_code_puppy.py +19 lines (tool list + docs)
code_puppy/tools/ask_user_question/__init__.py New (26 lines)
code_puppy/tools/ask_user_question/constants.py New (73 lines)
code_puppy/tools/ask_user_question/demo_tui.py New (55 lines)
code_puppy/tools/ask_user_question/handler.py New (212 lines)
code_puppy/tools/ask_user_question/models.py New (304 lines)
code_puppy/tools/ask_user_question/registration.py New (87 lines)
code_puppy/tools/ask_user_question/renderers.py New (298 lines)
code_puppy/tools/ask_user_question/terminal_ui.py New (346 lines)
code_puppy/tools/ask_user_question/theme.py New (154 lines)
code_puppy/tools/ask_user_question/tui_loop.py New (350 lines)
tests/tools/test_ask_user_question/__init__.py New (1 line)
tests/tools/test_ask_user_question/test_handler.py New (201 lines)
tests/tools/test_ask_user_question/test_models.py New (444 lines)

Total: 15 files, +2,573 lines

Testing

Unit Tests Added

  • test_models.py (444 lines)

    • QuestionOption validation (label, description, sanitization)
    • Question validation (options count, unique labels, multi-select)
    • AskUserQuestionInput validation (question count, unique headers)
    • QuestionAnswer properties (has_other, is_empty)
    • AskUserQuestionOutput helper methods (success, get_answer, get_selected)
  • test_handler.py (201 lines)

    • Environment detection (TTY, CI environments)
    • Input validation (empty array, too many questions, invalid options)
    • Error message formatting

Manual Testing

# Run the demo TUI
python -m code_puppy.tools.ask_user_question.demo_tui

Breaking Changes

None. This is a purely additive feature.

Additional Notes

Usage Example

ask_user_question(questions=[{
    "question": "Which database should we use?",
    "header": "Database",
    "options": [
        {"label": "PostgreSQL", "description": "Relational, ACID compliant"},
        {"label": "MongoDB", "description": "Document store, flexible schema"}
    ]
}])

Minimalism Principles (from docstring)

  • Use only when 2+ related questions need answers together
  • Don't use for simple yes/no - just ask in conversation
  • Prefer 2-3 questions over 4+
  • Make reasonable defaults when possible

Dependencies

No new dependencies added. Uses existing:

  • pydantic - Input/output validation
  • prompt_toolkit - Terminal TUI
  • rich - Panel rendering

similar to claude code AskUserQuestion tool
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.

1 participant