browsing 0.1.5

Browser automation: navigate, click, extract, screenshot. Standalone browser control via CDP.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
//! DOM view types

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;

/// Default attributes to include in DOM serialization
pub const DEFAULT_INCLUDE_ATTRIBUTES: &[&str] = &[
    "title",
    "type",
    "checked",
    "id",
    "name",
    "role",
    "value",
    "placeholder",
    "data-date-format",
    "alt",
    "aria-label",
    "aria-expanded",
    "data-state",
    "aria-checked",
    "aria-valuemin",
    "aria-valuemax",
    "aria-valuenow",
    "aria-placeholder",
    "pattern",
    "min",
    "max",
    "minlength",
    "maxlength",
    "step",
    "accept",
    "multiple",
    "inputmode",
    "autocomplete",
    "data-mask",
    "data-inputmask",
    "data-datepicker",
    "format",
    "expected_format",
    "contenteditable",
    "pseudo",
    "selected",
    "expanded",
    "pressed",
    "disabled",
    "invalid",
    "valuemin",
    "valuemax",
    "valuenow",
    "keyshortcuts",
    "haspopup",
    "multiselectable",
    "required",
    "valuetext",
    "level",
    "busy",
    "live",
    "ax_name",
];

/// Semantic role inferred from element structure and attributes
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum SemanticRole {
    /// Search input or search form
    SearchForm,
    /// Login or authentication form
    LoginForm,
    /// Registration form
    RegistrationForm,
    /// Navigation menu or links
    Navigation,
    /// Pagination controls (next/prev/page numbers)
    Pagination,
    /// Product listing or product card
    ProductCard,
    /// Article or blog post content
    Article,
    /// Filter or sort controls
    FilterPanel,
    /// Primary call-to-action button
    PrimaryAction,
    /// Secondary action button
    SecondaryAction,
    /// Form submission button
    SubmitButton,
    /// Input field for text entry
    TextInput,
    /// Dropdown or select element
    Dropdown,
    /// Checkbox or radio group
    ToggleGroup,
    /// Date or time picker
    DatePicker,
    /// File upload input
    FileUpload,
    /// CAPTCHA or verification challenge
    Captcha,
    /// Cookie consent banner
    CookieConsent,
    /// Advertisement or promotional content
    Advertisement,
    /// Footer content
    Footer,
    /// Header or banner area
    Header,
    /// Sidebar or secondary content
    Sidebar,
    /// Main content area
    MainContent,
    /// Unknown or unclassified
    Unknown,
}

/// Inferred intent of the overall page
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum PageIntent {
    /// Login or authentication page
    Login,
    /// Search results page
    SearchResults,
    /// Product listing / catalog
    ProductListing,
    /// Individual product detail page
    ProductDetail,
    /// Article or blog post
    Article,
    /// Form submission page (contact, survey, etc.)
    FormPage,
    /// Checkout or payment flow
    Checkout,
    /// Error page (404, 500, maintenance)
    ErrorPage,
    /// CAPTCHA or verification challenge
    Captcha,
    /// Cookie consent or privacy notice
    CookieConsent,
    /// Generic content / landing page
    Landing,
    /// Unknown / undetermined
    Unknown,
}

/// DOM element that was interacted with
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DOMInteractedElement {
    /// Index of the element
    pub index: u32,
    /// Backend node ID of the element
    pub backend_node_id: Option<u32>,
    /// HTML tag of the element
    pub tag: String,
    /// Text content of the element
    pub text: Option<String>,
    /// Attributes of the element
    pub attributes: HashMap<String, String>,
    /// CSS selector of the element
    pub selector: Option<String>,
    /// Inferred semantic role of the element
    pub semantic_role: Option<SemanticRole>,
    /// Human-readable description of what this element does
    pub semantic_affordance: Option<String>,
    /// Confidence score (0.0-1.0) of the semantic inference
    pub semantic_confidence: f32,
}

impl DOMInteractedElement {
    /// Converts the element to a dictionary
    pub fn to_dict(&self) -> HashMap<String, serde_json::Value> {
        let val = serde_json::to_value(self).unwrap();
        match val {
            serde_json::Value::Object(map) => map.into_iter().collect(),
            other => {
                let mut map = HashMap::new();
                map.insert("value".to_string(), other);
                map
            }
        }
    }
}

/// Serialized DOM state for text processing
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SerializedDOMState {
    /// HTML representation of the DOM
    pub html: Option<String>,
    /// Text content of the DOM
    pub text: Option<String>,
    /// Markdown representation of the DOM
    pub markdown: Option<String>,
    /// List of DOM elements
    pub elements: Vec<DOMElement>,
    /// Selector map for DOM elements
    pub selector_map: HashMap<u32, DOMInteractedElement>,
    /// Inferred intent of the page
    pub page_intent: Option<PageIntent>,
    /// Confidence score for the page intent inference
    pub page_intent_confidence: f32,
}

impl SerializedDOMState {
    /// Get text representation of the DOM state
    pub fn text_representation(&self, _include_attributes: Option<&[&str]>) -> Option<String> {
        // Prefer markdown, then text, then HTML
        if let Some(ref markdown) = self.markdown {
            return Some(markdown.clone());
        }
        if let Some(ref text) = self.text {
            return Some(text.clone());
        }
        if let Some(ref html) = self.html {
            return Some(html.clone());
        }
        None
    }
}

/// DOM element representation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DOMElement {
    /// Index of the element
    pub index: u32,
    /// HTML tag of the element
    pub tag: String,
    /// Text content of the element
    pub text: Option<String>,
    /// Attributes of the element
    pub attributes: HashMap<String, String>,
    /// Child elements
    pub children: Vec<DOMElement>,
}

