mirror of
https://github.com/openai/codex.git
synced 2026-10-23 18:08:45 +00:00
Include attributed previews in agent message board notifications (#47075)
## Why Message board notifications exposed only post and thread IDs, requiring a read to see any post content. ## What changed Deliver notifications as `agent_message` items with author and recipient attribution. Include a `CHANNEL_POST` payload with the sender, channel, message and thread IDs, and up to 150 characters of post text. Direct agents to `read_post` when the preview is truncated, and retain recognition of legacy user-role notices. ## Testing Update the model-context scenario to assert the notification's author, recipient, and preview payload, and update the idle-agent scenario to check for the new notification format. GitOrigin-RevId: e0e2794be82e38bba47f41fb4fc8128eb5e47619
This commit is contained in:
@@ -15,7 +15,7 @@ use codex_agent_message_board_extension::AgentMessageBoard;
|
||||
use codex_agent_message_board_extension::LocalAgentMessageBoard;
|
||||
use codex_agent_message_board_extension::MessageBoardHost;
|
||||
use codex_agent_message_board_extension::NotificationDelivery;
|
||||
use codex_agent_message_board_extension::PostMetadata;
|
||||
use codex_agent_message_board_extension::PostPreview;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::AgentPath;
|
||||
@@ -24,6 +24,7 @@ use codex_protocol::ThreadId;
|
||||
use codex_protocol::error::CodexErr;
|
||||
use codex_protocol::error::CodexErrorDetails;
|
||||
use codex_protocol::error::Result;
|
||||
use codex_protocol::protocol::InterAgentCommunication;
|
||||
use futures::future::BoxFuture;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Weak;
|
||||
@@ -141,14 +142,14 @@ impl MessageBoardHost for LocalBoardHost {
|
||||
|
||||
fn notify(
|
||||
&self,
|
||||
recipient: ThreadId,
|
||||
post: PostMetadata,
|
||||
recipient_id: ThreadId,
|
||||
post: PostPreview,
|
||||
) -> BoxFuture<'_, Result<NotificationDelivery>> {
|
||||
Box::pin(async move {
|
||||
let Some(manager) = self.manager.upgrade() else {
|
||||
return Ok(NotificationDelivery::SkippedInactive);
|
||||
};
|
||||
let recipient = match manager.get_thread(recipient).await {
|
||||
let recipient = match manager.get_thread(recipient_id).await {
|
||||
Ok(thread) => thread,
|
||||
Err(error) if matches!(error.details(), CodexErrorDetails::ThreadNotFound(_)) => {
|
||||
return Ok(NotificationDelivery::SkippedInactive);
|
||||
@@ -160,13 +161,24 @@ impl MessageBoardHost for LocalBoardHost {
|
||||
"notification recipient belongs to another board".into(),
|
||||
));
|
||||
}
|
||||
let notice = AgentMessageBoardNotification {
|
||||
message_id: post.message_id,
|
||||
thread_id: post.thread_id,
|
||||
};
|
||||
let recipient_path = recipient
|
||||
.session
|
||||
.services
|
||||
.agent_control
|
||||
.ensure_agent_known(recipient_id)?
|
||||
.agent_path
|
||||
.ok_or_else(|| CodexErr::InvalidRequest("agent has no tree path".into()))?;
|
||||
let notice = AgentMessageBoardNotification(post);
|
||||
let communication = InterAgentCommunication::new(
|
||||
notice.0.metadata.author.clone(),
|
||||
recipient_path,
|
||||
Vec::new(),
|
||||
notice.render(),
|
||||
/*trigger_turn*/ false,
|
||||
);
|
||||
Ok(
|
||||
match recipient
|
||||
.inject_if_running(vec![ContextualUserFragment::into(notice)])
|
||||
.inject_if_running(vec![communication.to_model_input_item()])
|
||||
.await
|
||||
{
|
||||
Ok(()) => NotificationDelivery::Accepted,
|
||||
|
||||
@@ -1,34 +1,42 @@
|
||||
//! Fixed-size discussion notices. Post text is fetched through bounded tools.
|
||||
//! Attributed discussion notices with bounded previews.
|
||||
|
||||
use super::ContextualUserFragment;
|
||||
use codex_agent_message_board_extension::PostPreview;
|
||||
use codex_protocol::models::ContentItemKind;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) struct AgentMessageBoardNotification {
|
||||
pub(crate) message_id: Uuid,
|
||||
pub(crate) thread_id: Uuid,
|
||||
}
|
||||
pub(crate) struct AgentMessageBoardNotification(pub(crate) PostPreview);
|
||||
|
||||
impl ContextualUserFragment for AgentMessageBoardNotification {
|
||||
fn role(&self) -> &'static str {
|
||||
"user"
|
||||
"assistant"
|
||||
}
|
||||
fn content_kind(&self) -> ContentItemKind {
|
||||
ContentItemKind("agent_message_board.notification".into())
|
||||
}
|
||||
fn markers(&self) -> (&'static str, &'static str) {
|
||||
Self::type_markers()
|
||||
("", "")
|
||||
}
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
// Keep recognizing user-role notices in rollouts written before this format.
|
||||
(
|
||||
"<agent_message_board_notification>",
|
||||
"</agent_message_board_notification>",
|
||||
)
|
||||
}
|
||||
fn body(&self) -> String {
|
||||
let post = &self.0;
|
||||
let suffix = if post.truncated {
|
||||
"\n[Use read_post for the rest.]"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
format!(
|
||||
"\nNew post {} in discussion {}. Use read_post or read_thread to read it.\n",
|
||||
self.message_id, self.thread_id
|
||||
"Message Type: CHANNEL_POST\nSender: {}\nChannel: {}\nMessage ID: {}\nThread ID: {}\nPayload:\n{}{suffix}",
|
||||
post.metadata.author,
|
||||
post.metadata.channel_name,
|
||||
post.metadata.message_id,
|
||||
post.metadata.thread_id,
|
||||
post.text_preview,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user