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:
jif
2026-09-21 13:27:39 +00:00
committed by copyberry
parent 23a6b705ba
commit 8a62cc4dc1
11 changed files with 194 additions and 43 deletions
+25 -19
View File
@@ -8,6 +8,7 @@ use crate::ThreadManager;
use crate::config::Config;
use crate::context::AgentMessageBoardNotification;
use crate::context::ContextualUserFragment;
use crate::tools::MULTI_AGENT_V2_NAMESPACE_DESCRIPTION;
use chrono::DateTime;
use chrono::Utc;
use codex_agent_message_board_extension::AgentMessageBoard;
@@ -33,25 +34,30 @@ pub fn install_agent_message_board(
registry: &mut ExtensionRegistryBuilder<Config>,
manager: Weak<ThreadManager>,
) {
codex_agent_message_board_extension::install(registry, move |config: &Config, tree, caller| {
// MAv2 supplies tree paths; ephemeral runtimes must not open durable storage.
if !config.features.enabled(Feature::AgentMessageBoard)
|| !config.features.enabled(Feature::MultiAgentV2)
|| config.ephemeral
{
return Box::pin(async { Ok(None) });
}
let sqlite = config.sqlite_config().clone();
let host = Arc::new(LocalBoardHost {
manager: manager.clone(),
tree,
caller,
});
Box::pin(async move {
let board = LocalAgentMessageBoard::open(&sqlite, tree, host).await?;
Ok(Some(Arc::new(board) as Arc<dyn AgentMessageBoard>))
})
});
codex_agent_message_board_extension::install(
registry,
MULTI_AGENT_V2_NAMESPACE_DESCRIPTION,
|config: &Config| config.multi_agent_v2.tool_namespace.clone(),
move |config: &Config, tree, caller| {
// MAv2 supplies tree paths; ephemeral runtimes must not open durable storage.
if !config.features.enabled(Feature::AgentMessageBoard)
|| !config.features.enabled(Feature::MultiAgentV2)
|| config.ephemeral
{
return Box::pin(async { Ok(None) });
}
let sqlite = config.sqlite_config().clone();
let host = Arc::new(LocalBoardHost {
manager: manager.clone(),
tree,
caller,
});
Box::pin(async move {
let board = LocalAgentMessageBoard::open(&sqlite, tree, host).await?;
Ok(Some(Arc::new(board) as Arc<dyn AgentMessageBoard>))
})
},
);
}
struct LocalBoardHost {
@@ -27,7 +27,7 @@ impl ContextualUserFragment for AgentMessageBoardNotification {
}
fn body(&self) -> String {
format!(
"\nNew post {} in discussion {}. Use collaboration.read_post or collaboration.read_thread to read it.\n",
"\nNew post {} in discussion {}. Use read_post or read_thread to read it.\n",
self.message_id, self.thread_id
)
}
+1
View File
@@ -34,6 +34,7 @@ use codex_utils_output_truncation::TruncationPolicy;
use codex_utils_output_truncation::formatted_truncate_text;
use codex_utils_output_truncation::truncate_text;
pub(crate) use executed_tool_calls::ExecutedToolCalls;
pub(crate) use multi_agent_tool::MULTI_AGENT_V2_NAMESPACE_DESCRIPTION;
pub use router::ToolRouter;
/// Legacy boundaries such as hook payloads, telemetry tags, and Responses tool
+2 -1
View File
@@ -16,7 +16,8 @@ use futures::future::BoxFuture;
use serde_json::Value;
use std::sync::Arc;
const MULTI_AGENT_V2_NAMESPACE_DESCRIPTION: &str = "Tools for spawning and managing sub-agents.";
pub(crate) const MULTI_AGENT_V2_NAMESPACE_DESCRIPTION: &str =
"Tools for spawning and managing sub-agents.";
pub(super) fn multi_agent_v2_handler(
handler: impl CoreToolRuntime + 'static,