e2e testing

This commit is contained in:
2026-08-10 07:22:56 -05:00
parent fa43f723a5
commit 88ad290c7e
29 changed files with 1695 additions and 99 deletions
+19
View File
@@ -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() {
+70 -2
View File
@@ -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 {
+105 -1
View File
@@ -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(