Skip to main content

rust_genai/
computer_use.rs

1//! Computer Use helpers.
2
3use serde::{Deserialize, Serialize};
4
5use rust_genai_types::tool::FunctionDeclaration;
6
7/// 预置的 Computer Use UI 动作名称。
8pub const COMPUTER_USE_ACTIONS: &[&str] = &[
9    "open_web_browser",
10    "wait_5_seconds",
11    "go_back",
12    "go_forward",
13    "search",
14    "navigate",
15    "click_at",
16    "hover_at",
17    "type_text_at",
18    "key_combination",
19    "scroll_document",
20    "scroll_at",
21    "drag_and_drop",
22];
23
24/// 生成预置动作的 `FunctionDeclaration` 列表。
25#[must_use]
26pub fn computer_use_function_declarations() -> Vec<FunctionDeclaration> {
27    COMPUTER_USE_ACTIONS
28        .iter()
29        .map(|name| FunctionDeclaration {
30            name: (*name).to_string(),
31            description: None,
32            parameters: None,
33            parameters_json_schema: None,
34            response: None,
35            response_json_schema: None,
36            behavior: None,
37        })
38        .collect()
39}
40
41/// 坐标归一化(像素 -> 0-999)。
42#[must_use]
43pub fn normalize_coordinate(pixel: i32, screen_dimension: i32) -> i32 {
44    if screen_dimension <= 0 {
45        return 0;
46    }
47    let numerator = i64::from(pixel) * 1000;
48    let denominator = i64::from(screen_dimension);
49    let value = numerator / denominator;
50    i32::try_from(value).unwrap_or(if value < 0 { i32::MIN } else { i32::MAX })
51}
52
53/// 坐标反归一化(0-999 -> 像素)。
54#[must_use]
55pub fn denormalize_coordinate(normalized: i32, screen_dimension: i32) -> i32 {
56    if screen_dimension <= 0 {
57        return 0;
58    }
59    let numerator = i64::from(normalized) * i64::from(screen_dimension);
60    let value = numerator / 1000;
61    i32::try_from(value).unwrap_or(if value < 0 { i32::MIN } else { i32::MAX })
62}
63
64/// Safety decision 信息。
65#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(rename_all = "snake_case")]
67pub struct SafetyDecision {
68    pub decision: SafetyDecisionType,
69    pub explanation: String,
70}
71
72#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
73#[serde(rename_all = "snake_case")]
74pub enum SafetyDecisionType {
75    RequireConfirmation,
76    Regular,
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_computer_use_coordinate_normalization() {
85        assert_eq!(normalize_coordinate(720, 1440), 500);
86        assert_eq!(denormalize_coordinate(500, 1440), 720);
87    }
88
89    #[test]
90    fn test_computer_use_actions_and_zero_dimension() {
91        let declarations = computer_use_function_declarations();
92        assert_eq!(declarations.len(), COMPUTER_USE_ACTIONS.len());
93        assert_eq!(declarations[0].name, COMPUTER_USE_ACTIONS[0]);
94        assert_eq!(normalize_coordinate(10, 0), 0);
95        assert_eq!(denormalize_coordinate(10, -1), 0);
96    }
97}