codex_runtime/runtime/core/
config.rs1use std::sync::Arc;
5
6use serde_json::{json, Value};
7use tokio::time::Duration;
8
9use crate::runtime::approvals::ServerRequestConfig;
10use crate::runtime::hooks::RuntimeHookConfig;
11use crate::runtime::sink::EventSink;
12use crate::runtime::state::StateProjectionLimits;
13use crate::runtime::transport::{StdioProcessSpec, StdioTransportConfig};
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum RestartPolicy {
21 Never,
22 OnCrash {
23 max_restarts: u32,
24 base_backoff_ms: u64,
25 max_backoff_ms: u64,
26 },
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub struct SupervisorConfig {
33 pub restart: RestartPolicy,
34 pub shutdown_flush_timeout_ms: u64,
35 pub shutdown_terminate_grace_ms: u64,
36 pub restart_budget_reset_ms: u64,
37}
38
39impl Default for SupervisorConfig {
40 fn default() -> Self {
41 Self {
42 restart: RestartPolicy::Never,
43 shutdown_flush_timeout_ms: 500,
44 shutdown_terminate_grace_ms: 750,
45 restart_budget_reset_ms: 30_000,
46 }
47 }
48}
49
50#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
53pub struct InitializeCapabilities {
54 pub experimental_api: bool,
55}
56
57impl InitializeCapabilities {
58 pub fn new() -> Self {
60 Self::default()
61 }
62
63 pub fn enable_experimental_api(mut self) -> Self {
65 self.experimental_api = true;
66 self
67 }
68}
69
70#[derive(Clone)]
78pub struct RuntimeConfig {
79 pub process: StdioProcessSpec,
80 pub hooks: RuntimeHookConfig,
81 pub transport: StdioTransportConfig,
82 pub supervisor: SupervisorConfig,
83 pub rpc_response_timeout: Duration,
84 pub server_requests: ServerRequestConfig,
85 pub initialize_params: Value,
86 pub live_channel_capacity: usize,
87 pub server_request_channel_capacity: usize,
88 pub event_sink: Option<Arc<dyn EventSink>>,
89 pub event_sink_channel_capacity: usize,
90 pub state_projection_limits: StateProjectionLimits,
91}
92
93impl RuntimeConfig {
94 pub fn new(process: StdioProcessSpec) -> Self {
97 Self {
98 process,
99 hooks: RuntimeHookConfig::default(),
100 transport: StdioTransportConfig::default(),
101 supervisor: SupervisorConfig::default(),
102 rpc_response_timeout: Duration::from_secs(30),
103 server_requests: ServerRequestConfig::default(),
104 initialize_params: json!({
105 "clientInfo": {
106 "name": env!("CARGO_PKG_NAME"),
107 "title": env!("CARGO_PKG_NAME"),
108 "version": env!("CARGO_PKG_VERSION")
109 },
110 "capabilities": {}
111 }),
112 live_channel_capacity: 1024,
113 server_request_channel_capacity: 128,
114 event_sink: None,
115 event_sink_channel_capacity: 1024,
116 state_projection_limits: StateProjectionLimits::default(),
117 }
118 }
119
120 pub fn with_hooks(mut self, hooks: RuntimeHookConfig) -> Self {
123 self.hooks = hooks;
124 self
125 }
126
127 pub fn with_initialize_capabilities(mut self, capabilities: InitializeCapabilities) -> Self {
129 set_initialize_capabilities(&mut self.initialize_params, capabilities);
130 self
131 }
132}
133
134fn set_initialize_capabilities(
135 initialize_params: &mut Value,
136 capabilities: InitializeCapabilities,
137) {
138 if !initialize_params.is_object() {
139 *initialize_params = json!({});
140 }
141
142 let Some(root) = initialize_params.as_object_mut() else {
143 return;
144 };
145 let capabilities_value = root
146 .entry("capabilities".to_owned())
147 .or_insert_with(|| Value::Object(Default::default()));
148 if !capabilities_value.is_object() {
149 *capabilities_value = Value::Object(Default::default());
150 }
151
152 let Some(capabilities_object) = capabilities_value.as_object_mut() else {
153 return;
154 };
155 if capabilities.experimental_api {
156 capabilities_object.insert("experimentalApi".to_owned(), Value::Bool(true));
157 } else {
158 capabilities_object.remove("experimentalApi");
159 }
160}