feat: renamed the user__ask to user__select and improved descriptions to improve model usage
This commit is contained in:
@@ -207,7 +207,7 @@ pub(in crate::config) const DEFAULT_USER_INTERACTION_INSTRUCTIONS: &str = indoc!
|
|||||||
## User Interaction
|
## User Interaction
|
||||||
|
|
||||||
You have built-in tools to interact with the user directly:
|
You have built-in tools to interact with the user directly:
|
||||||
- `user__ask --question \"...\" --options [\"A\", \"B\", \"C\"]`: Present a selection prompt. Returns the chosen option.
|
- `user__select --question \"...\" --options [\"A\", \"B\", \"C\"]`: Present a single-select list of named options. Use this — not `user__confirm` — whenever there are 2+ named options. Returns the chosen option.
|
||||||
- `user__confirm --question \"...\"`: Ask a yes/no question. Returns \"yes\" or \"no\".
|
- `user__confirm --question \"...\"`: Ask a yes/no question. Returns \"yes\" or \"no\".
|
||||||
- `user__input --question \"...\"`: Request free-form text input from the user.
|
- `user__input --question \"...\"`: Request free-form text input from the user.
|
||||||
- `user__checkbox --question \"...\" --options [\"A\", \"B\", \"C\"]`: Multi-select prompt. Returns an array of selected options.
|
- `user__checkbox --question \"...\" --options [\"A\", \"B\", \"C\"]`: Multi-select prompt. Returns an array of selected options.
|
||||||
|
|||||||
@@ -4784,7 +4784,7 @@ mod tests {
|
|||||||
let fns = ctx.select_functions(&role).unwrap();
|
let fns = ctx.select_functions(&role).unwrap();
|
||||||
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
||||||
assert!(names.contains(&"todo__init"));
|
assert!(names.contains(&"todo__init"));
|
||||||
assert!(names.contains(&"user__ask"));
|
assert!(names.contains(&"user__select"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -4848,7 +4848,7 @@ mod tests {
|
|||||||
|
|
||||||
let fns = ctx.select_functions(&role).unwrap();
|
let fns = ctx.select_functions(&role).unwrap();
|
||||||
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
||||||
assert!(names.contains(&"user__ask"));
|
assert!(names.contains(&"user__select"));
|
||||||
assert!(!names.contains(&"skill__list"));
|
assert!(!names.contains(&"skill__list"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4933,7 +4933,7 @@ mod tests {
|
|||||||
"teammate tools must survive an agent tool filter, got: {names:?}"
|
"teammate tools must survive an agent tool filter, got: {names:?}"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
names.contains(&"user__ask"),
|
names.contains(&"user__select"),
|
||||||
"user__ tools must survive an agent tool filter, got: {names:?}"
|
"user__ tools must survive an agent tool filter, got: {names:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1875,7 +1875,7 @@ mod tests {
|
|||||||
fn functions_append_user_interaction_adds_declarations() {
|
fn functions_append_user_interaction_adds_declarations() {
|
||||||
let mut f = Functions::default();
|
let mut f = Functions::default();
|
||||||
f.append_user_interaction_functions();
|
f.append_user_interaction_functions();
|
||||||
assert!(f.contains("user__ask"));
|
assert!(f.contains("user__select"));
|
||||||
assert!(f.contains("user__confirm"));
|
assert!(f.contains("user__confirm"));
|
||||||
assert!(f.contains("user__input"));
|
assert!(f.contains("user__input"));
|
||||||
assert!(f.contains("user__checkbox"));
|
assert!(f.contains("user__checkbox"));
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ const CUSTOM_MULTI_CHOICE_ANSWER_OPTION: &str = "Other (custom)";
|
|||||||
pub fn user_interaction_function_declarations() -> Vec<FunctionDeclaration> {
|
pub fn user_interaction_function_declarations() -> Vec<FunctionDeclaration> {
|
||||||
vec![
|
vec![
|
||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
name: format!("{USER_FUNCTION_PREFIX}ask"),
|
name: format!("{USER_FUNCTION_PREFIX}select"),
|
||||||
description: "Ask the user to select one option from a list. Returns the selected option. Indicate the recommended choice if there is one.".to_string(),
|
description: "Present a list of named options and ask the user to pick exactly one. \
|
||||||
|
Indicate the recommended choice if there is one. \
|
||||||
|
Use this — not `confirm` — whenever there are 2+ named options to choose \
|
||||||
|
between. Returns the selected option.".to_string(),
|
||||||
parameters: JsonSchema {
|
parameters: JsonSchema {
|
||||||
type_value: Some("object".to_string()),
|
type_value: Some("object".to_string()),
|
||||||
properties: Some(IndexMap::from([
|
properties: Some(IndexMap::from([
|
||||||
@@ -50,7 +53,9 @@ pub fn user_interaction_function_declarations() -> Vec<FunctionDeclaration> {
|
|||||||
},
|
},
|
||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
name: format!("{USER_FUNCTION_PREFIX}confirm"),
|
name: format!("{USER_FUNCTION_PREFIX}confirm"),
|
||||||
description: "Ask the user a yes/no question. Returns \"yes\" or \"no\".".to_string(),
|
description: "Ask a genuinely binary yes/no question with no other choices. Do NOT \
|
||||||
|
use for \"A or B?\" situations — use `select` instead. Returns \"yes\" \
|
||||||
|
or \"no\".".to_string(),
|
||||||
parameters: JsonSchema {
|
parameters: JsonSchema {
|
||||||
type_value: Some("object".to_string()),
|
type_value: Some("object".to_string()),
|
||||||
properties: Some(IndexMap::from([(
|
properties: Some(IndexMap::from([(
|
||||||
@@ -68,7 +73,8 @@ pub fn user_interaction_function_declarations() -> Vec<FunctionDeclaration> {
|
|||||||
},
|
},
|
||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
name: format!("{USER_FUNCTION_PREFIX}input"),
|
name: format!("{USER_FUNCTION_PREFIX}input"),
|
||||||
description: "Ask the user for free-form text input. Returns the text entered.".to_string(),
|
description: "Collect free-form text from the user when no predefined options exist. \
|
||||||
|
Returns the text entered.".to_string(),
|
||||||
parameters: JsonSchema {
|
parameters: JsonSchema {
|
||||||
type_value: Some("object".to_string()),
|
type_value: Some("object".to_string()),
|
||||||
properties: Some(IndexMap::from([(
|
properties: Some(IndexMap::from([(
|
||||||
@@ -86,7 +92,9 @@ pub fn user_interaction_function_declarations() -> Vec<FunctionDeclaration> {
|
|||||||
},
|
},
|
||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
name: format!("{USER_FUNCTION_PREFIX}checkbox"),
|
name: format!("{USER_FUNCTION_PREFIX}checkbox"),
|
||||||
description: "Ask the user to select one or more options from a list. Returns an array of selected options.".to_string(),
|
description: "Ask the user to pick one or more options from a list (multi-select). \
|
||||||
|
Use when multiple answers are valid simultaneously. Returns an array \
|
||||||
|
of selected options.".to_string(),
|
||||||
parameters: JsonSchema {
|
parameters: JsonSchema {
|
||||||
type_value: Some("object".to_string()),
|
type_value: Some("object".to_string()),
|
||||||
properties: Some(IndexMap::from([
|
properties: Some(IndexMap::from([
|
||||||
@@ -139,7 +147,7 @@ pub async fn handle_user_tool(
|
|||||||
|
|
||||||
fn handle_direct(action: &str, args: &Value) -> Result<Value> {
|
fn handle_direct(action: &str, args: &Value) -> Result<Value> {
|
||||||
match action {
|
match action {
|
||||||
"ask" => handle_direct_ask(args),
|
"select" => handle_direct_ask(args),
|
||||||
"confirm" => handle_direct_confirm(args),
|
"confirm" => handle_direct_confirm(args),
|
||||||
"input" => handle_direct_input(args),
|
"input" => handle_direct_input(args),
|
||||||
"checkbox" => handle_direct_checkbox(args),
|
"checkbox" => handle_direct_checkbox(args),
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ impl ApprovalNodeExecutor {
|
|||||||
&json!({ "question": question, "options": node.options }),
|
&json!({ "question": question, "options": node.options }),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("user__ask failed")?;
|
.context("user__select failed")?;
|
||||||
|
|
||||||
if let Some(err) = response.get("error").and_then(Value::as_str) {
|
if let Some(err) = response.get("error").and_then(Value::as_str) {
|
||||||
bail!("Approval interaction failed: {err}");
|
bail!("Approval interaction failed: {err}");
|
||||||
|
|||||||
Reference in New Issue
Block a user