Skip to content
3 changes: 3 additions & 0 deletions codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions codex-rs/app-server-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ workspace = true
codex-app-server = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-arg0 = { workspace = true }
codex-config = { workspace = true }
codex-core = { workspace = true }
codex-exec-server = { workspace = true }
codex-feedback = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/app-server-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use codex_app_server_protocol::Result as JsonRpcResult;
use codex_app_server_protocol::ServerNotification;
use codex_app_server_protocol::ServerRequest;
use codex_arg0::Arg0DispatchPaths;
use codex_config::NoopThreadConfigLoader;
use codex_core::config::Config;
use codex_core::config_loader::CloudRequirementsLoader;
use codex_core::config_loader::LoaderOverrides;
Expand Down Expand Up @@ -385,6 +386,7 @@ impl InProcessClientStartArgs {
cli_overrides: self.cli_overrides,
loader_overrides: self.loader_overrides,
cloud_requirements: self.cloud_requirements,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this "cloud requirements" value being passed through the config stack is confusingly named -- I think this is like enterprise config requirements sent down from the cloud? But it seems likely we'll trip on it.

thread_config_loader: Arc::new(NoopThreadConfigLoader),
feedback: self.feedback,
log_db: self.log_db,
environment_manager: self.environment_manager,
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ axum = { workspace = true, default-features = false, features = [
"tokio",
] }
core_test_support = { workspace = true }
codex-model-provider-info = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
opentelemetry = { workspace = true }
opentelemetry_sdk = { workspace = true }
Expand Down
77 changes: 77 additions & 0 deletions codex-rs/app-server/src/codex_message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ use codex_backend_client::AddCreditsNudgeCreditType as BackendAddCreditsNudgeCre
use codex_backend_client::Client as BackendClient;
use codex_chatgpt::connectors;
use codex_cloud_requirements::cloud_requirements_loader;
use codex_config::ThreadConfigLoader;
use codex_config::types::McpServerTransportConfig;
use codex_core::CodexThread;
use codex_core::ForkSnapshot;
Expand Down Expand Up @@ -478,6 +479,7 @@ pub(crate) struct CodexMessageProcessor {
cli_overrides: Arc<RwLock<Vec<(String, TomlValue)>>>,
runtime_feature_enablement: Arc<RwLock<BTreeMap<String, bool>>>,
cloud_requirements: Arc<RwLock<CloudRequirementsLoader>>,
thread_config_loader: Arc<dyn ThreadConfigLoader>,
active_login: Arc<Mutex<Option<ActiveLogin>>>,
pending_thread_unloads: Arc<Mutex<HashSet<ThreadId>>>,
thread_state_manager: ThreadStateManager,
Expand Down Expand Up @@ -638,6 +640,7 @@ pub(crate) struct CodexMessageProcessorArgs {
pub(crate) cli_overrides: Arc<RwLock<Vec<(String, TomlValue)>>>,
pub(crate) runtime_feature_enablement: Arc<RwLock<BTreeMap<String, bool>>>,
pub(crate) cloud_requirements: Arc<RwLock<CloudRequirementsLoader>>,
pub(crate) thread_config_loader: Arc<dyn ThreadConfigLoader>,
pub(crate) feedback: CodexFeedback,
pub(crate) log_db: Option<LogDbLayer>,
}
Expand Down Expand Up @@ -716,6 +719,7 @@ impl CodexMessageProcessor {
cli_overrides,
runtime_feature_enablement,
cloud_requirements,
thread_config_loader,
feedback,
log_db,
} = args;
Expand All @@ -730,6 +734,7 @@ impl CodexMessageProcessor {
cli_overrides,
runtime_feature_enablement,
cloud_requirements,
thread_config_loader,
active_login: Arc::new(Mutex::new(None)),
pending_thread_unloads: Arc::new(Mutex::new(HashSet::new())),
thread_state_manager: ThreadStateManager::new(),
Expand Down Expand Up @@ -2423,12 +2428,14 @@ impl CodexMessageProcessor {
};
let request_trace = request_context.request_trace();
let runtime_feature_enablement = self.current_runtime_feature_enablement();
let thread_config_loader = Arc::clone(&self.thread_config_loader);
let thread_start_task = async move {
Self::thread_start_task(
listener_task_context,
cli_overrides,
runtime_feature_enablement,
cloud_requirements,
thread_config_loader,
request_id,
app_server_client_name,
app_server_client_version,
Expand Down Expand Up @@ -2505,6 +2512,7 @@ impl CodexMessageProcessor {
cli_overrides: Vec<(String, TomlValue)>,
runtime_feature_enablement: BTreeMap<String, bool>,
cloud_requirements: CloudRequirementsLoader,
thread_config_loader: Arc<dyn ThreadConfigLoader>,
request_id: ConnectionRequestId,
app_server_client_name: Option<String>,
app_server_client_version: Option<String>,
Expand All @@ -2522,6 +2530,7 @@ impl CodexMessageProcessor {
&cli_overrides,
config_overrides.clone(),
typesafe_overrides.clone(),
Arc::clone(&thread_config_loader),
&cloud_requirements,
&listener_task_context.codex_home,
&runtime_feature_enablement,
Expand Down Expand Up @@ -2603,6 +2612,7 @@ impl CodexMessageProcessor {
cli_overrides_for_reload,
config_overrides,
typesafe_overrides,
thread_config_loader,
&cloud_requirements,
&listener_task_context.codex_home,
&runtime_feature_enablement,
Expand Down Expand Up @@ -6426,6 +6436,7 @@ impl CodexMessageProcessor {
&cli_overrides,
LoaderOverrides::default(),
CloudRequirementsLoader::default(),
self.thread_config_loader.as_ref(),
)
.await
{
Expand Down Expand Up @@ -9350,6 +9361,7 @@ async fn derive_config_from_params(
cli_overrides: &[(String, TomlValue)],
request_overrides: Option<HashMap<String, serde_json::Value>>,
typesafe_overrides: ConfigOverrides,
thread_config_loader: Arc<dyn ThreadConfigLoader>,
cloud_requirements: &CloudRequirementsLoader,
codex_home: &Path,
runtime_feature_enablement: &BTreeMap<String, bool>,
Expand All @@ -9370,6 +9382,7 @@ async fn derive_config_from_params(
.cli_overrides(merged_cli_overrides)
.harness_overrides(typesafe_overrides)
.cloud_requirements(cloud_requirements.clone())
.thread_config_loader(thread_config_loader)
.build()
.await?;
apply_runtime_feature_enablement(&mut config, runtime_feature_enablement);
Expand Down Expand Up @@ -10245,6 +10258,11 @@ mod tests {
use chrono::Utc;
use codex_app_server_protocol::ServerRequestPayload;
use codex_app_server_protocol::ToolRequestUserInputParams;
use codex_config::SessionThreadConfig;
use codex_config::StaticThreadConfigLoader;
use codex_config::ThreadConfigSource;
use codex_model_provider_info::ModelProviderInfo;
use codex_model_provider_info::WireApi;
use codex_protocol::ThreadId;
use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::protocol::AskForApproval;
Expand All @@ -10257,6 +10275,7 @@ mod tests {
use pretty_assertions::assert_eq;
use serde_json::json;
use std::path::PathBuf;
use std::sync::Arc;
use tempfile::TempDir;

#[test]
Expand Down Expand Up @@ -10409,6 +10428,64 @@ mod tests {
);
}

#[tokio::test]
async fn derive_config_from_params_uses_session_thread_config_model_provider() -> Result<()> {
let temp_dir = TempDir::new()?;
let session_provider = ModelProviderInfo {
name: "session".to_string(),
base_url: Some("http://127.0.0.1:8061/api/codex".to_string()),
env_key: None,
env_key_instructions: None,
experimental_bearer_token: None,
auth: None,
wire_api: WireApi::Responses,
query_params: None,
http_headers: None,
env_http_headers: None,
request_max_retries: None,
stream_max_retries: None,
stream_idle_timeout_ms: None,
websocket_connect_timeout_ms: None,
requires_openai_auth: false,
supports_websockets: true,
};
let config = derive_config_from_params(
&[],
Some(HashMap::from([
("model_provider".to_string(), json!("request")),
("features.plugins".to_string(), json!(true)),
(
"model_providers.session".to_string(),
json!({
"name": "request",
"base_url": "http://127.0.0.1:9999/api/codex",
"wire_api": "responses",
}),
),
])),
ConfigOverrides::default(),
Arc::new(StaticThreadConfigLoader::new(vec![
ThreadConfigSource::Session(SessionThreadConfig {
model_provider: Some("session".to_string()),
model_providers: HashMap::from([(
"session".to_string(),
session_provider.clone(),
)]),
features: BTreeMap::from([("plugins".to_string(), false)]),
}),
])),
&CloudRequirementsLoader::default(),
temp_dir.path(),
&BTreeMap::new(),
)
.await?;

assert_eq!(config.model_provider_id, "session");
assert_eq!(config.model_provider, session_provider);
assert!(!config.features.enabled(Feature::Plugins));
Ok(())
}

#[test]
fn collect_resume_override_mismatches_includes_service_tier() {
let request = ThreadResumeParams {
Expand Down
5 changes: 5 additions & 0 deletions codex-rs/app-server/src/in_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ use codex_app_server_protocol::Result;
use codex_app_server_protocol::ServerNotification;
use codex_app_server_protocol::ServerRequest;
use codex_arg0::Arg0DispatchPaths;
use codex_config::ThreadConfigLoader;
use codex_core::config::Config;
use codex_core::config_loader::CloudRequirementsLoader;
use codex_core::config_loader::LoaderOverrides;
Expand Down Expand Up @@ -116,6 +117,8 @@ pub struct InProcessStartArgs {
pub loader_overrides: LoaderOverrides,
/// Preloaded cloud requirements provider.
pub cloud_requirements: CloudRequirementsLoader,
/// Loader used to fetch typed thread config sources before a thread starts.
pub thread_config_loader: Arc<dyn ThreadConfigLoader>,
/// Feedback sink used by app-server/core telemetry and logs.
pub feedback: CodexFeedback,
/// SQLite tracing layer used to flush recently emitted logs before feedback upload.
Expand Down Expand Up @@ -397,6 +400,7 @@ fn start_uninitialized(args: InProcessStartArgs) -> InProcessClientHandle {
cli_overrides: args.cli_overrides,
loader_overrides: args.loader_overrides,
cloud_requirements: args.cloud_requirements,
thread_config_loader: args.thread_config_loader,
feedback: args.feedback,
log_db: args.log_db,
config_warnings: args.config_warnings,
Expand Down Expand Up @@ -731,6 +735,7 @@ mod tests {
cli_overrides: Vec::new(),
loader_overrides: LoaderOverrides::default(),
cloud_requirements: CloudRequirementsLoader::default(),
thread_config_loader: Arc::new(codex_config::NoopThreadConfigLoader),
feedback: CodexFeedback::new(),
log_db: None,
environment_manager: Arc::new(EnvironmentManager::new(/*exec_server_url*/ None)),
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/app-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use codex_arg0::Arg0DispatchPaths;
use codex_cloud_requirements::cloud_requirements_loader;
use codex_config::NoopThreadConfigLoader;
use codex_core::config::Config;
use codex_core::config::ConfigBuilder;
use codex_core::config_loader::CloudRequirementsLoader;
Expand Down Expand Up @@ -416,6 +417,7 @@ pub async fn run_main_with_transport(
}
};
let loader_overrides_for_config_api = loader_overrides.clone();
let thread_config_loader = Arc::new(NoopThreadConfigLoader);
let mut config_warnings = Vec::new();
let config = match ConfigBuilder::default()
.cli_overrides(cli_kv_overrides.clone())
Expand Down Expand Up @@ -659,6 +661,7 @@ pub async fn run_main_with_transport(
cli_overrides,
loader_overrides,
cloud_requirements: cloud_requirements.clone(),
thread_config_loader,
feedback: feedback.clone(),
log_db,
config_warnings,
Expand Down
4 changes: 4 additions & 0 deletions codex-rs/app-server/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ use codex_app_server_protocol::ServerRequestPayload;
use codex_app_server_protocol::experimental_required_message;
use codex_arg0::Arg0DispatchPaths;
use codex_chatgpt::connectors;
use codex_config::ThreadConfigLoader;
use codex_core::ThreadManager;
use codex_core::config::Config;
use codex_core::config_loader::CloudRequirementsLoader;
Expand Down Expand Up @@ -235,6 +236,7 @@ pub(crate) struct MessageProcessorArgs {
pub(crate) cli_overrides: Vec<(String, TomlValue)>,
pub(crate) loader_overrides: LoaderOverrides,
pub(crate) cloud_requirements: CloudRequirementsLoader,
pub(crate) thread_config_loader: Arc<dyn ThreadConfigLoader>,
pub(crate) feedback: CodexFeedback,
pub(crate) log_db: Option<LogDbLayer>,
pub(crate) config_warnings: Vec<ConfigWarningNotification>,
Expand All @@ -256,6 +258,7 @@ impl MessageProcessor {
cli_overrides,
loader_overrides,
cloud_requirements,
thread_config_loader,
feedback,
log_db,
config_warnings,
Expand Down Expand Up @@ -301,6 +304,7 @@ impl MessageProcessor {
cli_overrides: cli_overrides.clone(),
runtime_feature_enablement: runtime_feature_enablement.clone(),
cloud_requirements: cloud_requirements.clone(),
thread_config_loader,
feedback,
log_db,
});
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/src/message_processor/tracing_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ fn build_test_processor(
cli_overrides: Vec::new(),
loader_overrides: LoaderOverrides::default(),
cloud_requirements: CloudRequirementsLoader::default(),
thread_config_loader: Arc::new(codex_config::NoopThreadConfigLoader),
feedback: CodexFeedback::new(),
log_db: None,
config_warnings: Vec::new(),
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/tests/suite/v2/mcp_resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ async fn mcp_resource_read_returns_error_for_unknown_thread() -> Result<()> {
cli_overrides: Vec::new(),
loader_overrides,
cloud_requirements: CloudRequirementsLoader::default(),
thread_config_loader: Arc::new(codex_config::NoopThreadConfigLoader),
feedback: CodexFeedback::new(),
log_db: None,
environment_manager: Arc::new(EnvironmentManager::new(/*exec_server_url*/ None)),
Expand Down
1 change: 1 addition & 0 deletions codex-rs/config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ workspace = true

[dependencies]
anyhow = { workspace = true }
async-trait = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-execpolicy = { workspace = true }
codex-features = { workspace = true }
Expand Down
10 changes: 10 additions & 0 deletions codex-rs/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod schema;
pub mod shell_environment;
mod skills_config;
mod state;
mod thread_config;
pub mod types;

pub const CONFIG_TOML_FILE: &str = "config.toml";
Expand Down Expand Up @@ -93,5 +94,14 @@ pub use state::ConfigLayerEntry;
pub use state::ConfigLayerStack;
pub use state::ConfigLayerStackOrdering;
pub use state::LoaderOverrides;
pub use thread_config::NoopThreadConfigLoader;
pub use thread_config::SessionThreadConfig;
pub use thread_config::StaticThreadConfigLoader;
pub use thread_config::ThreadConfigContext;
pub use thread_config::ThreadConfigLoadError;
pub use thread_config::ThreadConfigLoadErrorCode;
pub use thread_config::ThreadConfigLoader;
pub use thread_config::ThreadConfigSource;
pub use thread_config::UserThreadConfig;

pub use codex_app_server_protocol::ConfigLayerSource;
Loading
Loading