ralph_workflow/json_parser/codex/
event_interpretation.rs1#[derive(Debug, Clone, PartialEq, Eq)]
2pub enum ItemStartedInterpretation {
3 CommandExecution,
4 AgentMessage,
5 Reasoning,
6 FileRead,
7 FileWrite,
8 McpTool,
9 WebSearch,
10 PlanUpdate,
11 Unknown(String),
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum ItemCompletedInterpretation {
16 AgentMessage,
17 Reasoning,
18 CommandExecution,
19 FileWrite,
20 FileRead,
21 McpTool,
22 WebSearch,
23 PlanUpdate,
24}
25
26pub fn interpret_item_started_type(item_type: Option<&str>) -> Option<ItemStartedInterpretation> {
27 item_type.map(|item_type| match item_type {
28 "command_execution" => ItemStartedInterpretation::CommandExecution,
29 "agent_message" => ItemStartedInterpretation::AgentMessage,
30 "reasoning" => ItemStartedInterpretation::Reasoning,
31 "file_read" => ItemStartedInterpretation::FileRead,
32 "file_write" => ItemStartedInterpretation::FileWrite,
33 "mcp_tool_call" | "mcp" => ItemStartedInterpretation::McpTool,
34 "web_search" => ItemStartedInterpretation::WebSearch,
35 "plan_update" => ItemStartedInterpretation::PlanUpdate,
36 other => ItemStartedInterpretation::Unknown(other.to_string()),
37 })
38}
39
40pub fn interpret_item_completed_type(
41 item_type: Option<&str>,
42) -> Option<ItemCompletedInterpretation> {
43 item_type.and_then(|item_type| match item_type {
44 "agent_message" => Some(ItemCompletedInterpretation::AgentMessage),
45 "reasoning" => Some(ItemCompletedInterpretation::Reasoning),
46 "command_execution" => Some(ItemCompletedInterpretation::CommandExecution),
47 "file_change" | "file_write" => Some(ItemCompletedInterpretation::FileWrite),
48 "file_read" => Some(ItemCompletedInterpretation::FileRead),
49 "mcp_tool_call" | "mcp" => Some(ItemCompletedInterpretation::McpTool),
50 "web_search" => Some(ItemCompletedInterpretation::WebSearch),
51 "plan_update" => Some(ItemCompletedInterpretation::PlanUpdate),
52 _ => None,
53 })
54}
55
56pub fn compute_reasoning_incremental_delta(
57 previous_content: &str,
58 current_content: &str,
59) -> String {
60 if let Some(stripped) = current_content.strip_prefix(previous_content) {
61 stripped.to_string()
62 } else {
63 current_content.to_string()
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::{
70 compute_reasoning_incremental_delta, interpret_item_completed_type,
71 interpret_item_started_type, ItemCompletedInterpretation, ItemStartedInterpretation,
72 };
73
74 #[test]
75 fn started_type_maps_aliases_to_mcp_tool() {
76 assert_eq!(
77 interpret_item_started_type(Some("mcp")),
78 Some(ItemStartedInterpretation::McpTool)
79 );
80 }
81
82 #[test]
83 fn completed_type_maps_file_change_to_file_write() {
84 assert_eq!(
85 interpret_item_completed_type(Some("file_change")),
86 Some(ItemCompletedInterpretation::FileWrite)
87 );
88 }
89
90 #[test]
91 fn reasoning_delta_returns_suffix_when_content_extends_previous() {
92 assert_eq!(
93 compute_reasoning_incremental_delta("hello", "hello world"),
94 " world"
95 );
96 }
97
98 #[test]
99 fn started_type_maps_unknown_type_to_unknown_variant() {
100 assert_eq!(
101 interpret_item_started_type(Some("custom_event")),
102 Some(ItemStartedInterpretation::Unknown(
103 "custom_event".to_string()
104 ))
105 );
106 }
107
108 #[test]
109 fn completed_type_returns_none_for_unknown_type() {
110 assert_eq!(interpret_item_completed_type(Some("custom_event")), None);
111 }
112
113 #[test]
114 fn reasoning_delta_returns_whole_content_when_not_prefix_extension() {
115 assert_eq!(
116 compute_reasoning_incremental_delta("old value", "new value"),
117 "new value"
118 );
119 }
120}