ai_providers/openai/common/
computer_tool_call_item.rs

1use serde::{Deserialize, Serialize};
2
3use crate::openai::common::status::Status;
4use crate::openai::errors::InputError;
5
6#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
7pub struct ClickAction {
8    pub button: String,
9    #[serde(rename = "type")]
10    pub type_field: String,
11    pub x: usize,
12    pub y: usize,
13}
14
15impl ClickAction {
16    const BUTTON: [&'static str; 5] = ["left", "right", "wheel", "back", "forward"];
17
18    pub fn new(button: impl Into<String>, x: usize, y: usize) -> Result<Self, InputError> {
19        let button_str = button.into();
20        if Self::BUTTON.contains(&button_str.as_str()) {
21            Ok(Self {
22                button: button_str,
23                type_field: "click".to_string(),
24                x,
25                y,
26            })
27        } else {
28            Err(InputError::InvalidButton(button_str))
29        }
30    }
31}
32
33#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
34pub struct DoubleClickAction {
35    #[serde(rename = "type")]
36    pub type_field: String,
37    pub x: usize,
38    pub y: usize,
39}
40
41impl DoubleClickAction {
42    pub fn new(x: usize, y: usize) -> Self {
43        Self {
44            type_field: "double_click".to_string(),
45            x,
46            y,
47        }
48    }
49}
50
51#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
52pub struct DragActionPath {
53    pub x: usize,
54    pub y: usize,
55}
56
57impl DragActionPath {
58    pub fn new(x: usize, y: usize) -> Self {
59        Self { x, y }
60    }
61}
62
63#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
64pub struct DragAction {
65    #[serde(rename = "type")]
66    pub type_field: String,
67    pub path: Vec<DragActionPath>,
68}
69
70impl DragAction {
71    pub fn new(path: Vec<DragActionPath>) -> Self {
72        Self {
73            type_field: "drag".to_string(),
74            path,
75        }
76    }
77}
78
79#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
80pub struct KeyPressAction {
81    #[serde(rename = "type")]
82    pub type_field: String,
83    pub keys: Vec<String>,
84}
85
86impl KeyPressAction {
87    pub fn new(keys: Vec<impl Into<String>>) -> Self {
88        Self {
89            type_field: "keypress".to_string(),
90            keys: keys.into_iter().map(|k| k.into()).collect(),
91        }
92    }
93}
94
95#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
96pub struct MoveAction {
97    #[serde(rename = "type")]
98    pub type_field: String,
99    pub x: usize,
100    pub y: usize,
101}
102
103impl MoveAction {
104    pub fn new(x: usize, y: usize) -> Self {
105        Self {
106            type_field: "move".to_string(),
107            x,
108            y,
109        }
110    }
111}
112
113#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
114pub struct ScreenshotAction {
115    #[serde(rename = "type")]
116    pub type_field: String,
117}
118
119impl ScreenshotAction {
120    pub fn new() -> Self {
121        Self {
122            type_field: "screenshot".to_string(),
123        }
124    }
125}
126
127impl Default for ScreenshotAction {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132
133#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
134pub struct ScrollAction {
135    #[serde(rename = "type")]
136    pub type_field: String,
137    pub scroll_x: usize,
138    pub scroll_y: usize,
139    pub x: usize,
140    pub y: usize,
141}
142
143impl ScrollAction {
144    pub fn new(scroll_x: usize, scroll_y: usize, x: usize, y: usize) -> Self {
145        Self {
146            type_field: "scroll".to_string(),
147            scroll_x,
148            scroll_y,
149            x,
150            y,
151        }
152    }
153}
154
155#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
156pub struct TypeAction {
157    #[serde(rename = "type")]
158    pub type_field: String,
159    pub text: String,
160}
161
162impl TypeAction {
163    pub fn new(text: impl Into<String>) -> Self {
164        Self {
165            type_field: "type".to_string(),
166            text: text.into(),
167        }
168    }
169}
170
171#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
172pub struct WaitAction {
173    #[serde(rename = "type")]
174    pub type_field: String,
175}
176
177impl WaitAction {
178    pub fn new() -> Self {
179        Self {
180            type_field: "wait".to_string(),
181        }
182    }
183}
184
185impl Default for WaitAction {
186    fn default() -> Self {
187        Self::new()
188    }
189}
190
191#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
192#[serde(untagged)]
193pub enum ComputerToolAction {
194    Click(ClickAction),
195    DoubleClick(DoubleClickAction),
196    Drag(DragAction),
197    KeyPress(KeyPressAction),
198    Move(MoveAction),
199    Screenshot(ScreenshotAction),
200    Scroll(ScrollAction),
201    Type(TypeAction),
202    Wait(WaitAction),
203}
204
205#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
206pub struct PendingSafetyChecks {
207    pub code: String,
208    pub id: String,
209    pub message: String,
210}
211
212impl PendingSafetyChecks {
213    pub fn new(code: impl Into<String>, id: impl Into<String>, message: impl Into<String>) -> Self {
214        Self {
215            code: code.into(),
216            id: id.into(),
217            message: message.into(),
218        }
219    }
220}
221
222#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
223pub struct ComputerToolCallItem {
224    pub action: ComputerToolAction,
225    pub call_id: String,
226    pub id: String,
227    pub pending_safety_checks: Vec<PendingSafetyChecks>,
228    pub status: Status,
229}
230
231impl ComputerToolCallItem {
232    pub fn new(
233        action: ComputerToolAction,
234        call_id: impl Into<String>,
235        id: impl Into<String>,
236        pending_safety_checks: Vec<PendingSafetyChecks>,
237        status: Status,
238    ) -> Self {
239        Self {
240            action,
241            call_id: call_id.into(),
242            id: id.into(),
243            pending_safety_checks,
244            status,
245        }
246    }
247}