use std::sync::Arc;
use async_trait::async_trait;
use serde_json::Value;
use crate::core::{DynTool, ToolContext};
use crate::error::{Error, Result};
use crate::genai_types::{FunctionDeclaration, Schema};
#[derive(Debug)]
struct GetUserChoice;
#[async_trait]
impl DynTool for GetUserChoice {
fn name(&self) -> &str {
"get_user_choice"
}
fn description(&self) -> &str {
"Ask the user to pick one of several options before continuing. \
Use this for human-in-the-loop confirmations."
}
fn is_long_running(&self) -> bool {
true
}
fn declaration(&self) -> Option<FunctionDeclaration> {
Some(
FunctionDeclaration::new(self.name(), self.description()).with_parameters(
Schema::object()
.property(
"prompt",
Schema::string().with_description("Question for the user."),
)
.property(
"options",
Schema::array(Schema::string()).with_description("Available answers."),
)
.require("prompt")
.require("options"),
),
)
}
async fn run(&self, args: Value, ctx: &mut ToolContext) -> Result<Value> {
let prompt = args
.get("prompt")
.and_then(Value::as_str)
.ok_or_else(|| Error::invalid_input("prompt must be a string"))?;
let options: Vec<String> = args
.get("options")
.and_then(|v| serde_json::from_value(v.clone()).ok())
.ok_or_else(|| Error::invalid_input("options must be an array of strings"))?;
ctx.long_running = true;
Ok(serde_json::json!({
"status": "awaiting_user",
"prompt": prompt,
"options": options,
}))
}
}
#[must_use]
pub fn get_user_choice_tool() -> Arc<dyn DynTool> {
Arc::new(GetUserChoice)
}