The UserInteractionRegistry is the mechanism that allows tools to “pause” and ask the user for information or confirmation. This is essential for tools that require human-in-the-loop decisions.

Architecture

The registry works by coordinating between the async tool execution task and the UI event loop. It uses oneshot channels to bridge the gap between an async request and its eventual response.

pub struct UserInteractionRegistry {
    pending_interactions: Mutex<HashMap<String, InteractionSender>>,
    event_sender: mpsc::UnboundedSender<ControllerEvent>,
}

How it Works

  1. Tool Requests Interaction: A tool calls a method on the interaction_registry (via the ToolContext).
  2. Registry Creates a Channel: The registry generates a unique ID, creates a oneshot channel, and stores the sender.
  3. Emit Event: The registry sends a ControllerEvent (e.g., AskUser) to the controller, which passes it to the UI.
  4. Tool Awaits: The tool execution task awaits the receiver of the oneshot channel.
  5. User Responds: The UI captures the user’s input and sends it back to the controller.
  6. Complete Interaction: The controller calls complete_interaction(id, response) on the registry.
  7. Resume Tool: The oneshot sender is triggered, the tool receives the response and continues execution.

Example: AskUserQuestions

The AskUserQuestions tool is a built-in tool that utilizes this registry.

// Inside a tool's execute method
let response = context.interaction_registry
    .ask_user(context.session_id, "What is your favorite color?")
    .await?;

// response is now the string the user typed

Interaction Types

While the most common interaction is a simple text question, the registry can support various types:

  • Confirmation: Yes/No prompts.
  • Selection: Choosing from a list of options.
  • Form: Multiple input fields.

Timeouts and Cleanup

To prevent “zombie” tasks, the registry can implement timeouts. If a user doesn’t respond within a certain period, the interaction can be automatically cancelled, and the tool will receive an error, allowing it to exit gracefully.