Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 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: 0 additions & 1 deletion codex-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,6 @@ unwrap_used = "deny"
[workspace.metadata.cargo-shear]
ignored = [
"codex-agent-graph-store",
"codex-extension-api",
"icu_provider",
"openssl-sys",
"codex-v8-poc",
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 @@ -37,6 +37,7 @@ codex-config = { workspace = true }
codex-core = { workspace = true }
codex-core-plugins = { workspace = true }
codex-exec-server = { workspace = true }
codex-extension-api = { workspace = true }
codex-external-agent-migration = { workspace = true }
codex-external-agent-sessions = { workspace = true }
codex-features = { workspace = true }
Expand Down
9 changes: 9 additions & 0 deletions codex-rs/app-server/src/extensions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use std::sync::Arc;

use codex_core::config::Config;
use codex_extension_api::ExtensionRegistry;
use codex_extension_api::ExtensionRegistryBuilder;

pub(crate) fn thread_extensions() -> Arc<ExtensionRegistry<Config>> {
Arc::new(ExtensionRegistryBuilder::<Config>::new().build())
}
1 change: 1 addition & 0 deletions codex-rs/app-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ mod config_manager_service;
mod connection_rpc_gate;
mod dynamic_tools;
mod error_code;
mod extensions;
mod filters;
mod fs_watch;
mod fuzzy_file_search;
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/app-server/src/mcp_refresh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ async fn queue_refresh(
#[cfg(test)]
mod tests {
use super::*;
use crate::extensions::thread_extensions;
use async_trait::async_trait;
use codex_arg0::Arg0DispatchPaths;
use codex_config::CloudRequirementsLoader;
Expand Down Expand Up @@ -183,6 +184,7 @@ mod tests {
auth_manager,
SessionSource::Exec,
Arc::new(EnvironmentManager::default_for_tests()),
thread_extensions(),
/*analytics_events_client*/ None,
thread_store,
Some(state_db.clone()),
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/app-server/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::attestation::app_server_attestation_provider;
use crate::config_manager::ConfigManager;
use crate::connection_rpc_gate::ConnectionRpcGate;
use crate::error_code::invalid_request;
use crate::extensions::thread_extensions;
use crate::fs_watch::FsWatchManager;
use crate::outgoing_message::ConnectionId;
use crate::outgoing_message::ConnectionRequestId;
Expand Down Expand Up @@ -303,6 +304,7 @@ impl MessageProcessor {
auth_manager.clone(),
session_source,
environment_manager,
thread_extensions(),
Some(analytics_events_client.clone()),
Arc::clone(&thread_store),
state_db.clone(),
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ codex-arg0 = { workspace = true }
codex-analytics = { workspace = true }
codex-config = { workspace = true }
codex-core = { workspace = true }
codex-extension-api = { workspace = true }
codex-exec-server = { workspace = true }
codex-features = { workspace = true }
codex-login = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub use codex_core::skills::SkillsManager;
pub use codex_core::thread_store_from_config;
pub use codex_exec_server::EnvironmentManager;
pub use codex_exec_server::ExecServerRuntimePaths;
pub use codex_extension_api::empty_extension_registry;
pub use codex_features::Feature;
pub use codex_features::Features;
pub use codex_login::AuthManager;
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ codex-config = { workspace = true }
codex-core-plugins = { workspace = true }
codex-core-skills = { workspace = true }
codex-exec-server = { workspace = true }
codex-extension-api = { workspace = true }
codex-features = { workspace = true }
codex-feedback = { workspace = true }
codex-login = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core/src/codex_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pub(crate) async fn run_codex_thread_interactive(
skills_manager: Arc::clone(&parent_session.services.skills_manager),
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),
conversation_history: initial_history.unwrap_or(InitialHistory::New),
session_source: SessionSource::SubAgent(subagent_source.clone()),
thread_source: Some(ThreadSource::Subagent),
Expand Down
1 change: 1 addition & 0 deletions codex-rs/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod config_lock;
pub use codex_thread::CodexThread;
pub use codex_thread::CodexThreadTurnContextOverrides;
pub use codex_thread::ThreadConfigSnapshot;
pub use session::turn_context::TurnContext;
mod agent;
mod attestation;
mod codex_delegate;
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/core/src/prompt_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::session::turn::built_tools;
use crate::state_db_bridge::StateDbHandle;
use crate::thread_manager::ThreadManager;
use crate::thread_manager::thread_store_from_config;
use codex_extension_api::empty_extension_registry;

/// Build the model-visible `input` list for a single debug turn.
#[doc(hidden)]
Expand Down Expand Up @@ -49,6 +50,7 @@ pub async fn build_prompt_input(
.await
.map_err(|err| CodexErr::Fatal(err.to_string()))?,
),
empty_extension_registry(),
/*analytics_events_client*/ None,
thread_store,
state_db.clone(),
Expand Down
30 changes: 30 additions & 0 deletions codex-rs/core/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use codex_config::types::OAuthCredentialsStoreMode;
use codex_exec_server::Environment;
use codex_exec_server::EnvironmentManager;
use codex_exec_server::FileSystemSandboxContext;
use codex_extension_api::PromptSlot;
use codex_features::FEATURES;
use codex_features::Feature;
use codex_features::unstable_features_warning_event;
Expand Down Expand Up @@ -392,6 +393,7 @@ pub(crate) struct CodexSpawnArgs {
pub(crate) skills_manager: Arc<SkillsManager>,
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) conversation_history: InitialHistory,
pub(crate) session_source: SessionSource,
pub(crate) thread_source: Option<ThreadSource>,
Expand Down Expand Up @@ -455,6 +457,7 @@ impl Codex {
skills_manager,
plugins_manager,
mcp_manager,
extensions,
conversation_history,
session_source,
thread_source,
Expand Down Expand Up @@ -650,6 +653,7 @@ impl Codex {
skills_manager,
plugins_manager,
mcp_manager.clone(),
extensions,
agent_control,
environment_manager,
analytics_events_client,
Expand Down Expand Up @@ -2570,6 +2574,7 @@ impl Session {
) -> Vec<ResponseItem> {
let mut developer_sections = Vec::<String>::with_capacity(8);
let mut contextual_user_sections = Vec::<String>::with_capacity(2);
let mut separate_developer_sections = Vec::<String>::new();
let (
reference_context_item,
previous_turn_settings,
Expand Down Expand Up @@ -2714,6 +2719,24 @@ impl Session {
{
developer_sections.push(commit_message_instruction);
}
for contributor in self.services.extensions.context_contributors() {
for fragment in contributor.contribute(
&self.services.session_extension_data,
&self.services.thread_extension_data,
) {
match fragment.slot() {
PromptSlot::DeveloperPolicy | PromptSlot::DeveloperCapabilities => {
developer_sections.push(fragment.text().to_string());
}
PromptSlot::ContextualUser => {
contextual_user_sections.push(fragment.text().to_string());
}
PromptSlot::SeparateDeveloper => {
separate_developer_sections.push(fragment.text().to_string());
}
}
}
}
if let Some(user_instructions) = turn_context.user_instructions.as_deref() {
contextual_user_sections.push(
UserInstructions {
Expand Down Expand Up @@ -2746,6 +2769,13 @@ impl Session {
{
items.push(developer_message);
}
for section in separate_developer_sections {
if let Some(developer_message) =
crate::context_manager::updates::build_developer_update_item(vec![section])
{
items.push(developer_message);
}
}
if let Some(usage_hint_text) = multi_agent_v2_usage_hint_text
&& let Some(usage_hint_message) =
crate::context_manager::updates::build_developer_update_item(vec![
Expand Down
15 changes: 15 additions & 0 deletions codex-rs/core/src/session/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ impl Session {
skills_manager: Arc<SkillsManager>,
plugins_manager: Arc<PluginsManager>,
mcp_manager: Arc<McpManager>,
extensions: Arc<codex_extension_api::ExtensionRegistry<crate::config::Config>>,
agent_control: AgentControl,
environment_manager: Arc<EnvironmentManager>,
analytics_events_client: Option<AnalyticsEventsClient>,
Expand Down Expand Up @@ -810,6 +811,16 @@ impl Session {
SessionId::from(thread_id)
};
let agent_control = agent_control.with_session_id(session_id);
let session_extension_data = codex_extension_api::ExtensionData::new();
let thread_extension_data = codex_extension_api::ExtensionData::new();
for contributor in extensions.thread_start_contributors() {
contributor.contribute(
config.as_ref(),
&session_extension_data,
&thread_extension_data,
);
}

let services = SessionServices {
// Initialize the MCP connection manager with an uninitialized
// instance. It will be replaced with one created via
Expand Down Expand Up @@ -845,6 +856,10 @@ impl Session {
skills_manager,
plugins_manager: Arc::clone(&plugins_manager),
mcp_manager: Arc::clone(&mcp_manager),
extensions,
// TODO(jif): extract session to share between sub-agents
session_extension_data,
thread_extension_data,
agent_control,
network_proxy,
network_approval: Arc::clone(&network_approval),
Expand Down
76 changes: 76 additions & 0 deletions codex-rs/core/src/session/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3725,6 +3725,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
skills_manager,
plugins_manager,
mcp_manager,
Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()),
AgentControl::default(),
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
/*analytics_events_client*/ None,
Expand Down Expand Up @@ -3871,6 +3872,9 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
skills_manager,
plugins_manager,
mcp_manager,
extensions: Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()),
session_extension_data: codex_extension_api::ExtensionData::new(),
thread_extension_data: codex_extension_api::ExtensionData::new(),
agent_control,
network_proxy: None,
network_approval: Arc::clone(&network_approval),
Expand Down Expand Up @@ -4061,6 +4065,7 @@ async fn make_session_with_config_and_rx(
skills_manager,
plugins_manager,
mcp_manager,
Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()),
AgentControl::default(),
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
/*analytics_events_client*/ None,
Expand Down Expand Up @@ -4163,6 +4168,7 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
skills_manager,
plugins_manager,
mcp_manager,
Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()),
agent_control,
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
/*analytics_events_client*/ None,
Expand Down Expand Up @@ -5586,6 +5592,9 @@ where
skills_manager,
plugins_manager,
mcp_manager,
extensions: Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()),
session_extension_data: codex_extension_api::ExtensionData::new(),
thread_extension_data: codex_extension_api::ExtensionData::new(),
agent_control,
network_proxy: None,
network_approval: Arc::clone(&network_approval),
Expand Down Expand Up @@ -6133,6 +6142,73 @@ async fn make_multi_agent_v2_usage_hint_test_session(
(session, turn_context)
}

struct GitAttributionTestContributor;
struct GitAttributionTestState;

impl codex_extension_api::ContextContributor for GitAttributionTestContributor {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is a merge artifact and it will disappear

fn contribute(
&self,
_session_store: &codex_extension_api::ExtensionData,
thread_store: &codex_extension_api::ExtensionData,
) -> Vec<codex_extension_api::PromptFragment> {
thread_store
.get::<GitAttributionTestState>()
.is_some()
.then(|| {
codex_extension_api::PromptFragment::developer_policy(
"git attribution extension enabled",
)
})
.into_iter()
.collect()
}
}

fn git_attribution_test_registry()
-> Arc<codex_extension_api::ExtensionRegistry<crate::config::Config>> {
let mut builder = codex_extension_api::ExtensionRegistryBuilder::new();
builder.prompt_contributor(Arc::new(GitAttributionTestContributor));
Arc::new(builder.build())
}

#[tokio::test]
async fn build_initial_context_includes_git_attribution_from_extensions() {
let (mut session, turn_context) = make_session_and_context().await;
session.services.extensions = git_attribution_test_registry();
session
.services
.thread_extension_data
.insert(GitAttributionTestState);

let initial_context = session.build_initial_context(&turn_context).await;
let developer_messages = developer_message_texts(&initial_context);

assert!(
developer_messages
.iter()
.flatten()
.any(|text| *text == "git attribution extension enabled"),
"expected git attribution developer text, got {developer_messages:?}"
);
}

#[tokio::test]
async fn build_initial_context_omits_git_attribution_when_feature_is_disabled() {
let (mut session, turn_context) = make_session_and_context().await;
session.services.extensions = git_attribution_test_registry();

let initial_context = session.build_initial_context(&turn_context).await;
let developer_messages = developer_message_texts(&initial_context);

assert!(
!developer_messages
.iter()
.flatten()
.any(|text| *text == "git attribution extension enabled"),
"did not expect git attribution developer text, got {developer_messages:?}"
);
}

#[tokio::test]
async fn build_initial_context_adds_multi_agent_v2_root_usage_hint_as_developer_message() {
let (session, turn_context) =
Expand Down
Loading
Loading