e2e testing
This commit is contained in:
@@ -19,11 +19,16 @@ pub async fn generate_multi_agent_output(
|
||||
cancellation_rx: futures::channel::oneshot::Receiver<()>,
|
||||
) -> Result<ResponseStream, ConvertToAPITypeError> {
|
||||
let supported_tools_override = params.supported_tools_override.take();
|
||||
let supported_tools = supported_tools_override
|
||||
let mut supported_tools = supported_tools_override
|
||||
.clone()
|
||||
.unwrap_or_else(|| get_supported_tools(¶ms));
|
||||
let supported_cli_agent_tools =
|
||||
remove_orchestration_tools_if_disabled(&mut supported_tools, params.orchestration_enabled);
|
||||
let mut supported_cli_agent_tools =
|
||||
supported_tools_override.unwrap_or_else(|| get_supported_cli_agent_tools(¶ms));
|
||||
remove_orchestration_tools_if_disabled(
|
||||
&mut supported_cli_agent_tools,
|
||||
params.orchestration_enabled,
|
||||
);
|
||||
if params.should_redact_secrets {
|
||||
redaction::redact_inputs(&mut params.input);
|
||||
}
|
||||
@@ -254,6 +259,21 @@ pub async fn generate_multi_agent_output(
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_orchestration_tools_if_disabled(
|
||||
supported_tools: &mut Vec<api::ToolType>,
|
||||
orchestration_enabled: bool,
|
||||
) {
|
||||
if orchestration_enabled {
|
||||
return;
|
||||
}
|
||||
supported_tools.retain(|tool| {
|
||||
!matches!(
|
||||
tool,
|
||||
api::ToolType::Subagent | api::ToolType::RunAgents | api::ToolType::StartAgentV2
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn get_supported_tools(params: &RequestParams) -> Vec<api::ToolType> {
|
||||
let mut supported_tools = vec![
|
||||
api::ToolType::Grep,
|
||||
@@ -262,7 +282,6 @@ fn get_supported_tools(params: &RequestParams) -> Vec<api::ToolType> {
|
||||
api::ToolType::ReadMcpResource,
|
||||
api::ToolType::CallMcpTool,
|
||||
api::ToolType::RunShellCommand,
|
||||
api::ToolType::Subagent,
|
||||
api::ToolType::WriteToLongRunningShellCommand,
|
||||
api::ToolType::ReadShellCommandOutput,
|
||||
api::ToolType::ReadDocuments,
|
||||
@@ -270,6 +289,10 @@ fn get_supported_tools(params: &RequestParams) -> Vec<api::ToolType> {
|
||||
api::ToolType::EditDocuments,
|
||||
];
|
||||
|
||||
if params.orchestration_enabled {
|
||||
supported_tools.push(api::ToolType::Subagent);
|
||||
}
|
||||
|
||||
if FeatureFlag::ConversationsAsContext.is_enabled() {
|
||||
supported_tools.push(api::ToolType::FetchConversation);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::HostId;
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
use super::{get_supported_cli_agent_tools, get_supported_tools};
|
||||
use super::{
|
||||
get_supported_cli_agent_tools, get_supported_tools, remove_orchestration_tools_if_disabled,
|
||||
};
|
||||
use crate::ai::agent::api::RequestParams;
|
||||
use crate::ai::blocklist::SessionContext;
|
||||
use crate::ai::llms::LLMId;
|
||||
@@ -77,6 +79,40 @@ fn supported_tools_expose_local_subagents_without_hosted_orchestration_tools() {
|
||||
assert!(!supported_tools.contains(&api::ToolType::StartAgentV2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supported_tools_omit_subagents_when_orchestration_is_disabled() {
|
||||
let params = request_params_with_ask_user_question_enabled(false);
|
||||
let supported_tools = get_supported_tools(¶ms);
|
||||
|
||||
assert!(!supported_tools.contains(&api::ToolType::Subagent));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supported_tool_override_cannot_restore_leaf_orchestration_tools() {
|
||||
let mut supported_tools = vec![
|
||||
api::ToolType::Grep,
|
||||
api::ToolType::Subagent,
|
||||
api::ToolType::RunAgents,
|
||||
api::ToolType::StartAgentV2,
|
||||
];
|
||||
|
||||
remove_orchestration_tools_if_disabled(&mut supported_tools, false);
|
||||
|
||||
assert_eq!(supported_tools, vec![api::ToolType::Grep]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enabled_orchestration_preserves_supported_tool_override() {
|
||||
let mut supported_tools = vec![api::ToolType::Grep, api::ToolType::Subagent];
|
||||
|
||||
remove_orchestration_tools_if_disabled(&mut supported_tools, true);
|
||||
|
||||
assert_eq!(
|
||||
supported_tools,
|
||||
vec![api::ToolType::Grep, api::ToolType::Subagent]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supported_tools_omit_hosted_only_capabilities() {
|
||||
let params = request_params_with_ask_user_question_enabled(false);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
@@ -360,6 +360,59 @@ impl TaskStore {
|
||||
append_refs_for_task(tasks, &mut refs, root_task);
|
||||
}
|
||||
|
||||
let indexed_task_ids = refs
|
||||
.iter()
|
||||
.map(|exchange_ref| exchange_ref.task_id.clone())
|
||||
.collect::<HashSet<_>>();
|
||||
let mut direct_cli_tasks = tasks
|
||||
.values()
|
||||
.filter(|task| {
|
||||
!indexed_task_ids.contains(task.id())
|
||||
&& task.parent_id().as_ref() == Some(root_task_id)
|
||||
&& task.is_cli_subagent()
|
||||
&& task
|
||||
.subagent_params()
|
||||
.is_some_and(|params| params.tool_call_id.is_empty())
|
||||
&& task.exchanges().next().is_some()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
direct_cli_tasks.sort_by(|left, right| {
|
||||
left.exchanges()
|
||||
.next()
|
||||
.map(|exchange| exchange.start_time)
|
||||
.cmp(&right.exchanges().next().map(|exchange| exchange.start_time))
|
||||
.then_with(|| left.id().to_string().cmp(&right.id().to_string()))
|
||||
});
|
||||
|
||||
// Direct providers synthesize CLI monitor tasks without a parent Subagent message.
|
||||
// Place each task as one chronological block so its exchanges remain reachable without
|
||||
// changing the DFS order of server-linked subtasks.
|
||||
for task in direct_cli_tasks {
|
||||
let first_start_time = task
|
||||
.exchanges()
|
||||
.next()
|
||||
.expect("direct CLI task was filtered to contain an exchange")
|
||||
.start_time;
|
||||
let insertion_index = refs
|
||||
.iter()
|
||||
.position(|exchange_ref| {
|
||||
tasks
|
||||
.get(&exchange_ref.task_id)
|
||||
.and_then(|task| task.exchanges().nth(exchange_ref.exchange_index))
|
||||
.is_some_and(|exchange| exchange.start_time > first_start_time)
|
||||
})
|
||||
.unwrap_or(refs.len());
|
||||
let task_id = task.id().clone();
|
||||
let task_refs = task
|
||||
.exchanges()
|
||||
.enumerate()
|
||||
.map(|(exchange_index, _)| ExchangeRef {
|
||||
task_id: task_id.clone(),
|
||||
exchange_index,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
refs.splice(insertion_index..insertion_index, task_refs);
|
||||
}
|
||||
refs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,46 @@ fn test_insert_subtask() {
|
||||
assert!(store.contains(&subtask_id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unlinked_direct_cli_task_is_linearized_chronologically() {
|
||||
let base_time = Local::now();
|
||||
let mut root_task = Task::new_optimistic_root();
|
||||
let root_task_id = root_task.id().clone();
|
||||
|
||||
let mut before_cli = create_test_exchange();
|
||||
before_cli.start_time = base_time;
|
||||
let before_cli_id = before_cli.id;
|
||||
root_task.append_exchange(before_cli);
|
||||
|
||||
let mut after_cli = create_test_exchange();
|
||||
after_cli.start_time = base_time + chrono::Duration::seconds(2);
|
||||
let after_cli_id = after_cli.id;
|
||||
root_task.append_exchange(after_cli);
|
||||
|
||||
let mut cli_task =
|
||||
Task::new_optimistic_cli_agent_subtask(BlockId::new(), Some(root_task_id.to_string()));
|
||||
let mut cli_exchange = create_test_exchange();
|
||||
cli_exchange.start_time = base_time + chrono::Duration::seconds(1);
|
||||
let cli_exchange_id = cli_exchange.id;
|
||||
cli_task.append_exchange(cli_exchange);
|
||||
|
||||
let mut store = TaskStore::with_root_task(root_task);
|
||||
store.insert(cli_task);
|
||||
|
||||
let exchange_ids = store
|
||||
.all_exchanges()
|
||||
.map(|exchange| exchange.id)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
exchange_ids,
|
||||
vec![before_cli_id, cli_exchange_id, after_cli_id]
|
||||
);
|
||||
assert_eq!(
|
||||
store.latest_exchange().map(|exchange| exchange.id),
|
||||
Some(after_cli_id)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_task() {
|
||||
let task = create_test_task_with_exchanges(3);
|
||||
|
||||
Reference in New Issue
Block a user