mirror of
https://github.com/openai/codex.git
synced 2026-10-31 19:28:49 +00:00
## Why Contextual fragments and extension-owned world-state sections currently return strings, limiting them to text content. ## What changed - Return `ContentItem` from fragment bodies and rendering, preserving classification and attribution. Apply text markers only to `InputText`; pass other content through unchanged. - Allow extension prompt and world-state contributions to carry typed content, and preserve media in context-window hints. - Hash non-text world-state fragments by their serialized content and role while retaining the existing text hashing behavior. - Add shared content-to-tool-output conversion that preserves image references, image detail, and audio. ## Testing Add coverage for typed world-state hashing and preservation of image content and attribution. Expand code-mode output tests to cover input text, output text, file-backed and inline images, and audio. GitOrigin-RevId: 2ed00d466a3f169b151202f3eef71e667ea64be1
70 lines
2.7 KiB
Rust
70 lines
2.7 KiB
Rust
use codex_protocol::AgentPath;
|
|
use codex_protocol::protocol::AgentStatus;
|
|
use codex_utils_output_truncation::TruncationPolicy;
|
|
use codex_utils_output_truncation::truncate_text;
|
|
|
|
use crate::context::ContextualUserFragment;
|
|
use crate::context::InterAgentCompletionMessage;
|
|
|
|
const COMPLETION_MESSAGE_MAX_TOKENS: usize = 1_000;
|
|
const COMPLETION_MESSAGE_ENVELOPE_TOKEN_RESERVE: usize = 100;
|
|
const ERROR_MAX_TOKENS: usize =
|
|
COMPLETION_MESSAGE_MAX_TOKENS - COMPLETION_MESSAGE_ENVELOPE_TOKEN_RESERVE;
|
|
const ERROR_NEXT_ACTION: &str = "This agent's turn failed. If you still need this agent, use the available collaboration tools to give it another task.";
|
|
const GUARDIAN_NEXT_ACTION: &str = "Tell the user this agent stopped after repeated Guardian denials. Do not resume this agent or retry its blocked work until the user explicitly confirms that it should continue.";
|
|
|
|
// Helpers for model-visible session state markers that are stored in user-role
|
|
// messages but are not user intent.
|
|
|
|
// TODO(jif) unify with structured schema
|
|
pub(crate) fn format_inter_agent_completion_message(
|
|
task_name: AgentPath,
|
|
sender: AgentPath,
|
|
status: &AgentStatus,
|
|
) -> Option<String> {
|
|
let payload = match status {
|
|
AgentStatus::Completed(Some(message)) => message.clone(),
|
|
AgentStatus::Completed(None) => String::new(),
|
|
AgentStatus::Errored(error) => {
|
|
let error = truncate_text(error, TruncationPolicy::Tokens(ERROR_MAX_TOKENS));
|
|
format!("Agent errored: {error}\n\n{ERROR_NEXT_ACTION}")
|
|
}
|
|
AgentStatus::Shutdown => "Agent shut down.".to_string(),
|
|
AgentStatus::NotFound => "Agent was not found.".to_string(),
|
|
AgentStatus::PendingInit | AgentStatus::Running | AgentStatus::Interrupted => return None,
|
|
};
|
|
Some(
|
|
InterAgentCompletionMessage::new(task_name, sender, payload)
|
|
.render()
|
|
.into_text()
|
|
.unwrap_or_default(),
|
|
)
|
|
}
|
|
|
|
pub(crate) fn format_guardian_interruption_message(
|
|
task_name: AgentPath,
|
|
sender: AgentPath,
|
|
error: &str,
|
|
) -> String {
|
|
let error = truncate_text(error, TruncationPolicy::Tokens(ERROR_MAX_TOKENS));
|
|
let payload = format!("Agent interrupted by Guardian: {error}\n\n{GUARDIAN_NEXT_ACTION}");
|
|
InterAgentCompletionMessage::new(task_name, sender, payload)
|
|
.render()
|
|
.into_text()
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "session_prefix_tests.rs"]
|
|
mod tests;
|
|
|
|
pub(crate) fn format_subagent_context_line(
|
|
agent_reference: &str,
|
|
agent_nickname: Option<&str>,
|
|
) -> String {
|
|
match agent_nickname.filter(|nickname| !nickname.is_empty()) {
|
|
Some(agent_nickname) => format!("- {agent_reference}: {agent_nickname}"),
|
|
None => format!("- {agent_reference}"),
|
|
}
|
|
}
|