use schemars::JsonSchema;
use serde::Deserialize;
use serde_json::Value;
use crate::{Question, QuestionOption, RunEvent, ToolKind};
use super::{parse_args, schema_for, Tool, ToolCtx, ToolOutcome};
#[derive(Deserialize, JsonSchema)]
struct QuestionArgs {
questions: Vec<QuestionPrompt>,
}
#[derive(Deserialize, JsonSchema)]
struct QuestionPrompt {
header: Option<String>,
question: String,
options: Vec<QuestionOpt>,
multiple: Option<bool>,
}
#[derive(Deserialize, JsonSchema)]
struct QuestionOpt {
label: String,
description: Option<String>,
}
pub(super) struct QuestionTool;
impl Tool for QuestionTool {
fn id(&self) -> &str {
"question"
}
fn description(&self) -> &str {
"Ask the user one or more multiple-choice questions to clarify intent or \
choose between approaches. The user's answer arrives as the next \
message — pose the question, then wait for it. Put a recommended option \
first; a free-text answer is always available, so don't add an 'Other'."
}
fn parameters(&self) -> Value {
schema_for::<QuestionArgs>()
}
fn kind(&self) -> ToolKind {
ToolKind::Other
}
fn mutating(&self) -> bool {
false
}
fn in_subagent(&self) -> bool {
false }
fn execute(&self, args: &Value, ctx: &ToolCtx) -> ToolOutcome {
let a: QuestionArgs = match parse_args(args) {
Ok(a) => a,
Err(o) => return o,
};
if a.questions.is_empty() {
return ToolOutcome::err("question: provide at least one question");
}
let questions: Vec<Question> = a
.questions
.into_iter()
.map(|q| Question {
header: q.header,
prompt: q.question,
options: q
.options
.into_iter()
.map(|o| QuestionOption { label: o.label, description: o.description })
.collect(),
multi_select: q.multiple.unwrap_or(false),
allow_free_text: true,
})
.collect();
let n = questions.len();
let ask = RunEvent::AskQuestion {
run_id: ctx.run_id.to_owned(),
request_id: ctx.call_id.to_owned(),
questions,
};
ToolOutcome::stop(format!(
"Posed {n} question{} to the user; their answer will arrive as the next message — wait for it before continuing.",
if n == 1 { "" } else { "s" }
))
.with_events(vec![ask])
}
}