mirror of
https://github.com/openai/codex.git
synced 2026-11-06 20:20:34 +00:00
Decouple message lifecycle state from model-visible item IDs (#59785)
## Why A message's model-visible item ID may be unknown until the recipient records it. Message lifecycle observers need to capture publication state before that point. ## What changed Remove `message_id` from `MessageLifecycleInput` and give each publication's `ExtensionData` a fresh UUID key. Stop assigning an item ID when publishing messages for lifecycle observers. ## Testing Update the agent mailbox test to store a contributor-specific token in `ExtensionData` at publication and retrieve it at consumption, verifying that publication state survives queued delivery and recipient eviction. GitOrigin-RevId: e254f94994d0976e61cb46ee23297f3248b9a389
This commit is contained in:
committed by
copyberry
parent
d63a342256
commit
5e5bdee745
@@ -260,20 +260,13 @@ impl LocalAgentControl {
|
||||
&self,
|
||||
agent_id: ThreadId,
|
||||
state: &Arc<ThreadManagerState>,
|
||||
mut communication: InterAgentCommunication,
|
||||
communication: InterAgentCommunication,
|
||||
context: AgentCommunicationContext,
|
||||
start_options: TurnStartOptions,
|
||||
) -> CodexResult<String> {
|
||||
let observers = state.extensions.message_lifecycle_contributors();
|
||||
let delivery = (!observers.is_empty()).then(|| {
|
||||
let message_id = communication
|
||||
.id
|
||||
.take()
|
||||
.filter(|id| !id.is_empty())
|
||||
.unwrap_or_else(|| (self.runtime.item_id_generator)("amsg"));
|
||||
communication.id = Some(message_id.clone());
|
||||
MessageDelivery::publish(context.sender_thread_id, message_id, observers)
|
||||
});
|
||||
let delivery = (!observers.is_empty())
|
||||
.then(|| MessageDelivery::publish(context.sender_thread_id, observers));
|
||||
let log_content = crate::agent_communication::send_log_content(&communication);
|
||||
{
|
||||
// Keep unloaded delivery atomic with publication of a reloaded session.
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use codex_extension_api::ExtensionData;
|
||||
use codex_extension_api::MessageLifecycleContributor;
|
||||
use codex_extension_api::MessageLifecycleInput;
|
||||
use codex_protocol::ResponseItemId;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::InterAgentCommunication;
|
||||
use serde::Deserialize;
|
||||
@@ -156,13 +155,11 @@ pub(crate) struct MessageDelivery(Arc<Mutex<Option<MessagePublication>>>);
|
||||
impl MessageDelivery {
|
||||
pub(crate) fn publish(
|
||||
sender: ThreadId,
|
||||
message_id: ResponseItemId,
|
||||
observers: &[Arc<dyn MessageLifecycleContributor>],
|
||||
) -> Self {
|
||||
let input = MessageLifecycleInput {
|
||||
sender,
|
||||
data: ExtensionData::new(message_id.to_string()),
|
||||
message_id,
|
||||
data: ExtensionData::new(uuid::Uuid::now_v7().to_string()),
|
||||
};
|
||||
for observer in observers {
|
||||
observer.on_publish(&input);
|
||||
|
||||
@@ -7,7 +7,6 @@ use codex_core::config::Config;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::MessageLifecycleContributor;
|
||||
use codex_extension_api::MessageLifecycleInput;
|
||||
use codex_protocol::ResponseItemId;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::AgentStatus;
|
||||
use codex_protocol::protocol::Op;
|
||||
@@ -20,15 +19,18 @@ use std::sync::mpsc;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
#[derive(Default)]
|
||||
struct Messages(Mutex<HashSet<ResponseItemId>>);
|
||||
struct Messages(Mutex<HashSet<uuid::Uuid>>);
|
||||
impl MessageLifecycleContributor for Messages {
|
||||
fn on_publish(&self, input: &MessageLifecycleInput) {
|
||||
let mut pending = self.0.lock().expect("messages lock");
|
||||
assert!(pending.insert(input.message_id.clone()));
|
||||
let token = uuid::Uuid::new_v4();
|
||||
input.data.insert(token);
|
||||
assert!(pending.insert(token));
|
||||
}
|
||||
fn on_consumed(&self, input: &MessageLifecycleInput, _recipient: ThreadId) {
|
||||
let mut pending = self.0.lock().expect("messages lock");
|
||||
assert!(pending.remove(&input.message_id));
|
||||
let token = input.data.remove::<uuid::Uuid>().expect("published token");
|
||||
assert!(pending.remove(token.as_ref()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
//! Capture publication state once; consume it independently for each delivery.
|
||||
|
||||
use crate::ExtensionData;
|
||||
use codex_protocol::ResponseItemId;
|
||||
use codex_protocol::ThreadId;
|
||||
|
||||
/// State shared by all deliveries of a publication, including recipients resolved later.
|
||||
/// The model-visible item ID may still be unknown until the recipient records the message.
|
||||
pub struct MessageLifecycleInput {
|
||||
pub message_id: ResponseItemId,
|
||||
pub sender: ThreadId,
|
||||
/// Capture contributor-specific state at publication; read it at consumption.
|
||||
pub data: ExtensionData,
|
||||
|
||||
Reference in New Issue
Block a user