mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
refactor: isolate code mode v8 runtime
This commit is contained in:
Generated
+16
-1
@@ -1914,6 +1914,7 @@ dependencies = [
|
||||
"codex-backend-client",
|
||||
"codex-chatgpt",
|
||||
"codex-cloud-config",
|
||||
"codex-code-mode-runtime",
|
||||
"codex-config",
|
||||
"codex-core",
|
||||
"codex-core-plugins",
|
||||
@@ -2428,12 +2429,24 @@ name = "codex-code-mode"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-protocol",
|
||||
"deno_core_icudata",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-code-mode-runtime"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-code-mode",
|
||||
"codex-protocol",
|
||||
"deno_core_icudata",
|
||||
"pretty_assertions",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"v8",
|
||||
]
|
||||
@@ -2526,6 +2539,7 @@ dependencies = [
|
||||
"codex-apply-patch",
|
||||
"codex-async-utils",
|
||||
"codex-code-mode",
|
||||
"codex-code-mode-runtime",
|
||||
"codex-config",
|
||||
"codex-connectors",
|
||||
"codex-core-plugins",
|
||||
@@ -3182,6 +3196,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"codex-arg0",
|
||||
"codex-code-mode-runtime",
|
||||
"codex-config",
|
||||
"codex-core",
|
||||
"codex-exec-server",
|
||||
|
||||
@@ -21,6 +21,7 @@ members = [
|
||||
"install-context",
|
||||
"codex-backend-openapi-models",
|
||||
"code-mode",
|
||||
"code-mode-runtime",
|
||||
"cloud-config",
|
||||
"cloud-tasks",
|
||||
"cloud-tasks-client",
|
||||
@@ -154,6 +155,7 @@ codex-cloud-config = { path = "cloud-config" }
|
||||
codex-cloud-tasks-client = { path = "cloud-tasks-client" }
|
||||
codex-cloud-tasks-mock-client = { path = "cloud-tasks-mock-client" }
|
||||
codex-code-mode = { path = "code-mode" }
|
||||
codex-code-mode-runtime = { path = "code-mode-runtime" }
|
||||
codex-config = { path = "config" }
|
||||
codex-connectors = { path = "connectors" }
|
||||
codex-core = { path = "core" }
|
||||
|
||||
@@ -33,6 +33,7 @@ axum = { workspace = true, default-features = false, features = [
|
||||
codex-analytics = { workspace = true }
|
||||
codex-arg0 = { workspace = true }
|
||||
codex-cloud-config = { workspace = true }
|
||||
codex-code-mode-runtime = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-core-plugins = { workspace = true }
|
||||
|
||||
@@ -187,6 +187,7 @@ mod tests {
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(EnvironmentManager::default_for_tests()),
|
||||
Arc::new(codex_code_mode_runtime::InProcessCodeModeSessionProvider),
|
||||
thread_extensions(
|
||||
guardian_agent_spawner(thread_manager.clone()),
|
||||
Arc::new(NoopExtensionEventSink),
|
||||
|
||||
@@ -311,6 +311,7 @@ impl MessageProcessor {
|
||||
auth_manager.clone(),
|
||||
session_source,
|
||||
environment_manager,
|
||||
Arc::new(codex_code_mode_runtime::InProcessCodeModeSessionProvider),
|
||||
thread_extensions(
|
||||
guardian_agent_spawner(thread_manager.clone()),
|
||||
app_server_extension_event_sink(outgoing.clone()),
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
load("//:defs.bzl", "codex_rust_crate")
|
||||
|
||||
codex_rust_crate(
|
||||
name = "code-mode-runtime",
|
||||
crate_name = "codex_code_mode_runtime",
|
||||
crate_features = select({
|
||||
"@rules_rs//rs/experimental/platforms/constraints:windows_msvc": [],
|
||||
"//conditions:default": ["sandbox"],
|
||||
}),
|
||||
deps_extra = ["@crates//:v8"],
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
name = "codex-code-mode-runtime"
|
||||
version.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
name = "codex_code_mode_runtime"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
sandbox = ["v8/v8_enable_sandbox"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
codex-code-mode = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
deno_core_icudata = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt", "sync", "time"] }
|
||||
tokio-util = { workspace = true, features = ["rt"] }
|
||||
tracing = { workspace = true }
|
||||
v8 = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = { workspace = true }
|
||||
@@ -0,0 +1,6 @@
|
||||
mod runtime;
|
||||
mod service;
|
||||
|
||||
pub use codex_code_mode::*;
|
||||
pub use service::CodeModeService;
|
||||
pub use service::InProcessCodeModeSessionProvider;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use crate::response::FunctionCallOutputContentItem;
|
||||
use crate::FunctionCallOutputContentItem;
|
||||
|
||||
use super::EXIT_SENTINEL;
|
||||
use super::RuntimeEvent;
|
||||
+6
-113
@@ -10,124 +10,17 @@ use std::sync::mpsc as std_mpsc;
|
||||
use std::thread;
|
||||
|
||||
use codex_protocol::ToolName;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::description::CodeModeToolKind;
|
||||
use crate::description::EnabledToolMetadata;
|
||||
use crate::description::ToolDefinition;
|
||||
use crate::description::enabled_tool_metadata;
|
||||
use crate::response::FunctionCallOutputContentItem;
|
||||
use crate::service::CellId;
|
||||
|
||||
pub const DEFAULT_EXEC_YIELD_TIME_MS: u64 = 10_000;
|
||||
pub const DEFAULT_WAIT_YIELD_TIME_MS: u64 = 10_000;
|
||||
pub const DEFAULT_MAX_OUTPUT_TOKENS_PER_EXEC_CALL: usize = 10_000;
|
||||
use crate::EnabledToolMetadata;
|
||||
use crate::enabled_tool_metadata;
|
||||
pub(crate) use codex_code_mode::CodeModeToolKind;
|
||||
pub(crate) use codex_code_mode::ExecuteRequest;
|
||||
pub(crate) use codex_code_mode::FunctionCallOutputContentItem;
|
||||
pub(crate) use codex_code_mode::ToolDefinition;
|
||||
const EXIT_SENTINEL: &str = "__codex_code_mode_exit__";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExecuteRequest {
|
||||
pub tool_call_id: String,
|
||||
pub enabled_tools: Vec<ToolDefinition>,
|
||||
pub source: String,
|
||||
pub yield_time_ms: Option<u64>,
|
||||
pub max_output_tokens: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WaitRequest {
|
||||
pub cell_id: CellId,
|
||||
pub yield_time_ms: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WaitToPendingRequest {
|
||||
pub cell_id: CellId,
|
||||
}
|
||||
|
||||
/// Result of waiting on a code-mode cell.
|
||||
///
|
||||
/// The wrapped `RuntimeResponse` is the model-facing wait result. The enum
|
||||
/// variant carries the extra lifecycle provenance that `RuntimeResponse` cannot:
|
||||
/// a failed real cell and a missing-cell wait both use
|
||||
/// `RuntimeResponse::Result { error_text: Some(..), .. }`, but only the former
|
||||
/// should be treated as a code-cell lifecycle event.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum WaitOutcome {
|
||||
/// The requested code cell was live when the wait command was accepted.
|
||||
LiveCell(RuntimeResponse),
|
||||
/// The requested code cell was not live.
|
||||
MissingCell(RuntimeResponse),
|
||||
}
|
||||
|
||||
/// Result of executing a code-mode cell until it either completes or reaches a
|
||||
/// quiescent pending state.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ExecuteToPendingOutcome {
|
||||
/// The cell is waiting for more runtime input after draining the runtime
|
||||
/// input queue that was ready at the pending boundary.
|
||||
Pending {
|
||||
cell_id: CellId,
|
||||
content_items: Vec<FunctionCallOutputContentItem>,
|
||||
/// Runtime tool-call ids emitted before this paused execution frontier
|
||||
/// sealed. Hosts can use these ids to drain their tool-call transport
|
||||
/// before surfacing the pending boundary to callers.
|
||||
pending_tool_call_ids: Vec<String>,
|
||||
},
|
||||
/// The cell reached a terminal runtime response before going pending.
|
||||
Completed(RuntimeResponse),
|
||||
}
|
||||
|
||||
/// Result of resuming a live code-mode cell until it completes or becomes
|
||||
/// quiescent again.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum WaitToPendingOutcome {
|
||||
/// The requested code cell was live when the wait command was accepted.
|
||||
LiveCell(ExecuteToPendingOutcome),
|
||||
/// The requested code cell was not live.
|
||||
MissingCell(RuntimeResponse),
|
||||
}
|
||||
|
||||
impl From<WaitOutcome> for RuntimeResponse {
|
||||
fn from(outcome: WaitOutcome) -> Self {
|
||||
match outcome {
|
||||
WaitOutcome::LiveCell(response) | WaitOutcome::MissingCell(response) => response,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize)]
|
||||
pub enum RuntimeResponse {
|
||||
Yielded {
|
||||
cell_id: CellId,
|
||||
content_items: Vec<FunctionCallOutputContentItem>,
|
||||
},
|
||||
Terminated {
|
||||
cell_id: CellId,
|
||||
content_items: Vec<FunctionCallOutputContentItem>,
|
||||
},
|
||||
Result {
|
||||
cell_id: CellId,
|
||||
content_items: Vec<FunctionCallOutputContentItem>,
|
||||
error_text: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Nested tool request emitted by one code-mode cell.
|
||||
///
|
||||
/// Code mode owns the per-cell runtime id. Hosts should preserve it for
|
||||
/// provenance/debugging, but should still assign their own runtime tool call id
|
||||
/// if their tool-call graph requires globally unique ids.
|
||||
#[derive(Debug)]
|
||||
pub struct CodeModeNestedToolCall {
|
||||
pub cell_id: CellId,
|
||||
pub runtime_tool_call_id: String,
|
||||
pub tool_name: ToolName,
|
||||
pub tool_kind: CodeModeToolKind,
|
||||
pub input: Option<JsonValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum RuntimeCommand {
|
||||
ToolResponse { id: String, result: JsonValue },
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::response::DEFAULT_IMAGE_DETAIL;
|
||||
use crate::response::FunctionCallOutputContentItem;
|
||||
use crate::response::ImageDetail;
|
||||
use crate::DEFAULT_IMAGE_DETAIL;
|
||||
use crate::FunctionCallOutputContentItem;
|
||||
use crate::ImageDetail;
|
||||
|
||||
const IMAGE_HELPER_EXPECTS_MESSAGE: &str = "image expects a non-empty image URL string, an object with image_url and optional detail, or a raw MCP image block";
|
||||
const CODEX_IMAGE_DETAIL_META_KEY: &str = "codex/imageDetail";
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,21 +9,15 @@ doctest = false
|
||||
name = "codex_code_mode"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
sandbox = ["v8/v8_enable_sandbox"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
codex-protocol = { workspace = true }
|
||||
deno_core_icudata = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt", "sync", "time"] }
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
tokio-util = { workspace = true, features = ["rt"] }
|
||||
tracing = { workspace = true }
|
||||
v8 = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = { workspace = true }
|
||||
|
||||
@@ -5,11 +5,15 @@ mod service;
|
||||
|
||||
pub use description::CODE_MODE_PRAGMA_PREFIX;
|
||||
pub use description::CodeModeToolKind;
|
||||
#[doc(hidden)]
|
||||
pub use description::EnabledToolMetadata;
|
||||
pub use description::ToolDefinition;
|
||||
pub use description::ToolNamespaceDescription;
|
||||
pub use description::augment_tool_definition;
|
||||
pub use description::build_exec_tool_description;
|
||||
pub use description::build_wait_tool_description;
|
||||
#[doc(hidden)]
|
||||
pub use description::enabled_tool_metadata;
|
||||
pub use description::is_code_mode_nested_tool;
|
||||
pub use description::normalize_code_mode_identifier;
|
||||
pub use description::parse_exec_source;
|
||||
@@ -36,11 +40,11 @@ pub use service::CodeModeSessionDelegate;
|
||||
pub use service::CodeModeSessionProvider;
|
||||
pub use service::CodeModeSessionProviderFuture;
|
||||
pub use service::CodeModeSessionResultFuture;
|
||||
pub use service::InProcessCodeModeSessionProvider;
|
||||
pub use service::NoopCodeModeSessionDelegate;
|
||||
pub use service::NotificationFuture;
|
||||
pub use service::StartedCell;
|
||||
pub use service::ToolInvocationFuture;
|
||||
pub use service::UnavailableCodeModeSessionProvider;
|
||||
|
||||
pub const PUBLIC_TOOL_NAME: &str = "exec";
|
||||
pub const WAIT_TOOL_NAME: &str = "wait";
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
use codex_protocol::ToolName;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::CellId;
|
||||
use crate::CodeModeToolKind;
|
||||
use crate::FunctionCallOutputContentItem;
|
||||
use crate::ToolDefinition;
|
||||
|
||||
pub const DEFAULT_EXEC_YIELD_TIME_MS: u64 = 10_000;
|
||||
pub const DEFAULT_WAIT_YIELD_TIME_MS: u64 = 10_000;
|
||||
pub const DEFAULT_MAX_OUTPUT_TOKENS_PER_EXEC_CALL: usize = 10_000;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExecuteRequest {
|
||||
pub tool_call_id: String,
|
||||
pub enabled_tools: Vec<ToolDefinition>,
|
||||
pub source: String,
|
||||
pub yield_time_ms: Option<u64>,
|
||||
pub max_output_tokens: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WaitRequest {
|
||||
pub cell_id: CellId,
|
||||
pub yield_time_ms: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WaitToPendingRequest {
|
||||
pub cell_id: CellId,
|
||||
}
|
||||
|
||||
/// Result of waiting on a code-mode cell.
|
||||
///
|
||||
/// The wrapped `RuntimeResponse` is the model-facing wait result. The enum
|
||||
/// variant carries the extra lifecycle provenance that `RuntimeResponse` cannot:
|
||||
/// a failed real cell and a missing-cell wait both use
|
||||
/// `RuntimeResponse::Result { error_text: Some(..), .. }`, but only the former
|
||||
/// should be treated as a code-cell lifecycle event.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum WaitOutcome {
|
||||
/// The requested code cell was live when the wait command was accepted.
|
||||
LiveCell(RuntimeResponse),
|
||||
/// The requested code cell was not live.
|
||||
MissingCell(RuntimeResponse),
|
||||
}
|
||||
|
||||
/// Result of executing a code-mode cell until it either completes or reaches a
|
||||
/// quiescent pending state.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ExecuteToPendingOutcome {
|
||||
/// The cell is waiting for more runtime input after draining the runtime
|
||||
/// input queue that was ready at the pending boundary.
|
||||
Pending {
|
||||
cell_id: CellId,
|
||||
content_items: Vec<FunctionCallOutputContentItem>,
|
||||
/// Runtime tool-call ids emitted before this paused execution frontier
|
||||
/// sealed. Hosts can use these ids to drain their tool-call transport
|
||||
/// before surfacing the pending boundary to callers.
|
||||
pending_tool_call_ids: Vec<String>,
|
||||
},
|
||||
/// The cell reached a terminal runtime response before going pending.
|
||||
Completed(RuntimeResponse),
|
||||
}
|
||||
|
||||
/// Result of resuming a live code-mode cell until it completes or becomes
|
||||
/// quiescent again.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum WaitToPendingOutcome {
|
||||
/// The requested code cell was live when the wait command was accepted.
|
||||
LiveCell(ExecuteToPendingOutcome),
|
||||
/// The requested code cell was not live.
|
||||
MissingCell(RuntimeResponse),
|
||||
}
|
||||
|
||||
impl From<WaitOutcome> for RuntimeResponse {
|
||||
fn from(outcome: WaitOutcome) -> Self {
|
||||
match outcome {
|
||||
WaitOutcome::LiveCell(response) | WaitOutcome::MissingCell(response) => response,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize)]
|
||||
pub enum RuntimeResponse {
|
||||
Yielded {
|
||||
cell_id: CellId,
|
||||
content_items: Vec<FunctionCallOutputContentItem>,
|
||||
},
|
||||
Terminated {
|
||||
cell_id: CellId,
|
||||
content_items: Vec<FunctionCallOutputContentItem>,
|
||||
},
|
||||
Result {
|
||||
cell_id: CellId,
|
||||
content_items: Vec<FunctionCallOutputContentItem>,
|
||||
error_text: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Nested tool request emitted by one code-mode cell.
|
||||
///
|
||||
/// Code mode owns the per-cell runtime id. Hosts should preserve it for
|
||||
/// provenance/debugging, but should still assign their own runtime tool call id
|
||||
/// if their tool-call graph requires globally unique ids.
|
||||
#[derive(Debug)]
|
||||
pub struct CodeModeNestedToolCall {
|
||||
pub cell_id: CellId,
|
||||
pub runtime_tool_call_id: String,
|
||||
pub tool_name: ToolName,
|
||||
pub tool_kind: CodeModeToolKind,
|
||||
pub input: Option<JsonValue>,
|
||||
}
|
||||
+22
-1697
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@ pub use codex_config::types::TuiKeymap;
|
||||
pub use codex_config::types::TuiNotificationSettings;
|
||||
pub use codex_config::types::TuiPetAnchor;
|
||||
pub use codex_config::types::UriBasedFileOpener;
|
||||
pub use codex_core::CodeModeSessionProvider;
|
||||
pub use codex_core::CodexThread;
|
||||
pub use codex_core::ForkSnapshot;
|
||||
pub use codex_core::McpManager;
|
||||
|
||||
@@ -132,6 +132,7 @@ codex-shell-escalation = { workspace = true }
|
||||
[dev-dependencies]
|
||||
assert_cmd = { workspace = true }
|
||||
assert_matches = { workspace = true }
|
||||
codex-code-mode-runtime = { workspace = true }
|
||||
codex-otel = { workspace = true }
|
||||
codex-test-binary-support = { workspace = true }
|
||||
codex-utils-cargo-bin = { workspace = true }
|
||||
|
||||
@@ -89,6 +89,7 @@ pub(crate) async fn run_codex_thread_interactive(
|
||||
plugins_manager: Arc::clone(&parent_session.services.plugins_manager),
|
||||
mcp_manager: Arc::clone(&parent_session.services.mcp_manager),
|
||||
extensions: Arc::clone(&parent_session.services.extensions),
|
||||
code_mode_session_provider: Arc::clone(&parent_session.services.code_mode_session_provider),
|
||||
conversation_history,
|
||||
session_source: SessionSource::SubAgent(subagent_source.clone()),
|
||||
forked_from_thread_id,
|
||||
|
||||
@@ -104,6 +104,7 @@ pub use client::X_RESPONSESAPI_INCLUDE_TIMING_METRICS_HEADER;
|
||||
pub use codex_protocol::config_types::ModelProviderAuthInfo;
|
||||
mod event_mapping;
|
||||
pub mod review_format;
|
||||
pub use codex_code_mode::CodeModeSessionProvider;
|
||||
pub use codex_prompts as review_prompts;
|
||||
mod thread_manager;
|
||||
pub(crate) mod web_search;
|
||||
|
||||
@@ -40,7 +40,7 @@ pub async fn build_prompt_input(
|
||||
|
||||
let thread_store = thread_store_from_config(&config, state_db.clone());
|
||||
let installation_id = resolve_installation_id(&config.codex_home).await?;
|
||||
let thread_manager = ThreadManager::new(
|
||||
let thread_manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
Arc::clone(&auth_manager),
|
||||
SessionSource::Exec,
|
||||
|
||||
@@ -314,6 +314,7 @@ use crate::turn_timing::TurnTimingState;
|
||||
use crate::turn_timing::record_turn_ttfm_metric;
|
||||
use crate::unified_exec::UnifiedExecProcessManager;
|
||||
use crate::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_code_mode::CodeModeSessionProvider;
|
||||
use codex_core_plugins::PluginsManager;
|
||||
use codex_git_utils::get_git_repo_root;
|
||||
use codex_mcp::compute_auth_statuses;
|
||||
@@ -399,6 +400,7 @@ pub(crate) struct CodexSpawnArgs {
|
||||
pub(crate) plugins_manager: Arc<PluginsManager>,
|
||||
pub(crate) mcp_manager: Arc<McpManager>,
|
||||
pub(crate) extensions: Arc<codex_extension_api::ExtensionRegistry<crate::config::Config>>,
|
||||
pub(crate) code_mode_session_provider: Arc<dyn CodeModeSessionProvider>,
|
||||
pub(crate) conversation_history: InitialHistory,
|
||||
pub(crate) session_source: SessionSource,
|
||||
pub(crate) forked_from_thread_id: Option<ThreadId>,
|
||||
@@ -483,6 +485,7 @@ impl Codex {
|
||||
plugins_manager,
|
||||
mcp_manager,
|
||||
extensions,
|
||||
code_mode_session_provider,
|
||||
conversation_history,
|
||||
session_source,
|
||||
forked_from_thread_id,
|
||||
|
||||
@@ -1051,7 +1051,10 @@ impl Session {
|
||||
session_configuration.parent_thread_id,
|
||||
),
|
||||
),
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(),
|
||||
code_mode_session_provider: Arc::clone(&code_mode_session_provider),
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(
|
||||
code_mode_session_provider,
|
||||
),
|
||||
environment_manager,
|
||||
};
|
||||
services
|
||||
|
||||
@@ -4778,7 +4778,10 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
Session::build_model_client_beta_features_header(config.as_ref()),
|
||||
/*attestation_provider*/ None,
|
||||
),
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(),
|
||||
code_mode_session_provider: Arc::new(codex_code_mode::UnavailableCodeModeSessionProvider),
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(Arc::new(
|
||||
codex_code_mode::UnavailableCodeModeSessionProvider,
|
||||
)),
|
||||
environment_manager: Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
};
|
||||
|
||||
@@ -6868,7 +6871,10 @@ where
|
||||
Session::build_model_client_beta_features_header(config.as_ref()),
|
||||
/*attestation_provider*/ None,
|
||||
),
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(),
|
||||
code_mode_session_provider: Arc::new(codex_code_mode::UnavailableCodeModeSessionProvider),
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(Arc::new(
|
||||
codex_code_mode::UnavailableCodeModeSessionProvider,
|
||||
)),
|
||||
environment_manager: Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
};
|
||||
|
||||
|
||||
@@ -713,6 +713,7 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() {
|
||||
plugins_manager,
|
||||
mcp_manager,
|
||||
extensions: codex_extension_api::empty_extension_registry(),
|
||||
code_mode_session_provider: Arc::new(codex_code_mode::UnavailableCodeModeSessionProvider),
|
||||
conversation_history: InitialHistory::New,
|
||||
session_source: SessionSource::SubAgent(SubAgentSource::Other(
|
||||
GUARDIAN_REVIEWER_NAME.to_string(),
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::unified_exec::UnifiedExecProcessManager;
|
||||
use arc_swap::ArcSwap;
|
||||
use arc_swap::ArcSwapOption;
|
||||
use codex_analytics::AnalyticsEventsClient;
|
||||
use codex_code_mode::CodeModeSessionProvider;
|
||||
use codex_core_plugins::PluginsManager;
|
||||
use codex_exec_server::EnvironmentManager;
|
||||
use codex_extension_api::ExtensionData;
|
||||
@@ -77,6 +78,7 @@ pub(crate) struct SessionServices {
|
||||
pub(crate) attestation_provider: Option<Arc<dyn AttestationProvider>>,
|
||||
/// Session-scoped model client shared across turns.
|
||||
pub(crate) model_client: ModelClient,
|
||||
pub(crate) code_mode_session_provider: Arc<dyn CodeModeSessionProvider>,
|
||||
pub(crate) code_mode_service: CodeModeService,
|
||||
/// Shared process-level environment registry. Sessions carry an `Arc` handle so they can pass
|
||||
/// the same manager through child-thread spawn paths without reconstructing it.
|
||||
|
||||
@@ -19,6 +19,8 @@ use crate::tasks::interrupted_turn_history_marker;
|
||||
use codex_analytics::AnalyticsEventsClient;
|
||||
use codex_app_server_protocol::ThreadHistoryBuilder;
|
||||
use codex_app_server_protocol::TurnStatus;
|
||||
use codex_code_mode::CodeModeSessionProvider;
|
||||
use codex_code_mode::UnavailableCodeModeSessionProvider;
|
||||
use codex_core_plugins::PluginsManager;
|
||||
use codex_exec_server::EnvironmentManager;
|
||||
use codex_extension_api::ExtensionRegistry;
|
||||
@@ -208,6 +210,7 @@ pub(crate) struct ThreadManagerState {
|
||||
mcp_manager: Arc<McpManager>,
|
||||
extensions: Arc<ExtensionRegistry<Config>>,
|
||||
thread_store: Arc<dyn ThreadStore>,
|
||||
code_mode_session_provider: Arc<dyn CodeModeSessionProvider>,
|
||||
attestation_provider: Option<Arc<dyn AttestationProvider>>,
|
||||
session_source: SessionSource,
|
||||
installation_id: String,
|
||||
@@ -256,6 +259,7 @@ impl ThreadManager {
|
||||
auth_manager: Arc<AuthManager>,
|
||||
session_source: SessionSource,
|
||||
environment_manager: Arc<EnvironmentManager>,
|
||||
code_mode_session_provider: Arc<dyn CodeModeSessionProvider>,
|
||||
extensions: Arc<ExtensionRegistry<Config>>,
|
||||
analytics_events_client: Option<AnalyticsEventsClient>,
|
||||
thread_store: Arc<dyn ThreadStore>,
|
||||
@@ -287,6 +291,7 @@ impl ThreadManager {
|
||||
mcp_manager,
|
||||
extensions,
|
||||
thread_store,
|
||||
code_mode_session_provider,
|
||||
attestation_provider,
|
||||
auth_manager,
|
||||
session_source,
|
||||
@@ -300,6 +305,34 @@ impl ThreadManager {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new_without_code_mode_runtime(
|
||||
config: &Config,
|
||||
auth_manager: Arc<AuthManager>,
|
||||
session_source: SessionSource,
|
||||
environment_manager: Arc<EnvironmentManager>,
|
||||
extensions: Arc<ExtensionRegistry<Config>>,
|
||||
analytics_events_client: Option<AnalyticsEventsClient>,
|
||||
thread_store: Arc<dyn ThreadStore>,
|
||||
state_db: Option<StateDbHandle>,
|
||||
installation_id: String,
|
||||
attestation_provider: Option<Arc<dyn AttestationProvider>>,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
config,
|
||||
auth_manager,
|
||||
session_source,
|
||||
environment_manager,
|
||||
Arc::new(UnavailableCodeModeSessionProvider),
|
||||
extensions,
|
||||
analytics_events_client,
|
||||
thread_store,
|
||||
state_db,
|
||||
installation_id,
|
||||
attestation_provider,
|
||||
)
|
||||
}
|
||||
|
||||
/// Construct with a dummy AuthManager containing the provided CodexAuth.
|
||||
/// Used for integration tests: should not be used by ordinary business logic.
|
||||
pub(crate) fn with_models_provider_for_tests(
|
||||
@@ -388,6 +421,7 @@ impl ThreadManager {
|
||||
mcp_manager,
|
||||
extensions: empty_extension_registry(),
|
||||
thread_store,
|
||||
code_mode_session_provider: Arc::new(UnavailableCodeModeSessionProvider),
|
||||
attestation_provider: None,
|
||||
auth_manager,
|
||||
session_source: SessionSource::Exec,
|
||||
@@ -1318,6 +1352,7 @@ impl ThreadManagerState {
|
||||
plugins_manager: Arc::clone(&self.plugins_manager),
|
||||
mcp_manager: Arc::clone(&self.mcp_manager),
|
||||
extensions: Arc::clone(&self.extensions),
|
||||
code_mode_session_provider: Arc::clone(&self.code_mode_session_provider),
|
||||
conversation_history: initial_history,
|
||||
session_source,
|
||||
forked_from_thread_id,
|
||||
|
||||
@@ -489,7 +489,7 @@ async fn resume_and_fork_do_not_restore_thread_environments_from_rollout() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
@@ -605,7 +605,7 @@ async fn explicit_installation_id_skips_codex_home_file() {
|
||||
let installation_id = uuid::Uuid::new_v4().to_string();
|
||||
let state_db = init_state_db(&config).await;
|
||||
let thread_store = thread_store_from_config(&config, state_db.clone());
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager,
|
||||
SessionSource::Exec,
|
||||
@@ -644,7 +644,7 @@ async fn resume_active_thread_from_rollout_returns_running_thread() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
@@ -701,7 +701,7 @@ async fn resume_stopped_thread_from_rollout_spawns_new_thread() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
@@ -765,7 +765,7 @@ async fn resume_stopped_thread_from_rollout_preserves_thread_source() {
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let state_db = init_state_db(&config).await;
|
||||
let thread_store = thread_store_from_config(&config, state_db.clone());
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
@@ -854,7 +854,7 @@ async fn rollout_path_resume_and_fork_read_history_through_thread_store() {
|
||||
.as_any()
|
||||
.downcast_ref::<InMemoryThreadStore>()
|
||||
.expect("configured in-memory store");
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
@@ -955,7 +955,7 @@ async fn new_uses_active_provider_for_model_refresh() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager,
|
||||
SessionSource::Exec,
|
||||
@@ -1175,7 +1175,7 @@ async fn interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_histor
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
@@ -1281,7 +1281,7 @@ async fn interrupted_fork_snapshot_preserves_explicit_turn_id() {
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
@@ -1377,7 +1377,7 @@ async fn interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
@@ -1517,7 +1517,7 @@ async fn resumed_thread_keeps_paused_goal_paused() -> anyhow::Result<()> {
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
|
||||
@@ -11,10 +11,12 @@ use std::time::Duration;
|
||||
use codex_code_mode::CellId;
|
||||
use codex_code_mode::CodeModeNestedToolCall;
|
||||
use codex_code_mode::CodeModeSession;
|
||||
use codex_code_mode::CodeModeSessionProvider;
|
||||
use codex_code_mode::CodeModeToolKind;
|
||||
use codex_code_mode::RuntimeResponse;
|
||||
use codex_protocol::models::FunctionCallOutputContentItem;
|
||||
use serde_json::Value as JsonValue;
|
||||
use tokio::sync::OnceCell;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use crate::function_tool::FunctionCallError;
|
||||
@@ -58,17 +60,17 @@ pub(crate) struct ExecContext {
|
||||
}
|
||||
|
||||
pub(crate) struct CodeModeService {
|
||||
session: Option<Arc<dyn CodeModeSession>>,
|
||||
session: OnceCell<Arc<dyn CodeModeSession>>,
|
||||
session_provider: Arc<dyn CodeModeSessionProvider>,
|
||||
dispatch_broker: Arc<CodeModeDispatchBroker>,
|
||||
}
|
||||
|
||||
impl CodeModeService {
|
||||
pub(crate) fn new() -> Self {
|
||||
pub(crate) fn new(session_provider: Arc<dyn CodeModeSessionProvider>) -> Self {
|
||||
let dispatch_broker = Arc::new(CodeModeDispatchBroker::new());
|
||||
Self {
|
||||
session: Some(Arc::new(codex_code_mode::CodeModeService::with_delegate(
|
||||
dispatch_broker.clone(),
|
||||
))),
|
||||
session: OnceCell::new(),
|
||||
session_provider,
|
||||
dispatch_broker,
|
||||
}
|
||||
}
|
||||
@@ -77,25 +79,25 @@ impl CodeModeService {
|
||||
&self,
|
||||
request: codex_code_mode::ExecuteRequest,
|
||||
) -> Result<codex_code_mode::StartedCell, String> {
|
||||
self.session()?.execute(request).await
|
||||
self.session().await?.execute(request).await
|
||||
}
|
||||
|
||||
pub(crate) async fn wait(
|
||||
&self,
|
||||
request: codex_code_mode::WaitRequest,
|
||||
) -> Result<codex_code_mode::WaitOutcome, String> {
|
||||
self.session()?.wait(request).await
|
||||
self.session().await?.wait(request).await
|
||||
}
|
||||
|
||||
pub(crate) async fn terminate(
|
||||
&self,
|
||||
cell_id: CellId,
|
||||
) -> Result<codex_code_mode::WaitOutcome, String> {
|
||||
self.session()?.terminate(cell_id).await
|
||||
self.session().await?.terminate(cell_id).await
|
||||
}
|
||||
|
||||
pub(crate) async fn shutdown(&self) -> Result<(), String> {
|
||||
match &self.session {
|
||||
match self.session.get() {
|
||||
Some(session) => session.shutdown().await,
|
||||
None => Ok(()),
|
||||
}
|
||||
@@ -116,9 +118,7 @@ impl CodeModeService {
|
||||
router: Arc<ToolRouter>,
|
||||
tracker: SharedTurnDiffTracker,
|
||||
) -> Option<CodeModeDispatchWorker> {
|
||||
if !matches!(turn.tool_mode, ToolMode::CodeMode | ToolMode::CodeModeOnly)
|
||||
|| self.session.is_none()
|
||||
{
|
||||
if !matches!(turn.tool_mode, ToolMode::CodeMode | ToolMode::CodeModeOnly) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -132,10 +132,13 @@ impl CodeModeService {
|
||||
)
|
||||
}
|
||||
|
||||
fn session(&self) -> Result<&Arc<dyn CodeModeSession>, String> {
|
||||
async fn session(&self) -> Result<&Arc<dyn CodeModeSession>, String> {
|
||||
self.session
|
||||
.as_ref()
|
||||
.ok_or_else(|| "code mode is unavailable".to_string())
|
||||
.get_or_try_init(|| {
|
||||
self.session_provider
|
||||
.create_session(self.dispatch_broker.clone())
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3982,7 +3982,7 @@ async fn tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtr
|
||||
.enable(Feature::Sqlite)
|
||||
.expect("test config should allow sqlite");
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
let manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
AuthManager::from_auth_for_testing(CodexAuth::from_api_key("dummy")),
|
||||
SessionSource::Exec,
|
||||
|
||||
@@ -473,6 +473,7 @@ impl TestCodexBuilder {
|
||||
codex_core::test_support::auth_manager_from_auth(auth.clone()),
|
||||
SessionSource::Exec,
|
||||
Arc::clone(&environment_manager),
|
||||
Arc::new(codex_code_mode_runtime::InProcessCodeModeSessionProvider),
|
||||
empty_extension_registry(),
|
||||
/*analytics_events_client*/ None,
|
||||
thread_store,
|
||||
|
||||
@@ -1131,7 +1131,7 @@ async fn prefers_apikey_when_config_prefers_apikey_even_with_chatgpt_tokens() {
|
||||
let installation_id = resolve_installation_id(&config.codex_home)
|
||||
.await
|
||||
.expect("resolve installation id");
|
||||
let thread_manager = ThreadManager::new(
|
||||
let thread_manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager,
|
||||
SessionSource::Exec,
|
||||
|
||||
@@ -19,6 +19,7 @@ workspace = true
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
codex-arg0 = { workspace = true }
|
||||
codex-code-mode-runtime = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-exec-server = { workspace = true }
|
||||
|
||||
@@ -67,6 +67,7 @@ impl MessageProcessor {
|
||||
auth_manager,
|
||||
SessionSource::Mcp,
|
||||
environment_manager,
|
||||
Arc::new(codex_code_mode_runtime::InProcessCodeModeSessionProvider),
|
||||
empty_extension_registry(),
|
||||
/*analytics_events_client*/ None,
|
||||
codex_core::thread_store_from_config(config.as_ref(), state_db.clone()),
|
||||
|
||||
@@ -120,7 +120,7 @@ async fn run_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
|
||||
.await?,
|
||||
);
|
||||
let installation_id = resolve_installation_id(&config.codex_home).await?;
|
||||
let thread_manager = ThreadManager::new(
|
||||
let thread_manager = ThreadManager::new_without_code_mode_runtime(
|
||||
&config,
|
||||
auth_manager,
|
||||
SessionSource::Exec,
|
||||
|
||||
Reference in New Issue
Block a user