Sagents.Middleware.AskUserQuestion (Sagents v0.16.2)
Copy MarkdownMiddleware that gives agents a structured way to ask the user questions.
Provides an ask_user tool that triggers the existing interrupt/resume lifecycle
with typed question and response data. This enables UIs to render appropriate
controls (radio buttons, checkboxes, text inputs) based on the question type.
Configuration
# All response types (default)
Sagents.Middleware.AskUserQuestion
# Restricted to specific types
{Sagents.Middleware.AskUserQuestion, response_types: [:single_select, :multi_select]}Forcing allow_other / allow_cancel
By default the LLM chooses allow_other and allow_cancel per question. Set
either to a fixed boolean in the init config to force it for every question
and remove it from the LLM's control. Omit a key to leave it LLM-decided.
# User must always answer (never cancel); always offer an "Other" input
{Sagents.Middleware.AskUserQuestion, allow_cancel: false, allow_other: true}Response Types
:single_select- User picks one option from a list (radio buttons):multi_select- User picks one or more options (checkboxes):freeform- User provides free-form text input
Interrupt Data
When the agent calls ask_user, execution returns:
{:interrupt, state, %{
type: :ask_user_question,
question: "Which database should we use?",
response_type: :single_select,
options: [
%{label: "PostgreSQL", value: "PostgreSQL", description: "Relational DB"},
%{label: "MongoDB", value: "MongoDB", description: "Document store"}
],
allow_other: false,
allow_cancel: true,
context: "We need a primary data store for the user service.",
tool_call_id: "call_123"
}}Every option has a :value. The LLM may supply one, but usually omits it, and
then the value is the option's label. Labels are single-line: line breaks
inside a label are collapsed to a space.
Resume Data
Resume with a response map. selected holds option values, posted back
unchanged from the interrupt's options:
# Answer
AgentServer.resume(agent_id, %{type: :answer, selected: ["PostgreSQL"]})
# Answer with additional text
AgentServer.resume(agent_id, %{
type: :answer,
selected: ["PostgreSQL"],
other_text: "Use jsonb columns"
})
# Cancel
AgentServer.resume(agent_id, %{type: :cancel})Result
The LLM receives the selected option values as text: one line for
:single_select, a Markdown bullet list for :multi_select. When the LLM
omitted value, that text is the label the user chose.
The resolved tool result also carries the answer in processed_content,
which is not sent to the LLM:
%{type: :answer, selected: [%{label: "PostgreSQL", value: "PostgreSQL"}], other_text: nil}
%{type: :cancel}selected lists the chosen regular options. The special "other" selection
is not included; its typed text is in other_text. A :freeform answer has
selected: [] and the text in other_text. processed_content is a virtual
field and is not persisted with the state.
Summary
Functions
Process a user's response to a question.