Fix Local Agent Execution And Auth Checks
- Gate server requests on available credentials - Run local child agents directly without a parent run ID - Include command IDs in Bedrock context and recognize transfer tools
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
use serde_json::json;
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
use super::sanitize_messages_for_bedrock;
|
||||
use super::{
|
||||
extract_new_input_messages, extract_system_prompt, extract_tools, sanitize_messages_for_bedrock,
|
||||
};
|
||||
use crate::ai::bedrock::convert::{ContentPart, ConversationMessage, MessageContent, MessageRole};
|
||||
|
||||
#[test]
|
||||
@@ -45,3 +48,168 @@ fn test_sanitize_messages_prepends_synthetic_tool_result_before_existing_user_te
|
||||
ContentPart::Text(text) if text == &existing_user_text
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn advertised_tools_follow_client_capabilities_and_include_local_subagents() {
|
||||
let request = api::Request {
|
||||
settings: Some(api::request::Settings {
|
||||
supported_tools: vec![
|
||||
api::ToolType::RunShellCommand.into(),
|
||||
api::ToolType::ReadFiles.into(),
|
||||
api::ToolType::Subagent.into(),
|
||||
],
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let names = extract_tools(&request)
|
||||
.into_iter()
|
||||
.map(|tool| tool.name)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
names,
|
||||
vec!["run_shell_command", "read_files", "start_agent"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plan_mode_prompt_prohibits_mutation() {
|
||||
let request = api::Request {
|
||||
input: Some(api::request::Input {
|
||||
r#type: Some(api::request::input::Type::UserInputs(
|
||||
api::request::input::UserInputs {
|
||||
inputs: vec![api::request::input::user_inputs::UserInput {
|
||||
input: Some(
|
||||
api::request::input::user_inputs::user_input::Input::UserQuery(
|
||||
api::request::input::UserQuery {
|
||||
query: "plan the change".to_string(),
|
||||
mode: Some(api::UserQueryMode {
|
||||
r#type: Some(api::user_query_mode::Type::Plan(())),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
),
|
||||
}],
|
||||
},
|
||||
)),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let prompt = extract_system_prompt(&request, &[]).unwrap();
|
||||
assert!(prompt.contains("## Plan Mode"));
|
||||
assert!(prompt.contains("do not edit files"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn running_command_turn_gets_monitor_prompt_and_cli_tools() {
|
||||
let request = api::Request {
|
||||
input: Some(api::request::Input {
|
||||
r#type: Some(api::request::input::Type::UserInputs(
|
||||
api::request::input::UserInputs {
|
||||
inputs: vec![api::request::input::user_inputs::UserInput {
|
||||
input: Some(
|
||||
api::request::input::user_inputs::user_input::Input::CliAgentUserQuery(
|
||||
api::request::input::CliAgentUserQuery {
|
||||
user_query: Some(api::request::input::UserQuery {
|
||||
query: "monitor this".to_string(),
|
||||
..Default::default()
|
||||
}),
|
||||
running_command: Some(api::RunningShellCommand {
|
||||
command: "cargo test".to_string(),
|
||||
snapshot: Some(api::LongRunningShellCommandSnapshot {
|
||||
command_id: "block-123".to_string(),
|
||||
..Default::default()
|
||||
}),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
),
|
||||
}],
|
||||
},
|
||||
)),
|
||||
..Default::default()
|
||||
}),
|
||||
settings: Some(api::request::Settings {
|
||||
supported_tools: vec![api::ToolType::RunShellCommand.into()],
|
||||
supported_cli_agent_tools: vec![
|
||||
api::ToolType::WriteToLongRunningShellCommand.into(),
|
||||
api::ToolType::ReadShellCommandOutput.into(),
|
||||
api::ToolType::TransferShellCommandControlToUser.into(),
|
||||
],
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let names = extract_tools(&request)
|
||||
.into_iter()
|
||||
.map(|tool| tool.name)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
names,
|
||||
vec![
|
||||
"write_to_long_running_shell_command",
|
||||
"read_shell_command_output",
|
||||
"transfer_shell_command_control_to_user",
|
||||
]
|
||||
);
|
||||
|
||||
let prompt = extract_system_prompt(&request, &[]).unwrap();
|
||||
assert!(prompt.contains("## Running Command Monitor"));
|
||||
assert!(prompt.contains("command ID"));
|
||||
assert!(prompt.contains("read_shell_command_output"));
|
||||
assert!(!prompt.contains("- Use `run_shell_command`"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_running_tool_result_preserves_command_id() {
|
||||
let request = api::Request {
|
||||
input: Some(api::request::Input {
|
||||
r#type: Some(api::request::input::Type::UserInputs(
|
||||
api::request::input::UserInputs {
|
||||
inputs: vec![api::request::input::user_inputs::UserInput {
|
||||
input: Some(
|
||||
api::request::input::user_inputs::user_input::Input::ToolCallResult(
|
||||
api::request::input::ToolCallResult {
|
||||
tool_call_id: "tool-1".to_string(),
|
||||
result: Some(
|
||||
api::request::input::tool_call_result::Result::RunShellCommand(
|
||||
api::RunShellCommandResult {
|
||||
command: "cargo test".to_string(),
|
||||
result: Some(
|
||||
api::run_shell_command_result::Result::LongRunningCommandSnapshot(
|
||||
api::LongRunningShellCommandSnapshot {
|
||||
command_id: "block-456".to_string(),
|
||||
output: "running 42 tests".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
}],
|
||||
},
|
||||
)),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let messages = extract_new_input_messages(&request);
|
||||
let MessageContent::ToolResult { content, .. } = &messages[0].content else {
|
||||
panic!("expected tool result");
|
||||
};
|
||||
assert!(content.contains("Command ID: block-456"));
|
||||
assert!(content.contains("running 42 tests"));
|
||||
assert!(content.contains("read_shell_command_output"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user