mirror of
https://github.com/openai/codex.git
synced 2026-05-03 04:42:20 +03:00
Add ephemeral turn context support
Introduce app-server ephemeralContext, render it as additional_context_for_this_turn fragments, and strip it correctly across contextual-user diffing and compaction flows. Regenerate app-server schema fixtures and add coverage for model-visible layout, compaction, oversize validation, and resumed/forked context reconstruction. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -44,6 +44,7 @@ use crate::plan_tool::UpdatePlanArgs;
|
||||
use crate::request_permissions::RequestPermissionsEvent;
|
||||
use crate::request_permissions::RequestPermissionsResponse;
|
||||
use crate::request_user_input::RequestUserInputResponse;
|
||||
use crate::user_input::EphemeralContext;
|
||||
use crate::user_input::UserInput;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use schemars::JsonSchema;
|
||||
@@ -80,6 +81,8 @@ pub const USER_INSTRUCTIONS_OPEN_TAG: &str = "<user_instructions>";
|
||||
pub const USER_INSTRUCTIONS_CLOSE_TAG: &str = "</user_instructions>";
|
||||
pub const ENVIRONMENT_CONTEXT_OPEN_TAG: &str = "<environment_context>";
|
||||
pub const ENVIRONMENT_CONTEXT_CLOSE_TAG: &str = "</environment_context>";
|
||||
pub const EPHEMERAL_CONTEXT_OPEN_TAG: &str = "<additional_context_for_this_turn>";
|
||||
pub const EPHEMERAL_CONTEXT_CLOSE_TAG: &str = "</additional_context_for_this_turn>";
|
||||
pub const COLLABORATION_MODE_OPEN_TAG: &str = "<collaboration_mode>";
|
||||
pub const COLLABORATION_MODE_CLOSE_TAG: &str = "</collaboration_mode>";
|
||||
pub const REALTIME_CONVERSATION_OPEN_TAG: &str = "<realtime_conversation>";
|
||||
@@ -209,6 +212,10 @@ pub enum Op {
|
||||
UserInput {
|
||||
/// User input items, see `InputItem`
|
||||
items: Vec<UserInput>,
|
||||
/// Turn-scoped context that is visible to the model but is not part of
|
||||
/// the durable turn baseline.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
ephemeral_context: Vec<EphemeralContext>,
|
||||
/// Optional JSON Schema used to constrain the final assistant message for this turn.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
final_output_json_schema: Option<Value>,
|
||||
@@ -4053,6 +4060,7 @@ mod tests {
|
||||
fn user_input_serialization_omits_final_output_json_schema_when_none() -> Result<()> {
|
||||
let op = Op::UserInput {
|
||||
items: Vec::new(),
|
||||
ephemeral_context: Vec::new(),
|
||||
final_output_json_schema: None,
|
||||
};
|
||||
|
||||
@@ -4070,6 +4078,7 @@ mod tests {
|
||||
op,
|
||||
Op::UserInput {
|
||||
items: Vec::new(),
|
||||
ephemeral_context: Vec::new(),
|
||||
final_output_json_schema: None,
|
||||
}
|
||||
);
|
||||
@@ -4089,6 +4098,7 @@ mod tests {
|
||||
});
|
||||
let op = Op::UserInput {
|
||||
items: Vec::new(),
|
||||
ephemeral_context: Vec::new(),
|
||||
final_output_json_schema: Some(schema.clone()),
|
||||
};
|
||||
|
||||
@@ -4105,6 +4115,33 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_input_serialization_includes_ephemeral_context_when_present() -> Result<()> {
|
||||
let op = Op::UserInput {
|
||||
items: Vec::new(),
|
||||
ephemeral_context: vec![EphemeralContext {
|
||||
title: "Context from my editor".to_string(),
|
||||
text: "## Active file: src/main.rs".to_string(),
|
||||
}],
|
||||
final_output_json_schema: None,
|
||||
};
|
||||
|
||||
let json_op = serde_json::to_value(op)?;
|
||||
assert_eq!(
|
||||
json_op,
|
||||
json!({
|
||||
"type": "user_input",
|
||||
"items": [],
|
||||
"ephemeral_context": [{
|
||||
"title": "Context from my editor",
|
||||
"text": "## Active file: src/main.rs",
|
||||
}],
|
||||
})
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_input_text_serializes_empty_text_elements() -> Result<()> {
|
||||
let input = UserInput::Text {
|
||||
|
||||
@@ -6,6 +6,14 @@ use ts_rs::TS;
|
||||
/// Conservative cap so one user message cannot monopolize a large context window.
|
||||
pub const MAX_USER_INPUT_TEXT_CHARS: usize = 1 << 20;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, TS, JsonSchema)]
|
||||
pub struct EphemeralContext {
|
||||
/// Human-readable title for additional context sent with one turn.
|
||||
pub title: String,
|
||||
/// Free-form text payload for additional context sent with one turn.
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
/// User input
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS, JsonSchema)]
|
||||
|
||||
Reference in New Issue
Block a user