/// Selector map for DOM elements
pub type DOMSelectorMap = HashMap<u32, DOMInteractedElement>;

/// DOM node types based on the DOM specification
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum NodeType {
    /// Element node
    ElementNode = 1,
    /// Attribute node
    AttributeNode = 2,
    /// Text node
    TextNode = 3,
    /// CDATA section node
    CdataSectionNode = 4,
    /// Entity reference node
    EntityReferenceNode = 5,
    /// Entity node
    EntityNode = 6,
    /// Processing instruction node
    ProcessingInstructionNode = 7,
    /// Comment node
    CommentNode = 8,
    /// Document node
    DocumentNode = 9,
    /// Document type node
    DocumentTypeNode = 10,
    /// Document fragment node
    DocumentFragmentNode = 11,
    /// Notation node
    NotationNode = 12,
}

/// DOM rectangle for bounding boxes
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct DOMRect {
    /// X coordinate
    pub x: f64,
    /// Y coordinate
    pub y: f64,
    /// Width of the rectangle
    pub width: f64,
    /// Height of the rectangle
    pub height: f64,
}

impl DOMRect {
    /// Creates a new DOM rectangle
    pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self {
        Self {
            x,
            y,
            width,
            height,
        }
    }
}

/// Enhanced accessibility property
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnhancedAXProperty {
    /// Name of the property
    pub name: String,
    /// Value of the property
    pub value: Option<serde_json::Value>,
}

/// Enhanced accessibility node
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnhancedAXNode {
    /// Accessibility node ID
    pub ax_node_id: String,
    /// Whether the node is ignored
    pub ignored: bool,
    /// Role of the node
    pub role: Option<String>,
    /// Name of the node
    pub name: Option<String>,
    /// Description of the node
    pub description: Option<String>,
    /// Properties of the node
    pub properties: Option<Vec<EnhancedAXProperty>>,
    /// IDs of child nodes
    pub child_ids: Option<Vec<String>>,
}

/// Enhanced snapshot node with layout information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnhancedSnapshotNode {
    /// Whether the node is clickable
    pub is_clickable: Option<bool>,
    /// Cursor style of the node
    pub cursor_style: Option<String>,
    /// Bounding rectangle
    pub bounds: Option<DOMRect>,
    /// Client rectangle
    pub client_rects: Option<DOMRect>,
    /// Scroll rectangle
    pub scroll_rects: Option<DOMRect>,
    /// Computed CSS styles
    pub computed_styles: Option<HashMap<String, String>>,
    /// Paint order
    pub paint_order: Option<i32>,
    /// Stacking contexts
    pub stacking_contexts: Option<i32>,
}

/// Enhanced DOM tree node combining DOM, AX, and Snapshot data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnhancedDOMTreeNode {
    /// Node ID
    pub node_id: u64,
    /// Backend node ID
    pub backend_node_id: u64,
    /// Type of the node
    pub node_type: NodeType,
    /// Name of the node
    pub node_name: String,
    /// Value of the node
    pub node_value: String,
    /// Attributes of the node
    pub attributes: HashMap<String, String>,
    /// Whether the node is scrollable
    pub is_scrollable: Option<bool>,
    /// Whether the node is visible
    pub is_visible: Option<bool>,
    /// Absolute position of the node
    pub absolute_position: Option<DOMRect>,

    // Frame information
    /// Target ID
    pub target_id: String,
    /// Frame ID
    pub frame_id: Option<String>,
    /// Session ID
    pub session_id: Option<String>,
    /// Content document
    pub content_document: Option<Box<EnhancedDOMTreeNode>>,

    // Shadow DOM
    /// Shadow root type
    pub shadow_root_type: Option<String>,
    /// Shadow roots
    pub shadow_roots: Option<Vec<EnhancedDOMTreeNode>>,

    // Navigation
    /// Parent node
    pub parent_node: Option<Box<EnhancedDOMTreeNode>>,
    /// Child nodes
    pub children_nodes: Option<Vec<EnhancedDOMTreeNode>>,

    // AX node data
    /// Accessibility node data
    pub ax_node: Option<EnhancedAXNode>,

    // Snapshot node data
    /// Snapshot node data
    pub snapshot_node: Option<EnhancedSnapshotNode>,

    // Semantic perception data
    /// Inferred semantic role of this node
    pub semantic_role: Option<SemanticRole>,
    /// Confidence score (0.0-1.0) of the semantic inference
    pub semantic_confidence: f32,

    // UUID for tracking
    /// UUID for tracking
    pub uuid: String,
}

impl EnhancedDOMTreeNode {
    /// Creates a new enhanced DOM tree node
    pub fn new(
        node_id: u64,
        backend_node_id: u64,
        node_type: NodeType,
        node_name: String,
        node_value: String,
        target_id: String,
    ) -> Self {
        let node_name = node_name.to_lowercase();
        Self {
            node_id,
            backend_node_id,
            node_type,
            node_name,
            node_value,
            attributes: HashMap::new(),
            is_scrollable: None,
            is_visible: None,
            absolute_position: None,
            target_id,
            frame_id: None,
            session_id: None,
            content_document: None,
            shadow_root_type: None,
            shadow_roots: None,
            parent_node: None,
            children_nodes: None,
            ax_node: None,
            snapshot_node: None,
            semantic_role: None,
            semantic_confidence: 0.0,
            uuid: Uuid::now_v7().to_string(),
        }
    }

    /// Returns the tag name of the node (already lowercased at construction)
    pub fn tag_name(&self) -> String {
        self.node_name.clone()
    }
}