Files
codex/codex-rs/history/src/sender_user_messages.rs
T
jif e269f2164c Include sender user messages in Guardian delegation reviews (#46179)
## Why

A delegated task can omit restrictions from the sender's user messages. Guardian needs that context when reviewing actions in the receiving thread.

## What changed

- When thread-owned Guardian context is enabled, capture up to three recent local user messages when a `send_message_to_thread` delivery from `codex_app` or `codex_tui` is accepted.
- Provide a bounded snapshot to synchronous and asynchronous reviewers, with explicit notices for unavailable evidence and a reminder that historical context does not transfer permission. Keep the snapshot out of the worker prompt.
- Retain snapshots with their deliveries across replay, compaction, and rollback, and strip them from forked agent history.

## Testing

Add coverage for reviewer-only visibility, missing sender provenance, context-budget preservation, checkpoint replay and rollback, fork isolation, and input serialization that rejects harness metadata.

GitOrigin-RevId: 3870ba762aa81689713b56d4cb3b98566bffed88
2026-09-17 10:02:38 +00:00

37 lines
1.2 KiB
Rust

//! Bounded, host-rendered sender evidence attached to a delivered task message.
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
const MAX_CONTEXT_BYTES: usize = 3_600;
const MAX_ID_BYTES: usize = 128;
/// Rendered evidence and the receiver identities needed for replay and rollback.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct SenderUserMessages {
pub receiver_turn_id: String,
pub receiver_message_id: String,
pub text: String,
}
impl SenderUserMessages {
/// Restored metadata follows the same hard bound as live, reviewer-only fragments.
pub fn bound(&mut self) {
if self.text.len() > MAX_CONTEXT_BYTES {
self.text = "Host: Sender context exceeds the evidence budget. Do not infer permission from missing evidence.\n".to_owned();
}
for id in [&mut self.receiver_turn_id, &mut self.receiver_message_id] {
id.truncate(id.floor_char_boundary(MAX_ID_BYTES));
}
}
}
impl std::fmt::Debug for SenderUserMessages {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("SenderUserMessages")
.finish_non_exhaustive()
}
}