mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
Route message board agent resolution through the selected controller (#47633)
## What changed Use `agent_control.resolve` for message board agent lookups and path validation instead of accessing `local_agent_runtime` directly. Derive paths from the session source, with a root fallback, and verify that each path resolves to the agent that owns it. Validate the requested caller's thread for path and clock queries, and apply the same path ownership check to notification recipients. GitOrigin-RevId: 92632a31b493b6519d2154f49e9d1d4a1019b394
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
//! Bridges the board extension to existing tree, clock and active-turn services.
|
||||
//! Bridges the board extension to the selected controller, clock and active-turn services.
|
||||
//!
|
||||
//! The extension owns storage and tools. This adapter never starts or restores
|
||||
//! recipients and never queues a notification for an idle agent.
|
||||
@@ -68,68 +68,76 @@ struct LocalBoardHost {
|
||||
}
|
||||
|
||||
impl LocalBoardHost {
|
||||
async fn actor(&self) -> Result<Arc<CodexThread>> {
|
||||
async fn actor(&self, caller: ThreadId) -> Result<Arc<CodexThread>> {
|
||||
let manager = self
|
||||
.manager
|
||||
.upgrade()
|
||||
.ok_or_else(|| CodexErr::ThreadNotFound(self.caller))?;
|
||||
let actor = manager.get_thread(self.caller).await?;
|
||||
.ok_or_else(|| CodexErr::ThreadNotFound(caller))?;
|
||||
let actor = manager.get_thread(caller).await?;
|
||||
if actor.session.session_id() != self.tree {
|
||||
return Err(CodexErr::InvalidRequest(
|
||||
"agent belongs to another message board".into(),
|
||||
));
|
||||
}
|
||||
// Match existing collaboration resolution: roots are registered lazily.
|
||||
if self.caller == ThreadId::from(self.tree) {
|
||||
actor
|
||||
.session
|
||||
.services
|
||||
.local_agent_runtime
|
||||
.register_session_root(self.caller, /*current_parent_thread_id*/ None);
|
||||
}
|
||||
Ok(actor)
|
||||
}
|
||||
|
||||
async fn registered_path(&self, actor: &CodexThread) -> Result<AgentPath> {
|
||||
let caller = actor.session.thread_id;
|
||||
let path = actor
|
||||
.session_source
|
||||
.get_agent_path()
|
||||
.or_else(|| (caller == ThreadId::from(self.tree)).then(AgentPath::root))
|
||||
.ok_or_else(|| CodexErr::InvalidRequest("agent has no tree path".into()))?;
|
||||
let resolved = actor
|
||||
.session
|
||||
.services
|
||||
.agent_control
|
||||
.resolve(
|
||||
caller,
|
||||
actor.session_source.parent_thread_id(),
|
||||
&actor.session_source,
|
||||
path.as_str(),
|
||||
)
|
||||
.await?;
|
||||
if resolved != caller {
|
||||
return Err(CodexErr::InvalidRequest(
|
||||
"agent does not own its tree path".into(),
|
||||
));
|
||||
}
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageBoardHost for LocalBoardHost {
|
||||
fn agent_path(&self, caller: ThreadId) -> BoxFuture<'_, Result<AgentPath>> {
|
||||
Box::pin(async move {
|
||||
self.actor()
|
||||
.await?
|
||||
.session
|
||||
.services
|
||||
.local_agent_runtime
|
||||
.ensure_agent_known(caller)?
|
||||
.agent_path
|
||||
.ok_or_else(|| CodexErr::InvalidRequest("agent has no tree path".into()))
|
||||
let actor = self.actor(caller).await?;
|
||||
self.registered_path(&actor).await
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_agent(&self, path: AgentPath) -> BoxFuture<'_, Result<ThreadId>> {
|
||||
Box::pin(async move {
|
||||
let actor = self.actor().await?;
|
||||
let actor = self.actor(self.caller).await?;
|
||||
actor
|
||||
.session
|
||||
.services
|
||||
.local_agent_runtime
|
||||
.resolve_agent_reference(self.caller, &actor.session_source, path.as_str())
|
||||
.agent_control
|
||||
.resolve(
|
||||
self.caller,
|
||||
actor.session_source.parent_thread_id(),
|
||||
&actor.session_source,
|
||||
path.as_str(),
|
||||
)
|
||||
.await
|
||||
})
|
||||
}
|
||||
|
||||
fn current_time(&self, caller: ThreadId) -> BoxFuture<'_, Result<DateTime<Utc>>> {
|
||||
Box::pin(async move {
|
||||
self.agent_path(caller).await?;
|
||||
let manager = self
|
||||
.manager
|
||||
.upgrade()
|
||||
.ok_or_else(|| CodexErr::ThreadNotFound(caller))?;
|
||||
let actor = manager.get_thread(caller).await?;
|
||||
if actor.session.session_id() != self.tree {
|
||||
return Err(CodexErr::InvalidRequest(
|
||||
"agent belongs to another message board".into(),
|
||||
));
|
||||
}
|
||||
let actor = self.actor(caller).await?;
|
||||
self.registered_path(&actor).await?;
|
||||
actor
|
||||
.session
|
||||
.services
|
||||
@@ -161,13 +169,7 @@ impl MessageBoardHost for LocalBoardHost {
|
||||
"notification recipient belongs to another board".into(),
|
||||
));
|
||||
}
|
||||
let recipient_path = recipient
|
||||
.session
|
||||
.services
|
||||
.local_agent_runtime
|
||||
.ensure_agent_known(recipient_id)?
|
||||
.agent_path
|
||||
.ok_or_else(|| CodexErr::InvalidRequest("agent has no tree path".into()))?;
|
||||
let recipient_path = self.registered_path(&recipient).await?;
|
||||
let notice = AgentMessageBoardNotification(post);
|
||||
let communication = InterAgentCommunication::new(
|
||||
notice.0.metadata.author.clone(),
|
||||
|
||||
Reference in New Issue
Block a user