mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
Align message-board tools with the multi-agent namespace (#47028)
## Why Message-board tools hardcoded the `collaboration` namespace and used a different namespace description from the multi-agent tools. This ignored custom namespace configuration and caused conflicts under strict tool collision checking. ## What changed - Use `multi_agent_v2.tool_namespace` and the shared multi-agent namespace description for message-board tools, resolving the namespace at runtime startup. - Support unnamespaced tool specifications when no namespace is supplied. - Remove hardcoded `collaboration` prefixes from message-board notifications. ## Testing Add app-server integration coverage for the default `collaboration` namespace and a configured `agents` namespace with strict collision checking enabled. Verify that both tool families are advertised together and that `get_channels` executes through the installed extension. GitOrigin-RevId: fef7be51ea2a84bbdb6d3491606db442ed4e6ea3
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
//! Board tools share MAv2 namespace metadata through the production installation path.
|
||||
|
||||
use anyhow::Context;
|
||||
use app_test_support::MockResponsesConfig;
|
||||
use app_test_support::TestAppServer;
|
||||
use codex_app_server_protocol::ThreadStartParams;
|
||||
use codex_app_server_protocol::TurnStartParams;
|
||||
use codex_app_server_protocol::TurnStartResponse;
|
||||
use codex_app_server_protocol::UserInput;
|
||||
use codex_features::Feature;
|
||||
use core_test_support::responses;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::Value;
|
||||
use serde_json::json;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
|
||||
#[test_case::test_case(None, "collaboration"; "default_namespace")]
|
||||
#[test_case::test_case(Some("agents"), "agents"; "configured_namespace")]
|
||||
#[tokio::test]
|
||||
async fn board_tools_share_multi_agent_namespace(
|
||||
configured_namespace: Option<&str>,
|
||||
namespace: &str,
|
||||
) -> anyhow::Result<()> {
|
||||
let server = responses::start_mock_server().await;
|
||||
let mock = responses::mount_sse_sequence(
|
||||
&server,
|
||||
vec![
|
||||
responses::sse(vec![
|
||||
responses::ev_function_call_with_namespace(
|
||||
"list-channels",
|
||||
namespace,
|
||||
"get_channels",
|
||||
"{}",
|
||||
),
|
||||
responses::ev_completed("response-1"),
|
||||
]),
|
||||
responses::sse(vec![
|
||||
responses::ev_assistant_message("done", "Done."),
|
||||
responses::ev_completed("response-2"),
|
||||
]),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
let codex_home = TempDir::new()?;
|
||||
let namespace_config = configured_namespace
|
||||
.map(|name| format!("tool_namespace = {name:?}"))
|
||||
.unwrap_or_default();
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::AgentMessageBoard)
|
||||
.disable_feature(Feature::CodeMode)
|
||||
.disable_feature(Feature::CodeModeOnly)
|
||||
.with_extra_config(&format!(
|
||||
"[features.multi_agent_v2]\nenabled = true\n{namespace_config}\n\
|
||||
[features.tool_registry]\nerror_on_tool_collisions = true"
|
||||
))
|
||||
.write(codex_home.path())?;
|
||||
let mut app = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
.build_initialized()
|
||||
.await?;
|
||||
let thread = app.start_thread(ThreadStartParams::default()).await?.thread;
|
||||
let request = app
|
||||
.send_turn_start_request(TurnStartParams {
|
||||
thread_id: thread.id,
|
||||
input: vec![UserInput::Text {
|
||||
text: "List the shared board channels.".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
let _: TurnStartResponse = app.read_response(request).await?;
|
||||
timeout(
|
||||
Duration::from_secs(60),
|
||||
app.read_stream_until_notification_message("turn/completed"),
|
||||
)
|
||||
.await??;
|
||||
|
||||
let requests = mock.requests();
|
||||
assert_eq!(requests.len(), 2);
|
||||
// Strict collision checking rejects different descriptions before sampling.
|
||||
// Both tool families must also be advertised under the configured name.
|
||||
for name in ["spawn_agent", "get_channels", "post"] {
|
||||
assert!(requests[0].tool_by_name(namespace, name).is_some());
|
||||
}
|
||||
let result: Value = serde_json::from_str(
|
||||
&requests[1]
|
||||
.function_call_output_text("list-channels")
|
||||
.context("board tool must execute through the installed extension")?,
|
||||
)?;
|
||||
assert_eq!(
|
||||
result,
|
||||
json!({"results": [], "n_returned": 0, "has_more": false, "next_cursor": null})
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -2,6 +2,7 @@ mod account;
|
||||
#[path = "account_system_proxy_tests.rs"]
|
||||
mod account_system_proxy;
|
||||
mod account_thread_usage;
|
||||
mod agent_message_board;
|
||||
mod analytics;
|
||||
mod app_installed;
|
||||
mod app_list;
|
||||
|
||||
Reference in New Issue
Block a user