Skip to main content

kcode_codex_runtime_v2/
model.rs

1use std::time::Duration;
2
3use serde_json::Value;
4
5/// Model reasoning effort accepted by Codex.
6#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
7pub enum ReasoningEffort {
8    /// Disable reasoning when supported.
9    None,
10    /// Minimal reasoning.
11    Minimal,
12    /// Low reasoning.
13    Low,
14    /// Medium reasoning.
15    Medium,
16    /// High reasoning.
17    High,
18    /// Extra-high reasoning.
19    #[default]
20    XHigh,
21    /// Maximum reasoning when supported.
22    Max,
23}
24
25impl ReasoningEffort {
26    /// Returns the Codex protocol value.
27    pub const fn as_str(self) -> &'static str {
28        match self {
29            Self::None => "none",
30            Self::Minimal => "minimal",
31            Self::Low => "low",
32            Self::Medium => "medium",
33            Self::High => "high",
34            Self::XHigh => "xhigh",
35            Self::Max => "max",
36        }
37    }
38}
39
40/// A dynamic function exposed to Codex for a fresh thread.
41#[derive(Clone, Debug, PartialEq)]
42pub struct DynamicTool {
43    /// Function name visible to the model.
44    pub name: String,
45    /// Short function description visible to the model.
46    pub description: String,
47    /// JSON Schema for the function arguments.
48    pub input_schema: Value,
49}
50
51impl DynamicTool {
52    /// Constructs one function tool.
53    pub fn new(
54        name: impl Into<String>,
55        description: impl Into<String>,
56        input_schema: Value,
57    ) -> Self {
58        Self {
59            name: name.into(),
60            description: description.into(),
61            input_schema,
62        }
63    }
64}
65
66/// One standard Codex turn request.
67#[derive(Clone, Debug, PartialEq)]
68pub struct AgentRequest {
69    /// Exact text supplied as the user input item for this turn.
70    pub input: String,
71    /// Codex model identifier.
72    pub model: String,
73    /// Requested reasoning effort.
74    pub reasoning_effort: ReasoningEffort,
75    /// Existing Codex thread identifier to resume.
76    pub previous_thread_id: Option<String>,
77    /// Dynamic functions supplied when a fresh thread is created.
78    pub tools: Vec<DynamicTool>,
79    /// Whether a fresh thread avoids persistent Codex session storage.
80    pub ephemeral: bool,
81    /// Maximum duration of the complete turn, including tool handling.
82    pub timeout: Duration,
83}
84
85impl AgentRequest {
86    /// Constructs a fresh turn with no tools.
87    pub fn new(input: impl Into<String>, model: impl Into<String>) -> Self {
88        Self {
89            input: input.into(),
90            model: model.into(),
91            reasoning_effort: ReasoningEffort::XHigh,
92            previous_thread_id: None,
93            tools: Vec::new(),
94            ephemeral: false,
95            timeout: Duration::from_secs(10 * 60),
96        }
97    }
98}
99
100/// A dynamic function call requested by Codex.
101#[derive(Clone, Debug, PartialEq)]
102pub struct DynamicToolCall {
103    /// Protocol call identifier used when returning the result.
104    pub call_id: String,
105    /// Dynamic function name.
106    pub tool: String,
107    /// Parsed JSON arguments supplied by the model.
108    pub arguments: Value,
109}
110
111/// Caller-provided result for one dynamic function call.
112#[derive(Clone, Debug, Eq, PartialEq)]
113pub struct ToolResult {
114    /// Whether the function completed successfully.
115    pub success: bool,
116    /// Text returned to the model.
117    pub text: String,
118}
119
120impl ToolResult {
121    /// Constructs a successful text result.
122    pub fn success(text: impl Into<String>) -> Self {
123        Self {
124            success: true,
125            text: text.into(),
126        }
127    }
128
129    /// Constructs a failed text result.
130    pub fn failure(text: impl Into<String>) -> Self {
131        Self {
132            success: false,
133            text: text.into(),
134        }
135    }
136}
137
138/// Normalized cumulative and latest-turn token accounting.
139#[derive(Clone, Debug, Default, Eq, PartialEq)]
140pub struct TokenUsage {
141    /// Cumulative input tokens for the thread.
142    pub input_tokens: u64,
143    /// Cumulative output tokens for the thread.
144    pub output_tokens: u64,
145    /// Cumulative cached input tokens for the thread.
146    pub cached_input_tokens: u64,
147    /// Cumulative reasoning output tokens for the thread.
148    pub reasoning_output_tokens: u64,
149    /// Input tokens for the latest model round.
150    pub last_input_tokens: Option<u64>,
151    /// Output tokens for the latest model round.
152    pub last_output_tokens: Option<u64>,
153}
154
155/// Successful terminal state of one Codex turn.
156#[derive(Clone, Debug, Eq, PartialEq)]
157pub struct CompletedTurn {
158    /// Codex thread identifier used for continuation.
159    pub thread_id: String,
160    /// Codex turn identifier.
161    pub turn_id: String,
162    /// Terminal assistant text. It may be empty after a control tool call.
163    pub answer: String,
164    /// Latest provider token accounting, when reported.
165    pub usage: Option<TokenUsage>,
166}
167
168/// Event yielded while a Codex turn is running.
169#[derive(Clone, Debug, PartialEq)]
170pub enum AgentEvent {
171    /// Exact UTF-8 JSONL record written by the client to Codex, including its newline.
172    ProviderInput(String),
173    /// A dynamic function call requiring a response from the caller.
174    ToolCall(DynamicToolCall),
175    /// The turn completed successfully.
176    Completed(CompletedTurn),
177}