mod cli_test_util;
use objectiveai_sdk::cli::command::functions::execute::standard::{
Request, RequestDangerousAdvanced, RequestInput, ResponseItem,
};
use objectiveai_sdk::cli::command::functions::execute::{
FunctionSpec, ProfileSpec,
};
use objectiveai_sdk::functions::FullInlineFunctionOrRemoteCommitOptional;
use objectiveai_sdk::functions::InlineProfileOrRemoteCommitOptional;
use serde_json::json;
fn mock_agent(foo_value: &str) -> serde_json::Value {
json!({
"upstream": "mock",
"output_mode": "instruction",
"client_objectiveai_mcp": {
"plugins": [{
"owner": "testorg",
"name": "test-mcp-plugin-foo-headers",
"version": "1.0.0",
"executable": false,
"mcp_servers": [{
"name": "demo",
"arguments": { "foo": foo_value }
}]
}]
},
"calls": [
{
"tool_calls": [
{ "name": "test-foo-plugin_invoke", "arguments": "{}" }
],
"content": ""
},
{
"tool_calls": [],
"content": format!("done-{foo_value}")
}
]
})
}
#[tokio::test(flavor = "multi_thread")]
async fn function_swarm_writes_per_agent_files() {
if cli_test_util::test_api_address().is_none() {
eprintln!(
"skipping function_swarm_writes_per_agent_files: OBJECTIVEAI_TEST_PORT not set"
);
return;
}
let base = cli_test_util::test_base_dir();
let function_json = json!({
"type": "vector.function",
"tasks": [{
"type": "vector.completion",
"messages": [{ "role": "user", "content": "pick one" }],
"responses": ["alpha", "beta"],
"output": { "$special": "output" }
}]
});
let profile_json = json!({
"agents": [mock_agent("A"), mock_agent("B")],
"weights": [1.0, 1.0]
});
let function = FunctionSpec::Resolved(
serde_json::from_value::<FullInlineFunctionOrRemoteCommitOptional>(function_json)
.expect("function JSON must deserialize"),
);
let profile = ProfileSpec::Resolved(
serde_json::from_value::<InlineProfileOrRemoteCommitOptional>(profile_json)
.expect("profile JSON must deserialize"),
);
let request = Request { path_type: objectiveai_sdk::cli::command::functions::execute::standard::Path::FunctionsExecuteStandard,
function,
profile,
input: RequestInput::Inline(
serde_json::from_value(json!({})).expect("empty input deserializes"),
),
continuation: None,
retry_token: None,
split: false,
invert: false,
dangerous_advanced: Some(RequestDangerousAdvanced {
stream: Some(true),
seed: Some(42),
}),
jq: None,
};
let executor = cli_test_util::executor_with_base_dir(&base);
let items: Vec<ResponseItem> = cli_test_util::collect_stream(&executor, request).await;
assert!(
!items.is_empty(),
"function executor must emit at least one chunk"
);
let a_path = base.join("A.txt");
let b_path = base.join("B.txt");
let a = std::fs::read_to_string(&a_path)
.unwrap_or_else(|e| panic!("missing {}: {e}", a_path.display()));
let b = std::fs::read_to_string(&b_path)
.unwrap_or_else(|e| panic!("missing {}: {e}", b_path.display()));
assert_eq!(a, "A - A\n");
assert_eq!(b, "B - B\nB - B\n");
}