e2e testing
This commit is contained in:
@@ -283,6 +283,25 @@ fn bedrock_rig_turn_uses_bedrock_history_invariants_without_a_proto_round_trip()
|
||||
assert_eq!(prepared.request.messages, prepared.persistent_messages);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modern_and_legacy_orchestration_tools_follow_subagent_capabilities() {
|
||||
for capability in [ToolType::Subagent, ToolType::StartAgentV2] {
|
||||
let (tools, _) = tool_definitions(&[capability], None);
|
||||
let names = tools
|
||||
.iter()
|
||||
.map(|tool| tool.name.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert!(names.contains(&"run_agents"));
|
||||
assert!(names.contains(&"start_agent"));
|
||||
}
|
||||
|
||||
let (leaf_tools, _) = tool_definitions(&[ToolType::Grep], None);
|
||||
assert!(!leaf_tools
|
||||
.iter()
|
||||
.any(|tool| matches!(tool.name.as_str(), "run_agents" | "start_agent")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn grouped_mcp_tool_names_use_the_installation_id_not_the_display_name() {
|
||||
|
||||
@@ -12,8 +12,9 @@ use crate::ai::agent::{
|
||||
AIAgentAction, AIAgentActionType, AIAgentPtyWriteMode, AskUserQuestionItem,
|
||||
AskUserQuestionOption, AskUserQuestionType, CreateDocumentsRequest, DocumentDiff,
|
||||
DocumentToCreate, EditDocumentsRequest, FileEdit, FileLocations, ReadDocumentsRequest,
|
||||
ReadFilesRequest, ReadSkillRequest, SearchCodebaseRequest, ShellCommandDelay,
|
||||
StartAgentExecutionMode, StartAgentVersion,
|
||||
ReadFilesRequest, ReadSkillRequest, RunAgentsAgentRunConfig, RunAgentsExecutionMode,
|
||||
RunAgentsRequest, SearchCodebaseRequest, ShellCommandDelay, StartAgentExecutionMode,
|
||||
StartAgentVersion,
|
||||
};
|
||||
use crate::ai::document::ai_document_model::AIDocumentId;
|
||||
|
||||
@@ -140,6 +141,27 @@ pub(super) fn action_from_tool_call(
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
"run_agents" => AIAgentActionType::RunAgents(RunAgentsRequest {
|
||||
summary: string(input, "summary"),
|
||||
base_prompt: string(input, "base_prompt"),
|
||||
skills: skill_references(input, skill_path_origin),
|
||||
model_id: string(input, "model_id"),
|
||||
harness_type: string(input, "harness_type"),
|
||||
execution_mode: run_agents_execution_mode(input),
|
||||
agent_run_configs: input
|
||||
.get("agent_run_configs")
|
||||
.and_then(serde_json::Value::as_array)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.map(|config| RunAgentsAgentRunConfig {
|
||||
name: string(config, "name"),
|
||||
prompt: string(config, "prompt"),
|
||||
title: string(config, "title"),
|
||||
})
|
||||
.collect(),
|
||||
plan_id: string(input, "plan_id"),
|
||||
harness_auth_secret_name: None,
|
||||
}),
|
||||
"start_agent" => AIAgentActionType::StartAgent {
|
||||
version: StartAgentVersion::V1,
|
||||
name: string(input, "name"),
|
||||
@@ -263,6 +285,52 @@ fn uuid(input: &serde_json::Value, key: &str) -> Option<Uuid> {
|
||||
.and_then(|value| Uuid::parse_str(value).ok())
|
||||
}
|
||||
|
||||
fn skill_references(
|
||||
input: &serde_json::Value,
|
||||
skill_path_origin: &SkillPathOrigin,
|
||||
) -> Vec<SkillReference> {
|
||||
input
|
||||
.get("skills")
|
||||
.and_then(serde_json::Value::as_array)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|skill| {
|
||||
let reference = string(skill, "skill");
|
||||
if reference.is_empty() {
|
||||
return None;
|
||||
}
|
||||
match skill
|
||||
.get("reference_type")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
{
|
||||
Some("bundled") => Some(SkillReference::BundledSkillId(reference)),
|
||||
Some("path") | Some(_) | None => skill_path_origin
|
||||
.location_for_path(reference)
|
||||
.ok()
|
||||
.map(SkillReference::Path),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn run_agents_execution_mode(input: &serde_json::Value) -> RunAgentsExecutionMode {
|
||||
let Some(execution_mode) = input.get("execution_mode") else {
|
||||
return RunAgentsExecutionMode::Local;
|
||||
};
|
||||
let mode_type = execution_mode
|
||||
.get("type")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.or_else(|| execution_mode.as_str());
|
||||
match mode_type {
|
||||
Some("remote") => RunAgentsExecutionMode::Remote {
|
||||
environment_id: string(execution_mode, "environment_id"),
|
||||
worker_host: string(execution_mode, "worker_host"),
|
||||
computer_use_enabled: boolean(execution_mode, "computer_use_enabled"),
|
||||
},
|
||||
Some("local") | Some(_) | None => RunAgentsExecutionMode::Local,
|
||||
}
|
||||
}
|
||||
|
||||
fn file_location(file: &serde_json::Value) -> Option<FileLocations> {
|
||||
if let Some(name) = file.as_str() {
|
||||
return Some(FileLocations {
|
||||
|
||||
@@ -6,7 +6,7 @@ use ai::skills::{SkillPathOrigin, SkillReference};
|
||||
use galaxy_agent_core::ToolCall;
|
||||
|
||||
use super::{action_from_tool_call, MCPToolTarget};
|
||||
use crate::ai::agent::{AIAgentActionType, FileEdit};
|
||||
use crate::ai::agent::{AIAgentActionType, FileEdit, RunAgentsExecutionMode};
|
||||
|
||||
fn call(name: &str, arguments: serde_json::Value) -> ToolCall {
|
||||
ToolCall {
|
||||
@@ -164,6 +164,110 @@ fn local_skill_paths_preserve_the_session_origin() {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_agents_calls_decode_to_local_domain_requests_with_safe_defaults() {
|
||||
let action = action_from_tool_call(
|
||||
"task-1",
|
||||
&call(
|
||||
"run_agents",
|
||||
serde_json::json!({
|
||||
"summary": "Parallel investigation",
|
||||
"base_prompt": "Inspect before changing files.",
|
||||
"agent_run_configs": [
|
||||
{
|
||||
"name": "runtime",
|
||||
"prompt": "Inspect runtime behavior",
|
||||
"title": "Runtime investigator"
|
||||
},
|
||||
{
|
||||
"name": "tests",
|
||||
"prompt": "Design focused tests"
|
||||
}
|
||||
]
|
||||
}),
|
||||
),
|
||||
&SkillPathOrigin::Local,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let AIAgentActionType::RunAgents(request) = action.action else {
|
||||
panic!("expected run-agents action");
|
||||
};
|
||||
assert_eq!(request.summary, "Parallel investigation");
|
||||
assert_eq!(request.base_prompt, "Inspect before changing files.");
|
||||
assert!(request.skills.is_empty());
|
||||
assert!(request.model_id.is_empty());
|
||||
assert!(request.harness_type.is_empty());
|
||||
assert_eq!(request.execution_mode, RunAgentsExecutionMode::Local);
|
||||
assert!(request.plan_id.is_empty());
|
||||
assert!(request.harness_auth_secret_name.is_none());
|
||||
assert_eq!(request.agent_run_configs.len(), 2);
|
||||
assert_eq!(request.agent_run_configs[0].name, "runtime");
|
||||
assert_eq!(
|
||||
request.agent_run_configs[0].prompt,
|
||||
"Inspect runtime behavior"
|
||||
);
|
||||
assert_eq!(request.agent_run_configs[0].title, "Runtime investigator");
|
||||
assert_eq!(request.agent_run_configs[1].name, "tests");
|
||||
assert_eq!(request.agent_run_configs[1].prompt, "Design focused tests");
|
||||
assert!(request.agent_run_configs[1].title.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_agents_calls_preserve_remote_config_and_skills() {
|
||||
let action = action_from_tool_call(
|
||||
"task-1",
|
||||
&call(
|
||||
"run_agents",
|
||||
serde_json::json!({
|
||||
"summary": "Remote investigation",
|
||||
"model_id": "remote-model",
|
||||
"harness_type": "codex",
|
||||
"execution_mode": {
|
||||
"type": "remote",
|
||||
"environment_id": "env-1",
|
||||
"worker_host": "worker.example",
|
||||
"computer_use_enabled": true
|
||||
},
|
||||
"skills": [
|
||||
{"skill": "galaxyctrl", "reference_type": "bundled"},
|
||||
{"skill": "/repo/SKILL.md", "reference_type": "path"}
|
||||
],
|
||||
"agent_run_configs": [{"name": "remote", "prompt": "Inspect"}],
|
||||
"plan_id": "plan-1"
|
||||
}),
|
||||
),
|
||||
&SkillPathOrigin::Local,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let AIAgentActionType::RunAgents(request) = action.action else {
|
||||
panic!("expected run-agents action");
|
||||
};
|
||||
assert_eq!(request.model_id, "remote-model");
|
||||
assert_eq!(request.harness_type, "codex");
|
||||
assert_eq!(request.plan_id, "plan-1");
|
||||
assert_eq!(
|
||||
request.skills,
|
||||
vec![
|
||||
SkillReference::BundledSkillId("galaxyctrl".to_string()),
|
||||
SkillReference::Path(galaxy_util::local_or_remote_path::LocalOrRemotePath::Local(
|
||||
PathBuf::from("/repo/SKILL.md")
|
||||
)),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
request.execution_mode,
|
||||
RunAgentsExecutionMode::Remote {
|
||||
environment_id: "env-1".to_string(),
|
||||
worker_host: "worker.example".to_string(),
|
||||
computer_use_enabled: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_tools_are_rejected_before_the_permission_boundary() {
|
||||
let error = action_from_tool_call(
|
||||
|
||||
Reference in New Issue
Block a user