codex_agent_extension/
lib.rs1use codex_core::CodexThread;
2use codex_core::NewThread;
3use codex_core::StartThreadOptions;
4use codex_core::ThreadManager;
5use codex_core::config::Config;
6use codex_protocol::ThreadId;
7use codex_protocol::error::CodexErr;
8use codex_protocol::error::Result as CodexResult;
9use codex_protocol::protocol::InitialHistory;
10use codex_protocol::protocol::W3cTraceContext;
11use codex_protocol::user_input::UserInput;
12use std::sync::Arc;
13use std::sync::Weak;
14
15pub struct AgentInvocation {
20 pub config: Config,
21 pub prompt: String,
22 pub parent_trace: Option<W3cTraceContext>,
23}
24
25pub struct AgentRun {
27 pub thread_id: ThreadId,
28 pub turn_id: String,
29 pub thread: Arc<CodexThread>,
30}
31
32#[derive(Clone)]
34pub struct AgentRunner {
35 thread_manager: Weak<ThreadManager>,
36}
37
38impl AgentRunner {
39 pub fn new(thread_manager: Weak<ThreadManager>) -> Self {
40 Self { thread_manager }
41 }
42
43 pub async fn start(
45 &self,
46 parent_thread_id: ThreadId,
47 invocation: AgentInvocation,
48 ) -> CodexResult<AgentRun> {
49 let AgentInvocation {
50 config,
51 prompt,
52 parent_trace,
53 } = invocation;
54 if prompt.trim().is_empty() {
55 return Err(CodexErr::InvalidRequest(
56 "agent prompt must not be empty".to_string(),
57 ));
58 }
59
60 let thread_manager = self
61 .thread_manager
62 .upgrade()
63 .ok_or_else(|| CodexErr::UnsupportedOperation("thread manager dropped".to_string()))?;
64 let environments =
65 thread_manager.default_environment_selections(&config.cwd, &config.workspace_roots);
66 let NewThread {
67 thread_id, thread, ..
68 } = thread_manager
69 .spawn_subagent(
70 parent_thread_id,
71 StartThreadOptions {
72 config,
73 allow_provider_model_fallback: false,
74 initial_history: InitialHistory::New,
75 history_mode: None,
76 session_source: None,
77 thread_source: None,
78 dynamic_tools: Vec::new(),
79 metrics_service_name: None,
80 parent_trace: parent_trace.clone(),
81 environments,
82 thread_extension_init: Default::default(),
83 supports_openai_form_elicitation: false,
84 },
85 )
86 .await?;
87 let turn_id = thread
88 .submit_with_trace(
89 vec![UserInput::Text {
90 text: prompt,
91 text_elements: Vec::new(),
92 }]
93 .into(),
94 parent_trace,
95 )
96 .await?;
97
98 Ok(AgentRun {
99 thread_id,
100 turn_id,
101 thread,
102 })
103 }
104}