As an agent, I want to ask questions with selectors and batch support, so that I can collect structured responses efficiently.
SYNOPSIS
Extend the interview tool to support text, single-select, and multi-select inputs with TUI navigation and batch question capability.
DESCRIPTION
The interview tool currently only supports free-form text input. This story adds:
-
Input modes:
text- Free-form text input (current behavior, default)select- Radio-button style single choice from optionsmulti- Checkbox style multiple choice from options
-
TUI interaction (when terminal supports it):
- Arrow keys (up/down) to navigate between options
- Space to toggle selection (multi-select)
- Enter to confirm selection
-
Numbered fallback (for dumb terminals or piped input):
- Display numbered list (e.g., “1. Red”, “2. Green”, “3. Blue”)
- User types number to select
- Comma-separated numbers for multi-select (e.g., “1, 3”)
-
Batch questions:
- Accept array of questions in single call
- Present sequentially, collect all answers before returning
SEE ALSO
- lib/elelem/terminal.rb - Add
selectandmulti_selectmethods - lib/elelem/plugins/interview.rb - Add
options,multi, andquestionsparams
Tasks
- TBD (filled in design mode)
Acceptance Criteria
- Agent can provide
optionsarray to enable selector mode - Agent can set
multi: trueto allow multiple selections - Single-select with TUI: arrow keys navigate, enter confirms
- Multi-select with TUI: arrow keys navigate, space toggles, enter confirms
- Falls back to numbered list when terminal doesn’t support TUI
- Free-form text input still works when no options provided
- Agent can pass
questionsarray with multiple question objects - Each question in batch can have its own options and multi setting
- Batch returns array of answers matching question order
- Single-question API remains backward compatible
- No new gem dependencies (uses io/console from stdlib)
Implementation Notes
The following implementation plan is provided as guidance for the developer.
Tool Schema
{
"question": { "type": "string", "description": "The question to ask" },
"options": { "type": "array", "description": "List of options (enables selector)" },
"multi": { "type": "boolean", "description": "Allow multiple selections" },
"questions": { "type": "array", "description": "Batch of question objects" }
}
Files to Modify
lib/elelem/terminal.rb- Addselectandmulti_selectmethodslib/elelem/plugins/interview.rb- Addoptions,multi, andquestionsparams
Terminal API
# Single select - returns selected option string
terminal.select(options) # => "option1"
# Multi select - returns array of selected options
terminal.multi_select(options) # => ["option1", "option3"]
Reference Implementation
Terminal#select (single choice)
def select(options)
return options.first if options.size == 1
require "io/console"
index = 0
render_options = -> {
options.each_with_index do |opt, i|
prefix = i == index ? "> " : " "
$stdout.puts "#{prefix}#{opt}"
end
}
render_options.call
loop do
key = read_key
case key
when :up then index = (index - 1) % options.size
when :down then index = (index + 1) % options.size
when :enter then break
end
$stdout.print "\e[#{options.size}A\e[J"
render_options.call
end
options[index]
end
def read_key
char = $stdin.getch
return :enter if char == "\r" || char == "\n"
return char unless char == "\e"
return char unless $stdin.ready?
seq = $stdin.getch
return char unless seq == "["
code = $stdin.getch
case code
when "A" then :up
when "B" then :down
else char
end
end
Terminal#multi_select (multiple choice)
def multi_select(options)
require "io/console"
index = 0
selected = Set.new
render_options = -> {
options.each_with_index do |opt, i|
cursor = i == index ? ">" : " "
check = selected.include?(i) ? "[x]" : "[ ]"
$stdout.puts "#{cursor} #{check} #{opt}"
end
}
render_options.call
loop do
key = read_key
case key
when :up then index = (index - 1) % options.size
when :down then index = (index + 1) % options.size
when :space then selected.include?(index) ? selected.delete(index) : selected.add(index)
when :enter then break
end
$stdout.print "\e[#{options.size}A\e[J"
render_options.call
end
options.values_at(*selected.to_a.sort)
end
Updated Interview Plugin
Elelem::Plugins.register(:interview) do |agent|
agent.toolbox.add("interview",
description: "Ask the user a question and wait for their response",
params: {
question: { type: "string", description: "The question to ask" },
options: { type: "array", description: "List of options for selector" },
multi: { type: "boolean", description: "Allow multiple selections" },
questions: { type: "array", description: "Batch of question objects" }
},
required: ["question"]
) do |args|
if args["questions"]&.any?
# Batch mode
answers = args["questions"].map do |q|
agent.terminal.say(agent.terminal.markdown(q["question"]))
ask_one(agent.terminal, q["options"], q["multi"])
end
{ answers: answers }
else
# Single question mode
agent.terminal.say(agent.terminal.markdown(args["question"]))
answer = ask_one(agent.terminal, args["options"], args["multi"])
{ answer: answer }
end
end
def ask_one(terminal, options, multi)
if options&.any?
multi ? terminal.multi_select(options) : terminal.select(options)
else
terminal.ask("> ")
end
end
end
Verification
- Run
./bin/run -p vertex - Ask the LLM to use the interview tool with options
- Test arrow key navigation
- Test single select (Enter confirms)
- Test multi select (Space toggles, Enter confirms)
- Test free-form text still works when no options provided
- Test batch questions with mixed types
- Run
bin/test