Skip to main content

victauri_plugin/mcp/
compound_params.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4
5// ── Enums ──────────────────────────────────────────────────────────────────
6
7/// Web storage type for browser storage operations.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
9#[serde(rename_all = "snake_case")]
10pub enum StorageType {
11    /// Browser localStorage (persistent across sessions).
12    Local,
13    /// Browser sessionStorage (cleared when tab closes).
14    Session,
15}
16
17impl StorageType {
18    /// Returns the JavaScript property name for this storage type.
19    #[must_use]
20    pub fn js_property(self) -> &'static str {
21        match self {
22            Self::Local => "localStorage",
23            Self::Session => "sessionStorage",
24        }
25    }
26}
27
28impl fmt::Display for StorageType {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            Self::Local => f.write_str("local"),
32            Self::Session => f.write_str("session"),
33        }
34    }
35}
36
37/// Browser dialog type for dialog response configuration.
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
39#[serde(rename_all = "snake_case")]
40pub enum DialogType {
41    /// JavaScript `alert()` dialog.
42    Alert,
43    /// JavaScript `confirm()` dialog.
44    Confirm,
45    /// JavaScript `prompt()` dialog.
46    Prompt,
47}
48
49impl DialogType {
50    /// Returns the lowercase string for JS bridge consumption.
51    #[must_use]
52    pub fn as_str(self) -> &'static str {
53        match self {
54            Self::Alert => "alert",
55            Self::Confirm => "confirm",
56            Self::Prompt => "prompt",
57        }
58    }
59}
60
61impl fmt::Display for DialogType {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        f.write_str(self.as_str())
64    }
65}
66
67/// Action to take on a browser dialog.
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
69#[serde(rename_all = "snake_case")]
70pub enum DialogAction {
71    /// Accept the dialog (click OK/Yes).
72    Accept,
73    /// Dismiss the dialog (click Cancel/No).
74    Dismiss,
75}
76
77impl DialogAction {
78    /// Returns the lowercase string for JS bridge consumption.
79    #[must_use]
80    pub fn as_str(self) -> &'static str {
81        match self {
82            Self::Accept => "accept",
83            Self::Dismiss => "dismiss",
84        }
85    }
86}
87
88impl fmt::Display for DialogAction {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        f.write_str(self.as_str())
91    }
92}
93
94// ── interact ────────────────────────────────────────────────────────────────
95
96/// Action for the compound `interact` tool.
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
98#[serde(rename_all = "snake_case")]
99pub enum InteractAction {
100    /// Click an element.
101    Click,
102    /// Double-click an element.
103    DoubleClick,
104    /// Hover over an element.
105    Hover,
106    /// Focus an element.
107    Focus,
108    /// Scroll an element into view.
109    ScrollIntoView,
110    /// Select an option in a `<select>` element.
111    SelectOption,
112}
113
114impl fmt::Display for InteractAction {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        match self {
117            Self::Click => f.write_str("click"),
118            Self::DoubleClick => f.write_str("double_click"),
119            Self::Hover => f.write_str("hover"),
120            Self::Focus => f.write_str("focus"),
121            Self::ScrollIntoView => f.write_str("scroll_into_view"),
122            Self::SelectOption => f.write_str("select_option"),
123        }
124    }
125}
126
127/// Parameters for the compound `interact` tool (click, hover, focus, scroll, select).
128#[derive(Debug, Deserialize, JsonSchema)]
129pub struct InteractParams {
130    /// Action to perform: click, `double_click`, hover, focus, `scroll_into_view`, `select_option`.
131    pub action: InteractAction,
132    /// Ref handle ID from a DOM snapshot (e.g. "e5"). Required for click, `double_click`, hover, focus, `select_option`.
133    pub ref_id: Option<String>,
134    /// Option values for `select_option` action.
135    pub values: Option<Vec<String>>,
136    /// Single option value for `select_option` (convenience alias for `values`).
137    pub value: Option<String>,
138    /// Horizontal scroll position (pixels). Used with `scroll_into_view` when `ref_id` is null.
139    pub x: Option<f64>,
140    /// Vertical scroll position (pixels). Used with `scroll_into_view` when `ref_id` is null.
141    pub y: Option<f64>,
142    /// If true, deliver a real OS mouse click (`isTrusted: true`) at the
143    /// element's center instead of a synthetic DOM click (for `click`). Falls
144    /// back with an error on platforms without native-input support. Currently
145    /// implemented on Windows.
146    pub trusted: Option<bool>,
147    /// Target webview label.
148    pub webview_label: Option<String>,
149}
150
151// ── input ───────────────────────────────────────────────────────────────────
152
153/// Action for the compound `input` tool.
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
155#[serde(rename_all = "snake_case")]
156pub enum InputAction {
157    /// Set an input element's value directly.
158    Fill,
159    /// Type text character-by-character.
160    TypeText,
161    /// Press a keyboard key.
162    PressKey,
163}
164
165impl fmt::Display for InputAction {
166    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167        match self {
168            Self::Fill => f.write_str("fill"),
169            Self::TypeText => f.write_str("type_text"),
170            Self::PressKey => f.write_str("press_key"),
171        }
172    }
173}
174
175/// Parameters for the compound `input` tool (fill, `type_text`, `press_key`).
176#[derive(Debug, Deserialize, JsonSchema)]
177pub struct InputParams {
178    /// Action to perform: fill, `type_text`, `press_key`.
179    pub action: InputAction,
180    /// Ref handle ID of the target element. Required for fill and `type_text`.
181    pub ref_id: Option<String>,
182    /// Value to set (for fill action).
183    pub value: Option<String>,
184    /// Text to type character-by-character (for `type_text` action).
185    pub text: Option<String>,
186    /// Key to press (for `press_key` action, e.g. "Enter", "Escape", "Tab", "`ArrowDown`").
187    pub key: Option<String>,
188    /// If true, deliver real OS keyboard input (`isTrusted: true`) instead of
189    /// synthetic DOM events — for `type_text`/`press_key`. The target element is
190    /// focused first (via `ref_id`). Falls back with an error on platforms
191    /// without native-input support. Currently implemented on Windows.
192    pub trusted: Option<bool>,
193    /// Target webview label.
194    pub webview_label: Option<String>,
195}
196
197// ── window ──────────────────────────────────────────────────────────────────
198
199/// Action for the compound `window` tool.
200#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
201#[serde(rename_all = "snake_case")]
202pub enum WindowAction {
203    /// Get the current state of a window.
204    GetState,
205    /// List all window labels.
206    List,
207    /// Manage a window (minimize, maximize, close, etc.).
208    Manage,
209    /// Resize a window.
210    Resize,
211    /// Move a window to a new position.
212    MoveTo,
213    /// Set a window's title.
214    SetTitle,
215}
216
217impl fmt::Display for WindowAction {
218    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219        match self {
220            Self::GetState => f.write_str("get_state"),
221            Self::List => f.write_str("list"),
222            Self::Manage => f.write_str("manage"),
223            Self::Resize => f.write_str("resize"),
224            Self::MoveTo => f.write_str("move_to"),
225            Self::SetTitle => f.write_str("set_title"),
226        }
227    }
228}
229
230/// Window management sub-action for the `manage` action.
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
232#[serde(rename_all = "snake_case")]
233pub enum ManageAction {
234    /// Minimize the window.
235    Minimize,
236    /// Restore from minimized state.
237    Unminimize,
238    /// Maximize the window.
239    Maximize,
240    /// Restore from maximized state.
241    Unmaximize,
242    /// Close the window.
243    Close,
244    /// Focus the window.
245    Focus,
246    /// Show the window.
247    Show,
248    /// Hide the window.
249    Hide,
250    /// Enter fullscreen mode.
251    Fullscreen,
252    /// Exit fullscreen mode.
253    Unfullscreen,
254    /// Set the window to always be on top.
255    AlwaysOnTop,
256    /// Remove the always-on-top flag.
257    NotAlwaysOnTop,
258}
259
260impl ManageAction {
261    /// Returns the `snake_case` string for bridge consumption.
262    #[must_use]
263    pub fn as_str(self) -> &'static str {
264        match self {
265            Self::Minimize => "minimize",
266            Self::Unminimize => "unminimize",
267            Self::Maximize => "maximize",
268            Self::Unmaximize => "unmaximize",
269            Self::Close => "close",
270            Self::Focus => "focus",
271            Self::Show => "show",
272            Self::Hide => "hide",
273            Self::Fullscreen => "fullscreen",
274            Self::Unfullscreen => "unfullscreen",
275            Self::AlwaysOnTop => "always_on_top",
276            Self::NotAlwaysOnTop => "not_always_on_top",
277        }
278    }
279}
280
281impl fmt::Display for ManageAction {
282    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283        f.write_str(self.as_str())
284    }
285}
286
287/// Parameters for the compound `window` tool (`get_state`, list, manage, resize, move, title).
288#[derive(Debug, Deserialize, JsonSchema)]
289pub struct WindowParams {
290    /// Action to perform: `get_state`, list, manage, resize, `move_to`, `set_title`.
291    pub action: WindowAction,
292    /// Target window label.
293    pub label: Option<String>,
294    /// Window management action (for manage): minimize, unminimize, maximize, unmaximize, close, focus, show, hide, fullscreen, unfullscreen, `always_on_top`, `not_always_on_top`.
295    pub manage_action: Option<ManageAction>,
296    /// Width in logical pixels (for resize).
297    pub width: Option<u32>,
298    /// Height in logical pixels (for resize).
299    pub height: Option<u32>,
300    /// X position in logical pixels (for `move_to`).
301    pub x: Option<i32>,
302    /// Y position in logical pixels (for `move_to`).
303    pub y: Option<i32>,
304    /// New window title (for `set_title`).
305    pub title: Option<String>,
306}
307
308// ── storage ─────────────────────────────────────────────────────────────────
309
310/// Action for the compound `storage` tool.
311#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
312#[serde(rename_all = "snake_case")]
313pub enum StorageAction {
314    /// Read a value from storage.
315    Get,
316    /// Write a value to storage.
317    Set,
318    /// Delete a value from storage.
319    Delete,
320    /// Get all cookies.
321    GetCookies,
322}
323
324impl fmt::Display for StorageAction {
325    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326        match self {
327            Self::Get => f.write_str("get"),
328            Self::Set => f.write_str("set"),
329            Self::Delete => f.write_str("delete"),
330            Self::GetCookies => f.write_str("get_cookies"),
331        }
332    }
333}
334
335/// Parameters for the compound `storage` tool (get, set, delete, `get_cookies`).
336#[derive(Debug, Deserialize, JsonSchema)]
337pub struct StorageParams {
338    /// Action to perform: get, set, delete, `get_cookies`.
339    pub action: StorageAction,
340    /// Storage type for get/set/delete. Defaults to local if omitted.
341    pub storage_type: Option<StorageType>,
342    /// Key to read, write, or delete.
343    pub key: Option<String>,
344    /// Value to store (for set action). Will be JSON-serialized if not a string.
345    pub value: Option<serde_json::Value>,
346    /// Target webview label.
347    pub webview_label: Option<String>,
348}
349
350// ── navigate ────────────────────────────────────────────────────────────────
351
352/// Action for the compound `navigate` tool.
353#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
354#[serde(rename_all = "snake_case")]
355pub enum NavigateAction {
356    /// Navigate to a URL.
357    GoTo,
358    /// Navigate back in browser history.
359    GoBack,
360    /// Get the navigation history log.
361    GetHistory,
362    /// Set an auto-response for browser dialogs.
363    SetDialogResponse,
364    /// Get the dialog event log.
365    GetDialogLog,
366}
367
368impl fmt::Display for NavigateAction {
369    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370        match self {
371            Self::GoTo => f.write_str("go_to"),
372            Self::GoBack => f.write_str("go_back"),
373            Self::GetHistory => f.write_str("get_history"),
374            Self::SetDialogResponse => f.write_str("set_dialog_response"),
375            Self::GetDialogLog => f.write_str("get_dialog_log"),
376        }
377    }
378}
379
380/// Parameters for the compound `navigate` tool (`go_to`, `go_back`, history, dialogs).
381#[derive(Debug, Deserialize, JsonSchema)]
382pub struct NavigateParams {
383    /// Action to perform: `go_to`, `go_back`, `get_history`, `set_dialog_response`, `get_dialog_log`.
384    pub action: NavigateAction,
385    /// URL to navigate to (for `go_to` action).
386    pub url: Option<String>,
387    /// Dialog type (for `set_dialog_response`).
388    pub dialog_type: Option<DialogType>,
389    /// Dialog action (for `set_dialog_response`).
390    pub dialog_action: Option<DialogAction>,
391    /// Response text for prompt dialogs (for `set_dialog_response`).
392    pub text: Option<String>,
393    /// Target webview label.
394    pub webview_label: Option<String>,
395}
396
397// ── recording ───────────────────────────────────────────────────────────────
398
399/// Action for the compound `recording` tool.
400#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
401#[serde(rename_all = "snake_case")]
402pub enum RecordingAction {
403    /// Begin recording events.
404    Start,
405    /// Stop recording and return the session.
406    Stop,
407    /// Save a state checkpoint.
408    Checkpoint,
409    /// List all checkpoints in the current session.
410    ListCheckpoints,
411    /// Get events since an index.
412    GetEvents,
413    /// Get events between two checkpoints.
414    EventsBetween,
415    /// Get an IPC replay sequence.
416    GetReplay,
417    /// Export the current session as JSON.
418    Export,
419    /// Import a previously exported session.
420    Import,
421    /// Replay recorded IPC commands and compare responses to baseline.
422    Replay,
423    /// Immediately drain pending bridge events into the recording (no 1-second wait).
424    Flush,
425}
426
427impl fmt::Display for RecordingAction {
428    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429        match self {
430            Self::Start => f.write_str("start"),
431            Self::Stop => f.write_str("stop"),
432            Self::Checkpoint => f.write_str("checkpoint"),
433            Self::ListCheckpoints => f.write_str("list_checkpoints"),
434            Self::GetEvents => f.write_str("get_events"),
435            Self::EventsBetween => f.write_str("events_between"),
436            Self::GetReplay => f.write_str("get_replay"),
437            Self::Export => f.write_str("export"),
438            Self::Import => f.write_str("import"),
439            Self::Replay => f.write_str("replay"),
440            Self::Flush => f.write_str("flush"),
441        }
442    }
443}
444
445/// Parameters for the compound `recording` tool (start, stop, checkpoint, replay, export, import).
446#[derive(Debug, Deserialize, JsonSchema)]
447pub struct RecordingParams {
448    /// Action to perform: start, stop, checkpoint, `list_checkpoints`, `get_events`, `events_between`, `get_replay`, export, import, replay, flush.
449    pub action: RecordingAction,
450    /// Session ID (for start — optional, UUID generated if omitted).
451    pub session_id: Option<String>,
452    /// Checkpoint ID (for checkpoint, required).
453    pub checkpoint_id: Option<String>,
454    /// Checkpoint label (for checkpoint, optional). Also accepts `label` as an alias.
455    #[serde(alias = "label")]
456    pub checkpoint_label: Option<String>,
457    /// State snapshot as JSON (for checkpoint).
458    pub state: Option<serde_json::Value>,
459    /// Starting checkpoint ID (for `events_between`).
460    pub from: Option<String>,
461    /// Ending checkpoint ID (for `events_between`).
462    pub to: Option<String>,
463    /// Only return events after this index (for `get_events`).
464    pub since_index: Option<usize>,
465    /// JSON string of a previously exported `RecordedSession` (for import).
466    pub session_json: Option<String>,
467    /// Target webview label (for replay).
468    pub webview_label: Option<String>,
469}
470
471// ── inspect ─────────────────────────────────────────────────────────────────
472
473/// Action for the compound `inspect` tool.
474#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
475#[serde(rename_all = "snake_case")]
476pub enum InspectAction {
477    /// Get computed CSS styles for an element.
478    GetStyles,
479    /// Get bounding boxes for elements.
480    GetBoundingBoxes,
481    /// Add a debug highlight overlay to an element.
482    Highlight,
483    /// Remove all debug highlight overlays.
484    ClearHighlights,
485    /// Run an accessibility audit.
486    AuditAccessibility,
487    /// Get performance metrics (timing, heap, DOM).
488    GetPerformance,
489}
490
491impl fmt::Display for InspectAction {
492    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493        match self {
494            Self::GetStyles => f.write_str("get_styles"),
495            Self::GetBoundingBoxes => f.write_str("get_bounding_boxes"),
496            Self::Highlight => f.write_str("highlight"),
497            Self::ClearHighlights => f.write_str("clear_highlights"),
498            Self::AuditAccessibility => f.write_str("audit_accessibility"),
499            Self::GetPerformance => f.write_str("get_performance"),
500        }
501    }
502}
503
504/// Parameters for the compound `inspect` tool (styles, bounding boxes, highlight, a11y, perf).
505#[derive(Debug, Deserialize, JsonSchema)]
506pub struct InspectParams {
507    /// Action to perform: `get_styles`, `get_bounding_boxes`, highlight, `clear_highlights`, `audit_accessibility`, `get_performance`.
508    pub action: InspectAction,
509    /// Ref handle ID (for `get_styles`, highlight).
510    pub ref_id: Option<String>,
511    /// List of ref handle IDs (for `get_bounding_boxes`).
512    pub ref_ids: Option<Vec<String>>,
513    /// CSS property names to return (for `get_styles` — if omitted, returns key properties).
514    pub properties: Option<Vec<String>>,
515    /// CSS color for the highlight overlay (for highlight, default: "rgba(255, 0, 0, 0.3)").
516    pub color: Option<String>,
517    /// Text label displayed above the highlight (for highlight).
518    #[serde(rename = "highlight_label")]
519    pub label: Option<String>,
520    /// Target webview label.
521    pub webview_label: Option<String>,
522}
523
524// ── css ─────────────────────────────────────────────────────────────────────
525
526/// Action for the compound `css` tool.
527#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
528#[serde(rename_all = "snake_case")]
529pub enum CssAction {
530    /// Inject custom CSS into the page.
531    Inject,
532    /// Remove previously injected CSS.
533    Remove,
534}
535
536impl fmt::Display for CssAction {
537    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538        match self {
539            Self::Inject => f.write_str("inject"),
540            Self::Remove => f.write_str("remove"),
541        }
542    }
543}
544
545/// Parameters for the compound `css` tool (inject, remove).
546#[derive(Debug, Deserialize, JsonSchema)]
547pub struct CssParams {
548    /// Action to perform: inject, remove.
549    pub action: CssAction,
550    /// CSS text to inject (for inject action).
551    pub css: Option<String>,
552    /// Target webview label.
553    pub webview_label: Option<String>,
554}
555
556// ── route (network interception) ──────────────────────────────────────────
557
558/// Action for the compound `route` tool.
559#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
560#[serde(rename_all = "snake_case")]
561pub enum RouteAction {
562    /// Add a network route rule.
563    Add,
564    /// List active route rules.
565    List,
566    /// Remove a route rule by id.
567    Clear,
568    /// Remove all route rules.
569    ClearAll,
570    /// Return the log of intercepted requests.
571    Matches,
572}
573
574impl fmt::Display for RouteAction {
575    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
576        match self {
577            Self::Add => f.write_str("add"),
578            Self::List => f.write_str("list"),
579            Self::Clear => f.write_str("clear"),
580            Self::ClearAll => f.write_str("clear_all"),
581            Self::Matches => f.write_str("matches"),
582        }
583    }
584}
585
586/// How a route rule's pattern is matched against the request URL.
587#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
588#[serde(rename_all = "snake_case")]
589pub enum RouteMatchType {
590    /// URL contains the pattern (default).
591    Substring,
592    /// Glob with `*` wildcards.
593    Glob,
594    /// JavaScript regular expression.
595    Regex,
596    /// Exact URL match.
597    Exact,
598}
599
600impl RouteMatchType {
601    /// Bridge string for this match type.
602    #[must_use]
603    pub fn as_str(self) -> &'static str {
604        match self {
605            Self::Substring => "substring",
606            Self::Glob => "glob",
607            Self::Regex => "regex",
608            Self::Exact => "exact",
609        }
610    }
611}
612
613/// What a matched route rule does to the request.
614#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
615#[serde(rename_all = "snake_case")]
616pub enum RouteBehavior {
617    /// Abort the request (the app sees a network failure).
618    Block,
619    /// Return a synthetic mock response (fetch only; XHR falls back to delay).
620    Fulfill,
621    /// Let the request proceed, but after `delay_ms` (latency injection).
622    Delay,
623}
624
625impl RouteBehavior {
626    /// Bridge string for this behavior.
627    #[must_use]
628    pub fn as_str(self) -> &'static str {
629        match self {
630            Self::Block => "block",
631            Self::Fulfill => "fulfill",
632            Self::Delay => "delay",
633        }
634    }
635}
636
637/// Parameters for the compound `route` tool (network interception / mock / block / delay).
638#[derive(Debug, Deserialize, JsonSchema)]
639pub struct RouteParams {
640    /// Action: add, list, clear, `clear_all`, matches.
641    pub action: RouteAction,
642    /// URL pattern to match (for add). Interpreted per `match_type`.
643    pub pattern: Option<String>,
644    /// How `pattern` is matched: substring (default), glob, regex, exact.
645    pub match_type: Option<RouteMatchType>,
646    /// Restrict to a single HTTP method (for add, optional).
647    pub method: Option<String>,
648    /// What the rule does: block, fulfill, delay (for add). Defaults to fulfill.
649    pub behavior: Option<RouteBehavior>,
650    /// Mock response status code (for fulfill). Default 200.
651    pub status: Option<u16>,
652    /// Mock response status text (for fulfill).
653    pub status_text: Option<String>,
654    /// Mock response headers as a JSON object (for fulfill).
655    pub headers: Option<serde_json::Value>,
656    /// Mock response body (for fulfill). Strings sent as-is; other JSON is serialized.
657    pub body: Option<serde_json::Value>,
658    /// Mock response content-type (for fulfill). Default "application/json".
659    pub content_type: Option<String>,
660    /// Delay in milliseconds (for delay, or to delay a fulfill).
661    pub delay_ms: Option<u64>,
662    /// Maximum times this rule fires (for add). 0 or omitted = unlimited.
663    pub times: Option<u64>,
664    /// Route rule id (for clear).
665    pub id: Option<u64>,
666    /// Maximum match-log entries to return (for matches).
667    pub limit: Option<usize>,
668    /// Target webview label.
669    pub webview_label: Option<String>,
670}
671
672// ── trace (screencast) ──────────────────────────────────────────────────────
673
674/// Action for the compound `trace` tool.
675#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
676#[serde(rename_all = "snake_case")]
677pub enum TraceAction {
678    /// Start capturing screenshots at a fixed interval.
679    Start,
680    /// Stop capturing and return a summary.
681    Stop,
682    /// Report whether a trace is active and how many frames are buffered.
683    Status,
684    /// Return captured frames (base64 PNGs).
685    Frames,
686}
687
688impl fmt::Display for TraceAction {
689    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690        match self {
691            Self::Start => f.write_str("start"),
692            Self::Stop => f.write_str("stop"),
693            Self::Status => f.write_str("status"),
694            Self::Frames => f.write_str("frames"),
695        }
696    }
697}
698
699/// Parameters for the compound `trace` tool (screencast / visual timeline).
700#[derive(Debug, Deserialize, JsonSchema)]
701pub struct TraceParams {
702    /// Action: start, stop, status, frames.
703    pub action: TraceAction,
704    /// Capture interval in milliseconds (for start). Default 500, min 50.
705    pub interval_ms: Option<u64>,
706    /// Maximum frames to retain in the ring buffer (for start). Default 60, max 600.
707    pub max_frames: Option<usize>,
708    /// If true (for start), also start the event recorder so the trace bundles
709    /// the IPC/DOM/console event timeline alongside the screencast.
710    pub with_events: Option<bool>,
711    /// Maximum frames to return (for frames). 0 or omitted returns all buffered.
712    pub limit: Option<usize>,
713    /// Target webview label to capture.
714    pub webview_label: Option<String>,
715}
716
717// ── logs ────────────────────────────────────────────────────────────────────
718
719/// Action for the compound `logs` tool.
720#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
721#[serde(rename_all = "snake_case")]
722pub enum LogsAction {
723    /// Get captured console.log/warn/error entries.
724    Console,
725    /// Get intercepted fetch/XHR network requests.
726    Network,
727    /// Get IPC call log.
728    Ipc,
729    /// Get URL change history.
730    Navigation,
731    /// Get alert/confirm/prompt dialog events.
732    Dialogs,
733    /// Get combined event stream.
734    Events,
735    /// Find slow IPC calls exceeding a threshold.
736    SlowIpc,
737}
738
739impl fmt::Display for LogsAction {
740    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
741        match self {
742            Self::Console => f.write_str("console"),
743            Self::Network => f.write_str("network"),
744            Self::Ipc => f.write_str("ipc"),
745            Self::Navigation => f.write_str("navigation"),
746            Self::Dialogs => f.write_str("dialogs"),
747            Self::Events => f.write_str("events"),
748            Self::SlowIpc => f.write_str("slow_ipc"),
749        }
750    }
751}
752
753/// Parameters for the compound `logs` tool (console, network, ipc, navigation, dialogs, events).
754#[derive(Debug, Deserialize, JsonSchema)]
755pub struct LogsParams {
756    /// Action to perform: console, network, ipc, navigation, dialogs, events, `slow_ipc`.
757    pub action: LogsAction,
758    /// Only return entries after this Unix timestamp in milliseconds (for console, events).
759    pub since: Option<f64>,
760    /// Filter by URL substring (for network).
761    pub filter: Option<String>,
762    /// Maximum number of entries to return (for ipc, network, `slow_ipc`).
763    pub limit: Option<usize>,
764    /// Threshold in milliseconds for slow IPC calls (for `slow_ipc`).
765    pub threshold_ms: Option<u64>,
766    /// When true (for ipc action), await up to 500ms for the latest IPC entry's
767    /// response body to be fully captured. Uses event-driven signaling from the
768    /// fetch interceptor rather than polling.
769    pub wait_for_capture: Option<bool>,
770    /// Target webview label.
771    pub webview_label: Option<String>,
772}