mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
Add vanilla context mode
This commit is contained in:
@@ -533,6 +533,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ContextMode": {
|
||||
"enum": [
|
||||
"default",
|
||||
"vanilla"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"DeviceKeyCreateParams": {
|
||||
"description": "Create a controller-local device key with a random key id.",
|
||||
"properties": {
|
||||
@@ -3457,6 +3464,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -3861,6 +3878,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -4039,6 +4066,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
|
||||
+37
@@ -7820,6 +7820,13 @@
|
||||
"title": "ContextCompactedNotification",
|
||||
"type": "object"
|
||||
},
|
||||
"ContextMode": {
|
||||
"enum": [
|
||||
"default",
|
||||
"vanilla"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"CreditsSnapshot": {
|
||||
"properties": {
|
||||
"balance": {
|
||||
@@ -15123,6 +15130,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -16623,6 +16640,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -16912,6 +16939,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
|
||||
+37
@@ -4318,6 +4318,13 @@
|
||||
"title": "ContextCompactedNotification",
|
||||
"type": "object"
|
||||
},
|
||||
"ContextMode": {
|
||||
"enum": [
|
||||
"default",
|
||||
"vanilla"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"CreditsSnapshot": {
|
||||
"properties": {
|
||||
"balance": {
|
||||
@@ -13009,6 +13016,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -14509,6 +14526,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -14798,6 +14825,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
|
||||
@@ -64,6 +64,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ContextMode": {
|
||||
"enum": [
|
||||
"default",
|
||||
"vanilla"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"PermissionProfileModificationParams": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -175,6 +182,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
|
||||
@@ -138,6 +138,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ContextMode": {
|
||||
"enum": [
|
||||
"default",
|
||||
"vanilla"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"FunctionCallOutputBody": {
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -1033,6 +1040,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
|
||||
@@ -64,6 +64,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ContextMode": {
|
||||
"enum": [
|
||||
"default",
|
||||
"vanilla"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"DynamicToolSpec": {
|
||||
"properties": {
|
||||
"deferLoading": {
|
||||
@@ -230,6 +237,16 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"contextMode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ContextMode"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cwd": {
|
||||
"type": [
|
||||
"string",
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ContextMode = "default" | "vanilla";
|
||||
@@ -5,6 +5,7 @@ import type { ServiceTier } from "../ServiceTier";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { ContextMode } from "./ContextMode";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
|
||||
/**
|
||||
@@ -23,4 +24,4 @@ model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, ephemeral?: boolean};
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, contextMode?: ContextMode | null, ephemeral?: boolean};
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { ServiceTier } from "../ServiceTier";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { ContextMode } from "./ContextMode";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
|
||||
/**
|
||||
@@ -26,4 +27,4 @@ model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null};
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, contextMode?: ContextMode | null, personality?: Personality | null};
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { ServiceTier } from "../ServiceTier";
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { ContextMode } from "./ContextMode";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
import type { ThreadStartSource } from "./ThreadStartSource";
|
||||
|
||||
@@ -13,4 +14,4 @@ export type ThreadStartParams = {model?: string | null, modelProvider?: string |
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, sessionStartSource?: ThreadStartSource | null};
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, contextMode?: ContextMode | null, personality?: Personality | null, ephemeral?: boolean | null, sessionStartSource?: ThreadStartSource | null};
|
||||
|
||||
@@ -77,6 +77,7 @@ export type { ConfigWriteResponse } from "./ConfigWriteResponse";
|
||||
export type { ConfiguredHookHandler } from "./ConfiguredHookHandler";
|
||||
export type { ConfiguredHookMatcherGroup } from "./ConfiguredHookMatcherGroup";
|
||||
export type { ContextCompactedNotification } from "./ContextCompactedNotification";
|
||||
export type { ContextMode } from "./ContextMode";
|
||||
export type { CreditsSnapshot } from "./CreditsSnapshot";
|
||||
export type { DeprecationNoticeNotification } from "./DeprecationNoticeNotification";
|
||||
export type { DeviceKeyAlgorithm } from "./DeviceKeyAlgorithm";
|
||||
|
||||
@@ -21,6 +21,7 @@ use codex_protocol::approvals::NetworkPolicyRuleAction as CoreNetworkPolicyRuleA
|
||||
use codex_protocol::config_types::ApprovalsReviewer as CoreApprovalsReviewer;
|
||||
use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::CollaborationModeMask as CoreCollaborationModeMask;
|
||||
use codex_protocol::config_types::ContextMode as CoreContextMode;
|
||||
use codex_protocol::config_types::ForcedLoginMethod;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::Personality;
|
||||
@@ -414,6 +415,13 @@ impl From<CoreSandboxMode> for SandboxMode {
|
||||
}
|
||||
}
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum ContextMode from CoreContextMode {
|
||||
Default,
|
||||
Vanilla
|
||||
}
|
||||
);
|
||||
|
||||
v2_enum_from_core!(
|
||||
pub enum ReviewDelivery from codex_protocol::protocol::ReviewDelivery {
|
||||
Inline, Detached
|
||||
@@ -3584,6 +3592,8 @@ pub struct ThreadStartParams {
|
||||
#[ts(optional = nullable)]
|
||||
pub developer_instructions: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub context_mode: Option<ContextMode>,
|
||||
#[ts(optional = nullable)]
|
||||
pub personality: Option<Personality>,
|
||||
#[ts(optional = nullable)]
|
||||
pub ephemeral: Option<bool>,
|
||||
@@ -3735,6 +3745,8 @@ pub struct ThreadResumeParams {
|
||||
#[ts(optional = nullable)]
|
||||
pub developer_instructions: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub context_mode: Option<ContextMode>,
|
||||
#[ts(optional = nullable)]
|
||||
pub personality: Option<Personality>,
|
||||
/// When true, return only thread metadata and live-resume state without
|
||||
/// populating `thread.turns`. This is useful when the client plans to call
|
||||
@@ -3839,6 +3851,8 @@ pub struct ThreadForkParams {
|
||||
pub base_instructions: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub developer_instructions: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub context_mode: Option<ContextMode>,
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub ephemeral: bool,
|
||||
/// When true, return only thread metadata and live fork state without
|
||||
|
||||
@@ -262,6 +262,7 @@ use codex_core::ThreadConfigSnapshot;
|
||||
use codex_core::ThreadManager;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::ConfigOverrides;
|
||||
use codex_core::config::ContextMode as CoreContextMode;
|
||||
use codex_core::config::NetworkProxyAuditMetadata;
|
||||
use codex_core::config::edit::ConfigEdit;
|
||||
use codex_core::config::edit::ConfigEditsBuilder;
|
||||
@@ -706,6 +707,9 @@ fn environment_selection_error_message(err: CodexErr) -> String {
|
||||
|
||||
impl CodexMessageProcessor {
|
||||
async fn instruction_sources_from_config(config: &Config) -> Vec<AbsolutePathBuf> {
|
||||
if !config.context_mode.includes_context_enrichment() {
|
||||
return Vec::new();
|
||||
}
|
||||
codex_core::AgentsMdManager::new(config)
|
||||
.instruction_sources(LOCAL_FS.as_ref())
|
||||
.await
|
||||
@@ -2510,6 +2514,7 @@ impl CodexMessageProcessor {
|
||||
service_name,
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
context_mode,
|
||||
dynamic_tools,
|
||||
mock_experimental_field: _mock_experimental_field,
|
||||
experimental_raw_events,
|
||||
@@ -2546,6 +2551,7 @@ impl CodexMessageProcessor {
|
||||
permissions,
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
context_mode,
|
||||
personality,
|
||||
);
|
||||
typesafe_overrides.ephemeral = ephemeral;
|
||||
@@ -2605,6 +2611,7 @@ impl CodexMessageProcessor {
|
||||
/*permissions*/ None,
|
||||
/*base_instructions*/ None,
|
||||
/*developer_instructions*/ None,
|
||||
/*context_mode*/ None,
|
||||
/*personality*/ None,
|
||||
);
|
||||
let config = self
|
||||
@@ -2975,6 +2982,7 @@ impl CodexMessageProcessor {
|
||||
permissions: Option<PermissionProfileSelectionParams>,
|
||||
base_instructions: Option<String>,
|
||||
developer_instructions: Option<String>,
|
||||
context_mode: Option<codex_app_server_protocol::ContextMode>,
|
||||
personality: Option<Personality>,
|
||||
) -> ConfigOverrides {
|
||||
let mut overrides = ConfigOverrides {
|
||||
@@ -2991,6 +2999,7 @@ impl CodexMessageProcessor {
|
||||
main_execve_wrapper_exe: self.arg0_paths.main_execve_wrapper_exe.clone(),
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
context_mode: context_mode.map(core_context_mode),
|
||||
personality,
|
||||
..Default::default()
|
||||
};
|
||||
@@ -4355,6 +4364,7 @@ impl CodexMessageProcessor {
|
||||
config: mut request_overrides,
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
context_mode,
|
||||
personality,
|
||||
exclude_turns,
|
||||
persist_extended_history,
|
||||
@@ -4389,6 +4399,7 @@ impl CodexMessageProcessor {
|
||||
permissions,
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
context_mode,
|
||||
personality,
|
||||
);
|
||||
self.load_and_apply_persisted_resume_metadata(
|
||||
@@ -4397,6 +4408,7 @@ impl CodexMessageProcessor {
|
||||
&mut typesafe_overrides,
|
||||
)
|
||||
.await;
|
||||
apply_context_mode_from_history(&thread_history, &mut typesafe_overrides);
|
||||
|
||||
// Derive a Config using the same logic as new conversation, honoring overrides if provided.
|
||||
let config = match self
|
||||
@@ -4599,7 +4611,7 @@ impl CodexMessageProcessor {
|
||||
if let (Some(requested_path), Some(active_path)) = (
|
||||
params.path.as_ref(),
|
||||
existing_thread.rollout_path().as_ref(),
|
||||
) && requested_path != active_path
|
||||
) && !path_utils::paths_match_after_normalization(requested_path, active_path)
|
||||
{
|
||||
return Err(invalid_request(format!(
|
||||
"cannot resume running thread {existing_thread_id} with stale path: requested `{}`, active `{}`",
|
||||
@@ -4957,6 +4969,7 @@ impl CodexMessageProcessor {
|
||||
config: cli_overrides,
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
context_mode,
|
||||
ephemeral,
|
||||
exclude_turns,
|
||||
persist_extended_history,
|
||||
@@ -5021,9 +5034,11 @@ impl CodexMessageProcessor {
|
||||
permissions,
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
context_mode,
|
||||
/*personality*/ None,
|
||||
);
|
||||
typesafe_overrides.ephemeral = ephemeral.then_some(true);
|
||||
apply_context_mode_from_items(&history_items, &mut typesafe_overrides);
|
||||
// Derive a Config using the same logic as new conversation, honoring overrides if provided.
|
||||
let config = self
|
||||
.config_manager
|
||||
@@ -8748,6 +8763,10 @@ fn collect_resume_override_mismatches(
|
||||
"developerInstructions override was provided and ignored while running".to_string(),
|
||||
);
|
||||
}
|
||||
if request.context_mode.is_some() {
|
||||
mismatch_details
|
||||
.push("contextMode override was provided and ignored while running".to_string());
|
||||
}
|
||||
if request.persist_extended_history {
|
||||
mismatch_details.push(
|
||||
"persistExtendedHistory override was provided and ignored while running".to_string(),
|
||||
@@ -8777,6 +8796,44 @@ fn merge_persisted_resume_metadata(
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_context_mode_from_history(
|
||||
thread_history: &InitialHistory,
|
||||
typesafe_overrides: &mut ConfigOverrides,
|
||||
) {
|
||||
if typesafe_overrides.context_mode.is_none()
|
||||
&& let Some(context_mode) = thread_history.get_context_mode()
|
||||
{
|
||||
typesafe_overrides.context_mode = Some(core_context_mode_from_protocol(context_mode));
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_context_mode_from_items(
|
||||
history_items: &[RolloutItem],
|
||||
typesafe_overrides: &mut ConfigOverrides,
|
||||
) {
|
||||
if typesafe_overrides.context_mode.is_none()
|
||||
&& let Some(context_mode) = history_items.iter().find_map(|item| match item {
|
||||
RolloutItem::SessionMeta(meta_line) => Some(meta_line.meta.context_mode),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
typesafe_overrides.context_mode = Some(core_context_mode_from_protocol(context_mode));
|
||||
}
|
||||
}
|
||||
|
||||
fn core_context_mode(mode: codex_app_server_protocol::ContextMode) -> CoreContextMode {
|
||||
core_context_mode_from_protocol(mode.to_core())
|
||||
}
|
||||
|
||||
fn core_context_mode_from_protocol(
|
||||
mode: codex_protocol::config_types::ContextMode,
|
||||
) -> CoreContextMode {
|
||||
match mode {
|
||||
codex_protocol::config_types::ContextMode::Default => CoreContextMode::Default,
|
||||
codex_protocol::config_types::ContextMode::Vanilla => CoreContextMode::Vanilla,
|
||||
}
|
||||
}
|
||||
|
||||
fn has_model_resume_override(
|
||||
request_overrides: Option<&HashMap<String, serde_json::Value>>,
|
||||
typesafe_overrides: &ConfigOverrides,
|
||||
@@ -10537,6 +10594,7 @@ mod tests {
|
||||
config: None,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
context_mode: None,
|
||||
personality: None,
|
||||
exclude_turns: false,
|
||||
persist_extended_history: false,
|
||||
@@ -10553,6 +10611,7 @@ mod tests {
|
||||
ephemeral: false,
|
||||
reasoning_effort: None,
|
||||
personality: None,
|
||||
context_mode: CoreContextMode::Default,
|
||||
session_source: SessionSource::Cli,
|
||||
};
|
||||
|
||||
@@ -10562,6 +10621,95 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect_resume_override_mismatches_includes_context_mode() {
|
||||
let cwd = test_path_buf("/tmp").abs();
|
||||
let request = ThreadResumeParams {
|
||||
thread_id: "thread-1".to_string(),
|
||||
context_mode: Some(codex_app_server_protocol::ContextMode::Vanilla),
|
||||
..ThreadResumeParams::default()
|
||||
};
|
||||
let config_snapshot = ThreadConfigSnapshot {
|
||||
model: "gpt-5".to_string(),
|
||||
model_provider_id: "openai".to_string(),
|
||||
service_tier: None,
|
||||
approval_policy: codex_protocol::protocol::AskForApproval::OnRequest,
|
||||
approvals_reviewer: codex_protocol::config_types::ApprovalsReviewer::User,
|
||||
permission_profile: codex_protocol::models::PermissionProfile::Disabled,
|
||||
active_permission_profile: None,
|
||||
cwd,
|
||||
ephemeral: false,
|
||||
reasoning_effort: None,
|
||||
personality: None,
|
||||
context_mode: CoreContextMode::Default,
|
||||
session_source: SessionSource::Cli,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
collect_resume_override_mismatches(&request, &config_snapshot),
|
||||
vec!["contextMode override was provided and ignored while running".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_context_mode_from_history_uses_stored_mode_when_omitted() {
|
||||
let thread_id = ThreadId::new();
|
||||
let thread_history = InitialHistory::Resumed(codex_protocol::protocol::ResumedHistory {
|
||||
conversation_id: thread_id,
|
||||
history: vec![session_meta_item(
|
||||
codex_protocol::config_types::ContextMode::Vanilla,
|
||||
)],
|
||||
rollout_path: None,
|
||||
});
|
||||
let mut overrides = ConfigOverrides::default();
|
||||
|
||||
apply_context_mode_from_history(&thread_history, &mut overrides);
|
||||
|
||||
assert_eq!(overrides.context_mode, Some(CoreContextMode::Vanilla));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_context_mode_from_history_preserves_explicit_mode() {
|
||||
let thread_id = ThreadId::new();
|
||||
let thread_history = InitialHistory::Resumed(codex_protocol::protocol::ResumedHistory {
|
||||
conversation_id: thread_id,
|
||||
history: vec![session_meta_item(
|
||||
codex_protocol::config_types::ContextMode::Vanilla,
|
||||
)],
|
||||
rollout_path: None,
|
||||
});
|
||||
let mut overrides = ConfigOverrides {
|
||||
context_mode: Some(CoreContextMode::Default),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
apply_context_mode_from_history(&thread_history, &mut overrides);
|
||||
|
||||
assert_eq!(overrides.context_mode, Some(CoreContextMode::Default));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_context_mode_from_items_uses_stored_mode_when_omitted() {
|
||||
let history_items = vec![session_meta_item(
|
||||
codex_protocol::config_types::ContextMode::Vanilla,
|
||||
)];
|
||||
let mut overrides = ConfigOverrides::default();
|
||||
|
||||
apply_context_mode_from_items(&history_items, &mut overrides);
|
||||
|
||||
assert_eq!(overrides.context_mode, Some(CoreContextMode::Vanilla));
|
||||
}
|
||||
|
||||
fn session_meta_item(context_mode: codex_protocol::config_types::ContextMode) -> RolloutItem {
|
||||
RolloutItem::SessionMeta(SessionMetaLine {
|
||||
meta: SessionMeta {
|
||||
context_mode,
|
||||
..SessionMeta::default()
|
||||
},
|
||||
git: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn test_thread_metadata(
|
||||
model: Option<&str>,
|
||||
reasoning_effort: Option<ReasoningEffort>,
|
||||
|
||||
@@ -142,6 +142,7 @@ pub fn create_fake_rollout_with_source(
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: model_provider.map(str::to_string),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
@@ -225,6 +226,7 @@ pub fn create_fake_rollout_with_text_elements(
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: model_provider.map(str::to_string),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -672,6 +672,7 @@ async fn skills_changed_notification_is_emitted_after_skill_change() -> Result<(
|
||||
service_name: None,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
context_mode: None,
|
||||
personality: None,
|
||||
ephemeral: None,
|
||||
session_start_source: None,
|
||||
|
||||
@@ -1115,6 +1115,7 @@ async fn seed_pathless_store_thread(
|
||||
metadata: ThreadPersistenceMetadata {
|
||||
cwd: None,
|
||||
model_provider: "test-provider".to_string(),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
memory_mode: ThreadMemoryMode::Disabled,
|
||||
},
|
||||
event_persistence_mode: ThreadEventPersistenceMode::default(),
|
||||
|
||||
@@ -1182,6 +1182,7 @@ stream_max_retries = 0
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: Some("mock_provider".to_string()),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::agent::AgentStatus;
|
||||
use crate::config::ConstraintResult;
|
||||
use crate::config::ContextMode;
|
||||
use crate::file_watcher::WatchRegistration;
|
||||
use crate::goals::GoalRuntimeEvent;
|
||||
use crate::session::Codex;
|
||||
@@ -58,6 +59,7 @@ pub struct ThreadConfigSnapshot {
|
||||
pub ephemeral: bool,
|
||||
pub reasoning_effort: Option<ReasoningEffort>,
|
||||
pub personality: Option<Personality>,
|
||||
pub context_mode: ContextMode,
|
||||
pub session_source: SessionSource,
|
||||
}
|
||||
|
||||
|
||||
@@ -4851,6 +4851,47 @@ async fn cli_override_sets_compact_prompt() -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn vanilla_context_mode_disables_context_enrichment_config() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let cfg = toml::from_str::<ConfigToml>(
|
||||
r#"
|
||||
instructions = "CFG_BASE_INSTRUCTIONS_MARKER"
|
||||
developer_instructions = "CFG_DEVELOPER_INSTRUCTIONS_MARKER"
|
||||
include_apps_instructions = true
|
||||
include_environment_context = true
|
||||
|
||||
[skills]
|
||||
include_instructions = true
|
||||
"#,
|
||||
)
|
||||
.expect("config TOML should parse");
|
||||
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
cfg,
|
||||
ConfigOverrides {
|
||||
base_instructions: Some("OVERRIDE_BASE_INSTRUCTIONS_MARKER".to_string()),
|
||||
developer_instructions: Some("OVERRIDE_DEVELOPER_INSTRUCTIONS_MARKER".to_string()),
|
||||
context_mode: Some(ContextMode::Vanilla),
|
||||
personality: Some(Personality::Pragmatic),
|
||||
..Default::default()
|
||||
},
|
||||
codex_home.abs(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(config.context_mode, ContextMode::Vanilla);
|
||||
assert_eq!(config.base_instructions, None);
|
||||
assert_eq!(config.developer_instructions, None);
|
||||
assert_eq!(config.personality, None);
|
||||
assert!(config.include_permissions_instructions);
|
||||
assert!(!config.include_apps_instructions);
|
||||
assert!(!config.include_skill_instructions);
|
||||
assert!(!config.include_environment_context);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn loads_compact_prompt_from_file() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
@@ -6422,6 +6463,7 @@ async fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
context_mode: ContextMode::Default,
|
||||
guardian_policy_config: None,
|
||||
include_permissions_instructions: true,
|
||||
include_apps_instructions: true,
|
||||
@@ -6624,6 +6666,7 @@ async fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
context_mode: ContextMode::Default,
|
||||
guardian_policy_config: None,
|
||||
include_permissions_instructions: true,
|
||||
include_apps_instructions: true,
|
||||
@@ -6780,6 +6823,7 @@ async fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
context_mode: ContextMode::Default,
|
||||
guardian_policy_config: None,
|
||||
include_permissions_instructions: true,
|
||||
include_apps_instructions: true,
|
||||
@@ -6921,6 +6965,7 @@ async fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
context_mode: ContextMode::Default,
|
||||
guardian_policy_config: None,
|
||||
include_permissions_instructions: true,
|
||||
include_apps_instructions: true,
|
||||
|
||||
@@ -78,6 +78,7 @@ use codex_model_provider_info::built_in_model_providers;
|
||||
use codex_model_provider_info::merge_configured_model_providers;
|
||||
use codex_models_manager::ModelsManagerConfig;
|
||||
use codex_protocol::config_types::AltScreenMode;
|
||||
use codex_protocol::config_types::ContextMode as ProtocolContextMode;
|
||||
use codex_protocol::config_types::ForcedLoginMethod;
|
||||
use codex_protocol::config_types::Personality;
|
||||
use codex_protocol::config_types::ReasoningSummary;
|
||||
@@ -451,6 +452,9 @@ pub struct Config {
|
||||
/// Developer instructions override injected as a separate message.
|
||||
pub developer_instructions: Option<String>,
|
||||
|
||||
/// Controls whether Codex loads project/user context into the model prompt.
|
||||
pub context_mode: ContextMode,
|
||||
|
||||
/// Guardian-specific policy config override from requirements.toml or config.toml.
|
||||
/// This is inserted into the fixed guardian prompt template under the
|
||||
/// `# Policy Configuration` section rather than replacing the whole
|
||||
@@ -812,6 +816,28 @@ pub struct Config {
|
||||
pub otel: codex_config::types::OtelConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum ContextMode {
|
||||
#[default]
|
||||
Default,
|
||||
Vanilla,
|
||||
}
|
||||
|
||||
impl ContextMode {
|
||||
pub fn includes_context_enrichment(self) -> bool {
|
||||
self == ContextMode::Default
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ContextMode> for ProtocolContextMode {
|
||||
fn from(value: ContextMode) -> Self {
|
||||
match value {
|
||||
ContextMode::Default => ProtocolContextMode::Default,
|
||||
ContextMode::Vanilla => ProtocolContextMode::Vanilla,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct MultiAgentV2Config {
|
||||
pub max_concurrent_threads_per_session: usize,
|
||||
@@ -1796,6 +1822,7 @@ pub struct ConfigOverrides {
|
||||
pub zsh_path: Option<PathBuf>,
|
||||
pub base_instructions: Option<String>,
|
||||
pub developer_instructions: Option<String>,
|
||||
pub context_mode: Option<ContextMode>,
|
||||
pub personality: Option<Personality>,
|
||||
pub compact_prompt: Option<String>,
|
||||
pub include_apply_patch_tool: Option<bool>,
|
||||
@@ -2038,8 +2065,6 @@ impl Config {
|
||||
guardian_policy_config_source: _,
|
||||
} = config_layer_stack.requirements().clone();
|
||||
|
||||
let user_instructions = AgentsMdManager::load_global_instructions(Some(&codex_home))
|
||||
.map(|loaded| loaded.contents);
|
||||
let mut startup_warnings = config_layer_stack
|
||||
.startup_warnings()
|
||||
.unwrap_or_default()
|
||||
@@ -2064,6 +2089,7 @@ impl Config {
|
||||
zsh_path: zsh_path_override,
|
||||
base_instructions,
|
||||
developer_instructions,
|
||||
context_mode,
|
||||
personality,
|
||||
compact_prompt,
|
||||
include_apply_patch_tool: include_apply_patch_tool_override,
|
||||
@@ -2085,6 +2111,14 @@ impl Config {
|
||||
"`sandbox_mode` and `default_permissions` overrides cannot both be set",
|
||||
));
|
||||
}
|
||||
let context_mode = context_mode.unwrap_or_default();
|
||||
let includes_context_enrichment = context_mode.includes_context_enrichment();
|
||||
let user_instructions = includes_context_enrichment
|
||||
.then(|| {
|
||||
AgentsMdManager::load_global_instructions(Some(&codex_home))
|
||||
.map(|loaded| loaded.contents)
|
||||
})
|
||||
.flatten();
|
||||
if permission_profile.is_some() && default_permissions_override.is_some() {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
@@ -2681,37 +2715,46 @@ impl Config {
|
||||
// Load base instructions override from a file if specified. If the
|
||||
// path is relative, resolve it against the effective cwd so the
|
||||
// behaviour matches other path-like config values.
|
||||
let model_instructions_path = config_profile
|
||||
.model_instructions_file
|
||||
.as_ref()
|
||||
.or(cfg.model_instructions_file.as_ref());
|
||||
let file_base_instructions = Self::try_read_non_empty_file(
|
||||
fs,
|
||||
model_instructions_path,
|
||||
"model instructions file",
|
||||
)
|
||||
.await?;
|
||||
let base_instructions = base_instructions
|
||||
.or(file_base_instructions)
|
||||
.or(cfg.instructions.clone());
|
||||
let developer_instructions = developer_instructions.or(cfg.developer_instructions);
|
||||
let base_instructions = if includes_context_enrichment {
|
||||
let model_instructions_path = config_profile
|
||||
.model_instructions_file
|
||||
.as_ref()
|
||||
.or(cfg.model_instructions_file.as_ref());
|
||||
let file_base_instructions = Self::try_read_non_empty_file(
|
||||
fs,
|
||||
model_instructions_path,
|
||||
"model instructions file",
|
||||
)
|
||||
.await?;
|
||||
base_instructions
|
||||
.or(file_base_instructions)
|
||||
.or(cfg.instructions.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let developer_instructions = includes_context_enrichment
|
||||
.then(|| developer_instructions.or(cfg.developer_instructions))
|
||||
.flatten();
|
||||
let include_permissions_instructions = config_profile
|
||||
.include_permissions_instructions
|
||||
.or(cfg.include_permissions_instructions)
|
||||
.unwrap_or(true);
|
||||
let include_apps_instructions = config_profile
|
||||
.include_apps_instructions
|
||||
.or(cfg.include_apps_instructions)
|
||||
.unwrap_or(true);
|
||||
let include_skill_instructions = cfg
|
||||
.skills
|
||||
.as_ref()
|
||||
.and_then(|skills| skills.include_instructions)
|
||||
.unwrap_or(true);
|
||||
let include_environment_context = config_profile
|
||||
.include_environment_context
|
||||
.or(cfg.include_environment_context)
|
||||
.unwrap_or(true);
|
||||
let include_apps_instructions = includes_context_enrichment
|
||||
&& config_profile
|
||||
.include_apps_instructions
|
||||
.or(cfg.include_apps_instructions)
|
||||
.unwrap_or(true);
|
||||
let include_skill_instructions = includes_context_enrichment
|
||||
&& cfg
|
||||
.skills
|
||||
.as_ref()
|
||||
.and_then(|skills| skills.include_instructions)
|
||||
.unwrap_or(true);
|
||||
let include_environment_context = includes_context_enrichment
|
||||
&& config_profile
|
||||
.include_environment_context
|
||||
.or(cfg.include_environment_context)
|
||||
.unwrap_or(true);
|
||||
let guardian_policy_config =
|
||||
guardian_policy_config_from_requirements(config_layer_stack.requirements_toml())
|
||||
.or_else(|| {
|
||||
@@ -2721,14 +2764,18 @@ impl Config {
|
||||
auto_review.policy.as_deref(),
|
||||
))
|
||||
});
|
||||
let personality = personality
|
||||
.or(config_profile.personality)
|
||||
.or(cfg.personality)
|
||||
.or_else(|| {
|
||||
features
|
||||
.enabled(Feature::Personality)
|
||||
.then_some(Personality::Pragmatic)
|
||||
});
|
||||
let personality = includes_context_enrichment
|
||||
.then(|| {
|
||||
personality
|
||||
.or(config_profile.personality)
|
||||
.or(cfg.personality)
|
||||
.or_else(|| {
|
||||
features
|
||||
.enabled(Feature::Personality)
|
||||
.then_some(Personality::Pragmatic)
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
|
||||
let experimental_compact_prompt_path = config_profile
|
||||
.experimental_compact_prompt_file
|
||||
@@ -2919,6 +2966,7 @@ impl Config {
|
||||
base_instructions,
|
||||
personality,
|
||||
developer_instructions,
|
||||
context_mode,
|
||||
compact_prompt,
|
||||
commit_attribution,
|
||||
include_permissions_instructions,
|
||||
|
||||
@@ -54,6 +54,7 @@ async fn write_rollout_with_user_event(dir: &Path, thread_id: ThreadId) -> io::R
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: None,
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -474,9 +474,13 @@ impl Codex {
|
||||
let fs = environment_selections.primary_filesystem();
|
||||
let plugins_input = config.plugins_config_input();
|
||||
let plugin_outcome = plugins_manager.plugins_for_config(&plugins_input).await;
|
||||
let effective_skill_roots = plugin_outcome.effective_skill_roots();
|
||||
let skills_input = skills_load_input_from_config(&config, effective_skill_roots);
|
||||
let loaded_skills = skills_manager.skills_for_config(&skills_input, fs).await;
|
||||
let loaded_skills = if config.context_mode.includes_context_enrichment() {
|
||||
let effective_skill_roots = plugin_outcome.effective_skill_roots();
|
||||
let skills_input = skills_load_input_from_config(&config, effective_skill_roots);
|
||||
skills_manager.skills_for_config(&skills_input, fs).await
|
||||
} else {
|
||||
SkillLoadOutcome::default()
|
||||
};
|
||||
|
||||
for err in &loaded_skills.errors {
|
||||
error!(
|
||||
@@ -495,9 +499,13 @@ impl Codex {
|
||||
}
|
||||
|
||||
let primary_environment = environment_selections.primary_environment();
|
||||
let user_instructions = AgentsMdManager::new(&config)
|
||||
.user_instructions(primary_environment.as_deref())
|
||||
.await;
|
||||
let user_instructions = if config.context_mode.includes_context_enrichment() {
|
||||
AgentsMdManager::new(&config)
|
||||
.user_instructions(primary_environment.as_deref())
|
||||
.await
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let exec_policy = if crate::guardian::is_guardian_reviewer_source(&session_source) {
|
||||
// Guardian review should rely on the built-in shell safety checks,
|
||||
@@ -598,6 +606,7 @@ impl Codex {
|
||||
developer_instructions: config.developer_instructions.clone(),
|
||||
user_instructions,
|
||||
personality: config.personality,
|
||||
context_mode: config.context_mode,
|
||||
base_instructions,
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
@@ -2578,16 +2587,22 @@ impl Session {
|
||||
}
|
||||
let separate_guardian_developer_message =
|
||||
crate::guardian::is_guardian_reviewer_source(&session_source);
|
||||
let includes_context_enrichment = turn_context
|
||||
.config
|
||||
.context_mode
|
||||
.includes_context_enrichment();
|
||||
// Keep the guardian policy prompt out of the aggregated developer bundle so it
|
||||
// stays isolated as its own top-level developer message for guardian subagents.
|
||||
if !separate_guardian_developer_message
|
||||
if includes_context_enrichment
|
||||
&& !separate_guardian_developer_message
|
||||
&& let Some(developer_instructions) = turn_context.developer_instructions.as_deref()
|
||||
&& !developer_instructions.is_empty()
|
||||
{
|
||||
developer_sections.push(developer_instructions.to_string());
|
||||
}
|
||||
// Add developer instructions for memories.
|
||||
if turn_context.features.enabled(Feature::MemoryTool)
|
||||
if includes_context_enrichment
|
||||
&& turn_context.features.enabled(Feature::MemoryTool)
|
||||
&& turn_context.config.memories.use_memories
|
||||
&& let Some(memory_prompt) =
|
||||
build_memory_tool_developer_instructions(&turn_context.config.codex_home).await
|
||||
@@ -2595,8 +2610,9 @@ impl Session {
|
||||
developer_sections.push(memory_prompt);
|
||||
}
|
||||
// Add developer instructions from collaboration_mode if they exist and are non-empty
|
||||
if let Some(collab_instructions) =
|
||||
CollaborationModeInstructions::from_collaboration_mode(&collaboration_mode)
|
||||
if includes_context_enrichment
|
||||
&& let Some(collab_instructions) =
|
||||
CollaborationModeInstructions::from_collaboration_mode(&collaboration_mode)
|
||||
{
|
||||
developer_sections.push(collab_instructions.render());
|
||||
}
|
||||
@@ -2607,7 +2623,8 @@ impl Session {
|
||||
) {
|
||||
developer_sections.push(realtime_update);
|
||||
}
|
||||
if self.features.enabled(Feature::Personality)
|
||||
if includes_context_enrichment
|
||||
&& self.features.enabled(Feature::Personality)
|
||||
&& let Some(personality) = turn_context.personality
|
||||
{
|
||||
let model_info = turn_context.model_info.clone();
|
||||
@@ -2624,7 +2641,10 @@ impl Session {
|
||||
.push(PersonalitySpecInstructions::new(personality_message).render());
|
||||
}
|
||||
}
|
||||
if turn_context.config.include_apps_instructions && turn_context.apps_enabled() {
|
||||
if includes_context_enrichment
|
||||
&& turn_context.config.include_apps_instructions
|
||||
&& turn_context.apps_enabled()
|
||||
{
|
||||
let mcp_connection_manager = self.services.mcp_connection_manager.read().await;
|
||||
let accessible_and_enabled_connectors =
|
||||
connectors::list_accessible_and_enabled_connectors_from_manager(
|
||||
@@ -2638,7 +2658,7 @@ impl Session {
|
||||
developer_sections.push(apps_instructions.render());
|
||||
}
|
||||
}
|
||||
if turn_context.config.include_skill_instructions {
|
||||
if includes_context_enrichment && turn_context.config.include_skill_instructions {
|
||||
let available_skills = build_available_skills(
|
||||
&turn_context.turn_skills.outcome,
|
||||
default_skill_metadata_budget(turn_context.model_info.context_window),
|
||||
@@ -2661,24 +2681,29 @@ impl Session {
|
||||
developer_sections.push(skills_instructions.render());
|
||||
}
|
||||
}
|
||||
let loaded_plugins = self
|
||||
.services
|
||||
.plugins_manager
|
||||
.plugins_for_config(&turn_context.config.plugins_config_input())
|
||||
.await;
|
||||
if let Some(plugin_instructions) =
|
||||
AvailablePluginsInstructions::from_plugins(loaded_plugins.capability_summaries())
|
||||
{
|
||||
developer_sections.push(plugin_instructions.render());
|
||||
if includes_context_enrichment {
|
||||
let loaded_plugins = self
|
||||
.services
|
||||
.plugins_manager
|
||||
.plugins_for_config(&turn_context.config.plugins_config_input())
|
||||
.await;
|
||||
if let Some(plugin_instructions) =
|
||||
AvailablePluginsInstructions::from_plugins(loaded_plugins.capability_summaries())
|
||||
{
|
||||
developer_sections.push(plugin_instructions.render());
|
||||
}
|
||||
}
|
||||
if turn_context.features.enabled(Feature::CodexGitCommit)
|
||||
if includes_context_enrichment
|
||||
&& turn_context.features.enabled(Feature::CodexGitCommit)
|
||||
&& let Some(commit_message_instruction) = commit_message_trailer_instruction(
|
||||
turn_context.config.commit_attribution.as_deref(),
|
||||
)
|
||||
{
|
||||
developer_sections.push(commit_message_instruction);
|
||||
}
|
||||
if let Some(user_instructions) = turn_context.user_instructions.as_deref() {
|
||||
if includes_context_enrichment
|
||||
&& let Some(user_instructions) = turn_context.user_instructions.as_deref()
|
||||
{
|
||||
contextual_user_sections.push(
|
||||
UserInstructions {
|
||||
text: user_instructions.to_string(),
|
||||
@@ -2687,7 +2712,7 @@ impl Session {
|
||||
.render(),
|
||||
);
|
||||
}
|
||||
if turn_context.config.include_environment_context {
|
||||
if includes_context_enrichment && turn_context.config.include_environment_context {
|
||||
let subagents = self
|
||||
.services
|
||||
.agent_control
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::*;
|
||||
use crate::goals::GoalRuntimeState;
|
||||
use codex_otel::LEGACY_NOTIFY_CONFIGURED_METRIC;
|
||||
use codex_protocol::config_types::ContextMode as ProtocolContextMode;
|
||||
use codex_protocol::permissions::FileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSpecialPath;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
@@ -51,6 +52,9 @@ pub(crate) struct SessionConfiguration {
|
||||
/// Personality preference for the model.
|
||||
pub(super) personality: Option<Personality>,
|
||||
|
||||
/// Controls whether Codex loads project/user context into the model prompt.
|
||||
pub(super) context_mode: crate::config::ContextMode,
|
||||
|
||||
/// Base instructions for the session.
|
||||
pub(super) base_instructions: String,
|
||||
|
||||
@@ -141,6 +145,7 @@ impl SessionConfiguration {
|
||||
ephemeral: self.original_config_do_not_use.ephemeral,
|
||||
reasoning_effort: self.collaboration_mode.reasoning_effort(),
|
||||
personality: self.personality,
|
||||
context_mode: self.context_mode,
|
||||
session_source: self.session_source.clone(),
|
||||
}
|
||||
}
|
||||
@@ -400,6 +405,9 @@ impl Session {
|
||||
metadata: ThreadPersistenceMetadata {
|
||||
cwd: Some(config.cwd.to_path_buf()),
|
||||
model_provider: config.model_provider_id.clone(),
|
||||
context_mode: ProtocolContextMode::from(
|
||||
session_configuration.context_mode,
|
||||
),
|
||||
memory_mode: if config.memories.generate_memories {
|
||||
ThreadMemoryMode::Enabled
|
||||
} else {
|
||||
@@ -422,6 +430,9 @@ impl Session {
|
||||
metadata: ThreadPersistenceMetadata {
|
||||
cwd: Some(config.cwd.to_path_buf()),
|
||||
model_provider: config.model_provider_id.clone(),
|
||||
context_mode: ProtocolContextMode::from(
|
||||
session_configuration.context_mode,
|
||||
),
|
||||
memory_mode: if config.memories.generate_memories {
|
||||
ThreadMemoryMode::Enabled
|
||||
} else {
|
||||
|
||||
@@ -2354,6 +2354,7 @@ async fn set_rate_limits_retains_previous_credits() {
|
||||
user_instructions: config.user_instructions.clone(),
|
||||
service_tier: None,
|
||||
personality: config.personality,
|
||||
context_mode: config.context_mode,
|
||||
base_instructions: config
|
||||
.base_instructions
|
||||
.clone()
|
||||
@@ -2457,6 +2458,7 @@ async fn set_rate_limits_updates_plan_type_when_present() {
|
||||
user_instructions: config.user_instructions.clone(),
|
||||
service_tier: None,
|
||||
personality: config.personality,
|
||||
context_mode: config.context_mode,
|
||||
base_instructions: config
|
||||
.base_instructions
|
||||
.clone()
|
||||
@@ -2733,6 +2735,7 @@ async fn attach_thread_persistence(session: &mut Session) -> PathBuf {
|
||||
metadata: ThreadPersistenceMetadata {
|
||||
cwd: Some(config.cwd.to_path_buf()),
|
||||
model_provider: config.model_provider_id.clone(),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
memory_mode: if config.memories.generate_memories {
|
||||
ThreadMemoryMode::Enabled
|
||||
} else {
|
||||
@@ -2915,6 +2918,7 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
|
||||
user_instructions: config.user_instructions.clone(),
|
||||
service_tier: None,
|
||||
personality: config.personality,
|
||||
context_mode: config.context_mode,
|
||||
base_instructions: config
|
||||
.base_instructions
|
||||
.clone()
|
||||
@@ -3438,6 +3442,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
|
||||
user_instructions: config.user_instructions.clone(),
|
||||
service_tier: None,
|
||||
personality: config.personality,
|
||||
context_mode: config.context_mode,
|
||||
base_instructions: config
|
||||
.base_instructions
|
||||
.clone()
|
||||
@@ -3543,6 +3548,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
user_instructions: config.user_instructions.clone(),
|
||||
service_tier: None,
|
||||
personality: config.personality,
|
||||
context_mode: config.context_mode,
|
||||
base_instructions: config
|
||||
.base_instructions
|
||||
.clone()
|
||||
@@ -3755,6 +3761,7 @@ async fn make_session_with_config_and_rx(
|
||||
user_instructions: config.user_instructions.clone(),
|
||||
service_tier: None,
|
||||
personality: config.personality,
|
||||
context_mode: config.context_mode,
|
||||
base_instructions: config
|
||||
.base_instructions
|
||||
.clone()
|
||||
@@ -4726,6 +4733,7 @@ async fn shutdown_complete_does_not_append_to_thread_store_after_shutdown() {
|
||||
metadata: ThreadPersistenceMetadata {
|
||||
cwd: Some(config.cwd.to_path_buf()),
|
||||
model_provider: config.model_provider_id.clone(),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
memory_mode: if config.memories.generate_memories {
|
||||
ThreadMemoryMode::Enabled
|
||||
} else {
|
||||
@@ -5025,6 +5033,7 @@ where
|
||||
user_instructions: config.user_instructions.clone(),
|
||||
service_tier: None,
|
||||
personality: config.personality,
|
||||
context_mode: config.context_mode,
|
||||
base_instructions: config
|
||||
.base_instructions
|
||||
.clone()
|
||||
@@ -5808,6 +5817,45 @@ async fn build_initial_context_trims_skill_metadata_from_context_window_budget()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn build_initial_context_omits_context_enrichment_in_vanilla_mode() {
|
||||
let (session, mut turn_context) = make_session_and_context().await;
|
||||
let mut config = (*turn_context.config).clone();
|
||||
config.context_mode = crate::config::ContextMode::Vanilla;
|
||||
config.include_apps_instructions = true;
|
||||
config.include_skill_instructions = true;
|
||||
config.include_environment_context = true;
|
||||
turn_context.config = Arc::new(config);
|
||||
turn_context.developer_instructions = Some("VANILLA_DEVELOPER_INSTRUCTIONS_MARKER".to_string());
|
||||
turn_context.user_instructions = Some("VANILLA_USER_INSTRUCTIONS_MARKER".to_string());
|
||||
turn_context.personality = Some(codex_protocol::config_types::Personality::Pragmatic);
|
||||
let mut outcome = SkillLoadOutcome::default();
|
||||
outcome.skills = vec![SkillMetadata {
|
||||
name: "vanilla-repo-skill".to_string(),
|
||||
description: "VANILLA_SKILL_DESCRIPTION_MARKER".to_string(),
|
||||
short_description: None,
|
||||
interface: None,
|
||||
dependencies: None,
|
||||
policy: None,
|
||||
path_to_skills_md: test_path_buf("/tmp/vanilla-repo-skill/SKILL.md").abs(),
|
||||
scope: SkillScope::Repo,
|
||||
}];
|
||||
turn_context.turn_skills = TurnSkillsContext::new(Arc::new(outcome));
|
||||
|
||||
let initial_context = session.build_initial_context(&turn_context).await;
|
||||
let visible_text = developer_input_texts(&initial_context)
|
||||
.into_iter()
|
||||
.chain(user_input_texts(&initial_context))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
assert!(!visible_text.contains("VANILLA_DEVELOPER_INSTRUCTIONS_MARKER"));
|
||||
assert!(!visible_text.contains("VANILLA_USER_INSTRUCTIONS_MARKER"));
|
||||
assert!(!visible_text.contains("vanilla-repo-skill"));
|
||||
assert!(!visible_text.contains("VANILLA_SKILL_DESCRIPTION_MARKER"));
|
||||
assert!(!visible_text.contains("<environment_context>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_thread_start_skill_metrics_records_enabled_kept_and_truncated_values() {
|
||||
let session_telemetry = test_session_telemetry_without_metadata();
|
||||
|
||||
@@ -70,6 +70,7 @@ async fn write_rollout_with_user_event(dir: &Path, thread_id: ThreadId) -> io::R
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: None,
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
@@ -115,6 +116,7 @@ async fn write_rollout_with_meta_only(dir: &Path, thread_id: ThreadId) -> io::Re
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: None,
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -174,6 +174,7 @@ async fn find_locates_rollout_file_written_by_recorder() -> std::io::Result<()>
|
||||
/*forked_from_id*/ None,
|
||||
SessionSource::Exec,
|
||||
BaseInstructions::default(),
|
||||
codex_protocol::config_types::ContextMode::Default,
|
||||
Vec::new(),
|
||||
EventPersistenceMode::Limited,
|
||||
),
|
||||
|
||||
@@ -148,6 +148,7 @@ async fn backfill_scans_existing_rollouts() -> Result<()> {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: None,
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: Some(dynamic_tools_for_hook),
|
||||
memory_mode: None,
|
||||
|
||||
@@ -412,6 +412,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
|
||||
zsh_path: None,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
context_mode: None,
|
||||
personality: None,
|
||||
compact_prompt: None,
|
||||
include_apply_patch_tool: None,
|
||||
|
||||
@@ -77,6 +77,20 @@ pub enum SandboxMode {
|
||||
DangerFullAccess,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ContextMode {
|
||||
#[default]
|
||||
Default,
|
||||
Vanilla,
|
||||
}
|
||||
|
||||
impl ContextMode {
|
||||
pub fn is_default(&self) -> bool {
|
||||
*self == ContextMode::Default
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Display, TS)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
#[ts(type = r#""user" | "auto_review" | "guardian_subagent""#)]
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::ThreadId;
|
||||
use crate::approvals::ElicitationRequestEvent;
|
||||
use crate::config_types::ApprovalsReviewer;
|
||||
use crate::config_types::CollaborationMode;
|
||||
use crate::config_types::ContextMode;
|
||||
use crate::config_types::ModeKind;
|
||||
use crate::config_types::Personality;
|
||||
use crate::config_types::ReasoningSummary as ReasoningSummaryConfig;
|
||||
@@ -2526,6 +2527,22 @@ impl InitialHistory {
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_context_mode(&self) -> Option<ContextMode> {
|
||||
match self {
|
||||
InitialHistory::New | InitialHistory::Cleared => None,
|
||||
InitialHistory::Resumed(resumed) => {
|
||||
resumed.history.iter().find_map(|item| match item {
|
||||
RolloutItem::SessionMeta(meta_line) => Some(meta_line.meta.context_mode),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
InitialHistory::Forked(items) => items.iter().find_map(|item| match item {
|
||||
RolloutItem::SessionMeta(meta_line) => Some(meta_line.meta.context_mode),
|
||||
_ => None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn session_cwd_from_items(items: &[RolloutItem]) -> Option<PathBuf> {
|
||||
@@ -2731,6 +2748,8 @@ pub struct SessionMeta {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub agent_path: Option<String>,
|
||||
pub model_provider: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "ContextMode::is_default")]
|
||||
pub context_mode: ContextMode,
|
||||
/// base_instructions for the session. This *should* always be present when creating a new session,
|
||||
/// but may be missing for older sessions. If not present, fall back to rendering the base_instructions
|
||||
/// from ModelsManager.
|
||||
@@ -2755,6 +2774,7 @@ impl Default for SessionMeta {
|
||||
agent_role: None,
|
||||
agent_path: None,
|
||||
model_provider: None,
|
||||
context_mode: ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -44,6 +44,7 @@ async fn extract_metadata_from_rollout_uses_session_meta() {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: Some("openai".to_string()),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
@@ -95,6 +96,7 @@ async fn extract_metadata_from_rollout_returns_latest_memory_mode() {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: Some("openai".to_string()),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
@@ -354,6 +356,7 @@ fn write_rollout_in_sessions_with_cwd(
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: Some("test-provider".to_string()),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -12,6 +12,7 @@ use std::sync::Mutex;
|
||||
use chrono::SecondsFormat;
|
||||
use chrono::Utc;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::config_types::ContextMode;
|
||||
use codex_protocol::dynamic_tools::DynamicToolSpec;
|
||||
use codex_protocol::models::BaseInstructions;
|
||||
use codex_utils_string::truncate_middle_chars;
|
||||
@@ -90,6 +91,7 @@ pub enum RolloutRecorderParams {
|
||||
forked_from_id: Option<ThreadId>,
|
||||
source: SessionSource,
|
||||
base_instructions: BaseInstructions,
|
||||
context_mode: ContextMode,
|
||||
dynamic_tools: Vec<DynamicToolSpec>,
|
||||
event_persistence_mode: EventPersistenceMode,
|
||||
},
|
||||
@@ -166,6 +168,7 @@ impl RolloutRecorderParams {
|
||||
forked_from_id: Option<ThreadId>,
|
||||
source: SessionSource,
|
||||
base_instructions: BaseInstructions,
|
||||
context_mode: ContextMode,
|
||||
dynamic_tools: Vec<DynamicToolSpec>,
|
||||
event_persistence_mode: EventPersistenceMode,
|
||||
) -> Self {
|
||||
@@ -174,6 +177,7 @@ impl RolloutRecorderParams {
|
||||
forked_from_id,
|
||||
source,
|
||||
base_instructions,
|
||||
context_mode,
|
||||
dynamic_tools,
|
||||
event_persistence_mode,
|
||||
}
|
||||
@@ -661,6 +665,7 @@ impl RolloutRecorder {
|
||||
forked_from_id,
|
||||
source,
|
||||
base_instructions,
|
||||
context_mode,
|
||||
dynamic_tools,
|
||||
event_persistence_mode,
|
||||
} => {
|
||||
@@ -689,6 +694,7 @@ impl RolloutRecorder {
|
||||
agent_path: source.get_agent_path().map(Into::into),
|
||||
source,
|
||||
model_provider: Some(config.model_provider_id().to_string()),
|
||||
context_mode,
|
||||
base_instructions: Some(base_instructions),
|
||||
dynamic_tools: if dynamic_tools.is_empty() {
|
||||
None
|
||||
|
||||
@@ -232,6 +232,7 @@ async fn recorder_materializes_on_flush_with_pending_items() -> std::io::Result<
|
||||
/*forked_from_id*/ None,
|
||||
SessionSource::Exec,
|
||||
BaseInstructions::default(),
|
||||
codex_protocol::config_types::ContextMode::Default,
|
||||
Vec::new(),
|
||||
EventPersistenceMode::Limited,
|
||||
),
|
||||
@@ -312,6 +313,7 @@ async fn persist_reports_filesystem_error_and_retries_buffered_items() -> std::i
|
||||
/*forked_from_id*/ None,
|
||||
SessionSource::Exec,
|
||||
BaseInstructions::default(),
|
||||
codex_protocol::config_types::ContextMode::Default,
|
||||
Vec::new(),
|
||||
EventPersistenceMode::Limited,
|
||||
),
|
||||
@@ -411,6 +413,7 @@ async fn metadata_irrelevant_events_touch_state_db_updated_at() -> std::io::Resu
|
||||
/*forked_from_id*/ None,
|
||||
SessionSource::Cli,
|
||||
BaseInstructions::default(),
|
||||
codex_protocol::config_types::ContextMode::Default,
|
||||
Vec::new(),
|
||||
EventPersistenceMode::Limited,
|
||||
),
|
||||
|
||||
@@ -36,6 +36,7 @@ fn write_rollout_with_metadata(path: &Path, thread_id: ThreadId) -> std::io::Res
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: Some("test-provider".into()),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -1149,6 +1149,7 @@ async fn test_updated_at_uses_file_mtime() -> Result<()> {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: Some("test-provider".into()),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -282,6 +282,7 @@ mod tests {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: Some("openai".to_string()),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
@@ -415,6 +416,7 @@ mod tests {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: Some("openai".to_string()),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -1362,6 +1362,7 @@ mod tests {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: None,
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: Some("polluted".to_string()),
|
||||
@@ -1420,6 +1421,7 @@ mod tests {
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
model_provider: None,
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
base_instructions: None,
|
||||
dynamic_tools: None,
|
||||
memory_mode: None,
|
||||
|
||||
@@ -159,6 +159,7 @@ fn new_config(model: Option<String>, arg0_paths: Arg0DispatchPaths) -> anyhow::R
|
||||
model_auto_compact_token_limit: None,
|
||||
model_provider_id,
|
||||
model_provider,
|
||||
context_mode: Default::default(),
|
||||
personality: None,
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::Never),
|
||||
|
||||
@@ -35,6 +35,7 @@ pub(super) async fn create_thread(
|
||||
params.forked_from_id,
|
||||
params.source,
|
||||
params.base_instructions,
|
||||
params.metadata.context_mode,
|
||||
params.dynamic_tools,
|
||||
event_persistence_mode(params.event_persistence_mode),
|
||||
),
|
||||
|
||||
@@ -216,7 +216,7 @@ impl ThreadStore for LocalThreadStore {
|
||||
return read_thread::read_thread_by_rollout_path(
|
||||
self,
|
||||
rollout_path,
|
||||
/*include_archived*/ true,
|
||||
params.include_archived,
|
||||
/*include_history*/ true,
|
||||
)
|
||||
.await?
|
||||
@@ -533,6 +533,7 @@ mod tests {
|
||||
metadata: ThreadPersistenceMetadata {
|
||||
cwd: None,
|
||||
model_provider: "test-provider".to_string(),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
memory_mode: ThreadMemoryMode::Enabled,
|
||||
},
|
||||
event_persistence_mode: ThreadEventPersistenceMode::Limited,
|
||||
@@ -762,6 +763,7 @@ mod tests {
|
||||
ThreadPersistenceMetadata {
|
||||
cwd: Some(std::env::current_dir().expect("cwd")),
|
||||
model_provider: "test-provider".to_string(),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
memory_mode: ThreadMemoryMode::Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,11 @@ pub(super) async fn read_thread(
|
||||
})?;
|
||||
|
||||
let mut thread = read_thread_from_rollout_path(store, path).await?;
|
||||
if !params.include_archived && thread.archived_at.is_some() {
|
||||
return Err(ThreadStoreError::InvalidRequest {
|
||||
message: format!("thread {thread_id} is archived"),
|
||||
});
|
||||
}
|
||||
attach_history_if_requested(&mut thread, params.include_history).await?;
|
||||
Ok(thread)
|
||||
}
|
||||
|
||||
@@ -523,6 +523,7 @@ mod tests {
|
||||
ThreadPersistenceMetadata {
|
||||
cwd: Some(std::env::current_dir().expect("cwd")),
|
||||
model_provider: "test-provider".to_string(),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
memory_mode: ThreadMemoryMode::Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,6 +350,7 @@ mod tests {
|
||||
let metadata = ThreadPersistenceMetadata {
|
||||
cwd: Some(PathBuf::from("/workspace")),
|
||||
model_provider: "test-provider".to_string(),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
memory_mode: ThreadMemoryMode::Enabled,
|
||||
};
|
||||
|
||||
@@ -382,6 +383,7 @@ mod tests {
|
||||
let metadata = ThreadPersistenceMetadata {
|
||||
cwd: Some(PathBuf::from("/workspace")),
|
||||
model_provider: "test-provider".to_string(),
|
||||
context_mode: codex_protocol::config_types::ContextMode::Default,
|
||||
memory_mode: ThreadMemoryMode::Disabled,
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::path::PathBuf;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::config_types::ContextMode;
|
||||
use codex_protocol::dynamic_tools::DynamicToolSpec;
|
||||
use codex_protocol::models::BaseInstructions;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
@@ -35,6 +36,8 @@ pub struct ThreadPersistenceMetadata {
|
||||
pub cwd: Option<PathBuf>,
|
||||
/// Model provider associated with the thread.
|
||||
pub model_provider: String,
|
||||
/// Context mode associated with the thread.
|
||||
pub context_mode: ContextMode,
|
||||
/// Memory mode associated with the live thread.
|
||||
pub memory_mode: MemoryMode,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user