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 /// Target webview label.
143 pub webview_label: Option<String>,
144}
145
146// ── input ───────────────────────────────────────────────────────────────────
147
148/// Action for the compound `input` tool.
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
150#[serde(rename_all = "snake_case")]
151pub enum InputAction {
152 /// Set an input element's value directly.
153 Fill,
154 /// Type text character-by-character.
155 TypeText,
156 /// Press a keyboard key.
157 PressKey,
158}
159
160impl fmt::Display for InputAction {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 match self {
163 Self::Fill => f.write_str("fill"),
164 Self::TypeText => f.write_str("type_text"),
165 Self::PressKey => f.write_str("press_key"),
166 }
167 }
168}
169
170/// Parameters for the compound `input` tool (fill, `type_text`, `press_key`).
171#[derive(Debug, Deserialize, JsonSchema)]
172pub struct InputParams {
173 /// Action to perform: fill, `type_text`, `press_key`.
174 pub action: InputAction,
175 /// Ref handle ID of the target element. Required for fill and `type_text`.
176 pub ref_id: Option<String>,
177 /// Value to set (for fill action).
178 pub value: Option<String>,
179 /// Text to type character-by-character (for `type_text` action).
180 pub text: Option<String>,
181 /// Key to press (for `press_key` action, e.g. "Enter", "Escape", "Tab", "`ArrowDown`").
182 pub key: Option<String>,
183 /// Target webview label.
184 pub webview_label: Option<String>,
185}
186
187// ── window ──────────────────────────────────────────────────────────────────
188
189/// Action for the compound `window` tool.
190#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
191#[serde(rename_all = "snake_case")]
192pub enum WindowAction {
193 /// Get the current state of a window.
194 GetState,
195 /// List all window labels.
196 List,
197 /// Manage a window (minimize, maximize, close, etc.).
198 Manage,
199 /// Resize a window.
200 Resize,
201 /// Move a window to a new position.
202 MoveTo,
203 /// Set a window's title.
204 SetTitle,
205}
206
207impl fmt::Display for WindowAction {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 match self {
210 Self::GetState => f.write_str("get_state"),
211 Self::List => f.write_str("list"),
212 Self::Manage => f.write_str("manage"),
213 Self::Resize => f.write_str("resize"),
214 Self::MoveTo => f.write_str("move_to"),
215 Self::SetTitle => f.write_str("set_title"),
216 }
217 }
218}
219
220/// Window management sub-action for the `manage` action.
221#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
222#[serde(rename_all = "snake_case")]
223pub enum ManageAction {
224 /// Minimize the window.
225 Minimize,
226 /// Restore from minimized state.
227 Unminimize,
228 /// Maximize the window.
229 Maximize,
230 /// Restore from maximized state.
231 Unmaximize,
232 /// Close the window.
233 Close,
234 /// Focus the window.
235 Focus,
236 /// Show the window.
237 Show,
238 /// Hide the window.
239 Hide,
240 /// Enter fullscreen mode.
241 Fullscreen,
242 /// Exit fullscreen mode.
243 Unfullscreen,
244 /// Set the window to always be on top.
245 AlwaysOnTop,
246 /// Remove the always-on-top flag.
247 NotAlwaysOnTop,
248}
249
250impl ManageAction {
251 /// Returns the `snake_case` string for bridge consumption.
252 #[must_use]
253 pub fn as_str(self) -> &'static str {
254 match self {
255 Self::Minimize => "minimize",
256 Self::Unminimize => "unminimize",
257 Self::Maximize => "maximize",
258 Self::Unmaximize => "unmaximize",
259 Self::Close => "close",
260 Self::Focus => "focus",
261 Self::Show => "show",
262 Self::Hide => "hide",
263 Self::Fullscreen => "fullscreen",
264 Self::Unfullscreen => "unfullscreen",
265 Self::AlwaysOnTop => "always_on_top",
266 Self::NotAlwaysOnTop => "not_always_on_top",
267 }
268 }
269}
270
271impl fmt::Display for ManageAction {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 f.write_str(self.as_str())
274 }
275}
276
277/// Parameters for the compound `window` tool (`get_state`, list, manage, resize, move, title).
278#[derive(Debug, Deserialize, JsonSchema)]
279pub struct WindowParams {
280 /// Action to perform: `get_state`, list, manage, resize, `move_to`, `set_title`.
281 pub action: WindowAction,
282 /// Target window label.
283 pub label: Option<String>,
284 /// Window management action (for manage): minimize, unminimize, maximize, unmaximize, close, focus, show, hide, fullscreen, unfullscreen, `always_on_top`, `not_always_on_top`.
285 pub manage_action: Option<ManageAction>,
286 /// Width in logical pixels (for resize).
287 pub width: Option<u32>,
288 /// Height in logical pixels (for resize).
289 pub height: Option<u32>,
290 /// X position in logical pixels (for `move_to`).
291 pub x: Option<i32>,
292 /// Y position in logical pixels (for `move_to`).
293 pub y: Option<i32>,
294 /// New window title (for `set_title`).
295 pub title: Option<String>,
296}
297
298// ── storage ─────────────────────────────────────────────────────────────────
299
300/// Action for the compound `storage` tool.
301#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
302#[serde(rename_all = "snake_case")]
303pub enum StorageAction {
304 /// Read a value from storage.
305 Get,
306 /// Write a value to storage.
307 Set,
308 /// Delete a value from storage.
309 Delete,
310 /// Get all cookies.
311 GetCookies,
312}
313
314impl fmt::Display for StorageAction {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 match self {
317 Self::Get => f.write_str("get"),
318 Self::Set => f.write_str("set"),
319 Self::Delete => f.write_str("delete"),
320 Self::GetCookies => f.write_str("get_cookies"),
321 }
322 }
323}
324
325/// Parameters for the compound `storage` tool (get, set, delete, `get_cookies`).
326#[derive(Debug, Deserialize, JsonSchema)]
327pub struct StorageParams {
328 /// Action to perform: get, set, delete, `get_cookies`.
329 pub action: StorageAction,
330 /// Storage type for get/set/delete. Defaults to local if omitted.
331 pub storage_type: Option<StorageType>,
332 /// Key to read, write, or delete.
333 pub key: Option<String>,
334 /// Value to store (for set action). Will be JSON-serialized if not a string.
335 pub value: Option<serde_json::Value>,
336 /// Target webview label.
337 pub webview_label: Option<String>,
338}
339
340// ── navigate ────────────────────────────────────────────────────────────────
341
342/// Action for the compound `navigate` tool.
343#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
344#[serde(rename_all = "snake_case")]
345pub enum NavigateAction {
346 /// Navigate to a URL.
347 GoTo,
348 /// Navigate back in browser history.
349 GoBack,
350 /// Get the navigation history log.
351 GetHistory,
352 /// Set an auto-response for browser dialogs.
353 SetDialogResponse,
354 /// Get the dialog event log.
355 GetDialogLog,
356}
357
358impl fmt::Display for NavigateAction {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 match self {
361 Self::GoTo => f.write_str("go_to"),
362 Self::GoBack => f.write_str("go_back"),
363 Self::GetHistory => f.write_str("get_history"),
364 Self::SetDialogResponse => f.write_str("set_dialog_response"),
365 Self::GetDialogLog => f.write_str("get_dialog_log"),
366 }
367 }
368}
369
370/// Parameters for the compound `navigate` tool (`go_to`, `go_back`, history, dialogs).
371#[derive(Debug, Deserialize, JsonSchema)]
372pub struct NavigateParams {
373 /// Action to perform: `go_to`, `go_back`, `get_history`, `set_dialog_response`, `get_dialog_log`.
374 pub action: NavigateAction,
375 /// URL to navigate to (for `go_to` action).
376 pub url: Option<String>,
377 /// Dialog type (for `set_dialog_response`).
378 pub dialog_type: Option<DialogType>,
379 /// Dialog action (for `set_dialog_response`).
380 pub dialog_action: Option<DialogAction>,
381 /// Response text for prompt dialogs (for `set_dialog_response`).
382 pub text: Option<String>,
383 /// Target webview label.
384 pub webview_label: Option<String>,
385}
386
387// ── recording ───────────────────────────────────────────────────────────────
388
389/// Action for the compound `recording` tool.
390#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
391#[serde(rename_all = "snake_case")]
392pub enum RecordingAction {
393 /// Begin recording events.
394 Start,
395 /// Stop recording and return the session.
396 Stop,
397 /// Save a state checkpoint.
398 Checkpoint,
399 /// List all checkpoints in the current session.
400 ListCheckpoints,
401 /// Get events since an index.
402 GetEvents,
403 /// Get events between two checkpoints.
404 EventsBetween,
405 /// Get an IPC replay sequence.
406 GetReplay,
407 /// Export the current session as JSON.
408 Export,
409 /// Import a previously exported session.
410 Import,
411 /// Replay recorded IPC commands and compare responses to baseline.
412 Replay,
413 /// Immediately drain pending bridge events into the recording (no 1-second wait).
414 Flush,
415}
416
417impl fmt::Display for RecordingAction {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 match self {
420 Self::Start => f.write_str("start"),
421 Self::Stop => f.write_str("stop"),
422 Self::Checkpoint => f.write_str("checkpoint"),
423 Self::ListCheckpoints => f.write_str("list_checkpoints"),
424 Self::GetEvents => f.write_str("get_events"),
425 Self::EventsBetween => f.write_str("events_between"),
426 Self::GetReplay => f.write_str("get_replay"),
427 Self::Export => f.write_str("export"),
428 Self::Import => f.write_str("import"),
429 Self::Replay => f.write_str("replay"),
430 Self::Flush => f.write_str("flush"),
431 }
432 }
433}
434
435/// Parameters for the compound `recording` tool (start, stop, checkpoint, replay, export, import).
436#[derive(Debug, Deserialize, JsonSchema)]
437pub struct RecordingParams {
438 /// Action to perform: start, stop, checkpoint, `list_checkpoints`, `get_events`, `events_between`, `get_replay`, export, import, replay, flush.
439 pub action: RecordingAction,
440 /// Session ID (for start — optional, UUID generated if omitted).
441 pub session_id: Option<String>,
442 /// Checkpoint ID (for checkpoint, required).
443 pub checkpoint_id: Option<String>,
444 /// Checkpoint label (for checkpoint, optional). Also accepts `label` as an alias.
445 #[serde(alias = "label")]
446 pub checkpoint_label: Option<String>,
447 /// State snapshot as JSON (for checkpoint).
448 pub state: Option<serde_json::Value>,
449 /// Starting checkpoint ID (for `events_between`).
450 pub from: Option<String>,
451 /// Ending checkpoint ID (for `events_between`).
452 pub to: Option<String>,
453 /// Only return events after this index (for `get_events`).
454 pub since_index: Option<usize>,
455 /// JSON string of a previously exported `RecordedSession` (for import).
456 pub session_json: Option<String>,
457 /// Target webview label (for replay).
458 pub webview_label: Option<String>,
459}
460
461// ── inspect ─────────────────────────────────────────────────────────────────
462
463/// Action for the compound `inspect` tool.
464#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
465#[serde(rename_all = "snake_case")]
466pub enum InspectAction {
467 /// Get computed CSS styles for an element.
468 GetStyles,
469 /// Get bounding boxes for elements.
470 GetBoundingBoxes,
471 /// Add a debug highlight overlay to an element.
472 Highlight,
473 /// Remove all debug highlight overlays.
474 ClearHighlights,
475 /// Run an accessibility audit.
476 AuditAccessibility,
477 /// Get performance metrics (timing, heap, DOM).
478 GetPerformance,
479}
480
481impl fmt::Display for InspectAction {
482 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483 match self {
484 Self::GetStyles => f.write_str("get_styles"),
485 Self::GetBoundingBoxes => f.write_str("get_bounding_boxes"),
486 Self::Highlight => f.write_str("highlight"),
487 Self::ClearHighlights => f.write_str("clear_highlights"),
488 Self::AuditAccessibility => f.write_str("audit_accessibility"),
489 Self::GetPerformance => f.write_str("get_performance"),
490 }
491 }
492}
493
494/// Parameters for the compound `inspect` tool (styles, bounding boxes, highlight, a11y, perf).
495#[derive(Debug, Deserialize, JsonSchema)]
496pub struct InspectParams {
497 /// Action to perform: `get_styles`, `get_bounding_boxes`, highlight, `clear_highlights`, `audit_accessibility`, `get_performance`.
498 pub action: InspectAction,
499 /// Ref handle ID (for `get_styles`, highlight).
500 pub ref_id: Option<String>,
501 /// List of ref handle IDs (for `get_bounding_boxes`).
502 pub ref_ids: Option<Vec<String>>,
503 /// CSS property names to return (for `get_styles` — if omitted, returns key properties).
504 pub properties: Option<Vec<String>>,
505 /// CSS color for the highlight overlay (for highlight, default: "rgba(255, 0, 0, 0.3)").
506 pub color: Option<String>,
507 /// Text label displayed above the highlight (for highlight).
508 #[serde(rename = "highlight_label")]
509 pub label: Option<String>,
510 /// Target webview label.
511 pub webview_label: Option<String>,
512}
513
514// ── css ─────────────────────────────────────────────────────────────────────
515
516/// Action for the compound `css` tool.
517#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
518#[serde(rename_all = "snake_case")]
519pub enum CssAction {
520 /// Inject custom CSS into the page.
521 Inject,
522 /// Remove previously injected CSS.
523 Remove,
524}
525
526impl fmt::Display for CssAction {
527 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
528 match self {
529 Self::Inject => f.write_str("inject"),
530 Self::Remove => f.write_str("remove"),
531 }
532 }
533}
534
535/// Parameters for the compound `css` tool (inject, remove).
536#[derive(Debug, Deserialize, JsonSchema)]
537pub struct CssParams {
538 /// Action to perform: inject, remove.
539 pub action: CssAction,
540 /// CSS text to inject (for inject action).
541 pub css: Option<String>,
542 /// Target webview label.
543 pub webview_label: Option<String>,
544}
545
546// ── logs ────────────────────────────────────────────────────────────────────
547
548/// Action for the compound `logs` tool.
549#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
550#[serde(rename_all = "snake_case")]
551pub enum LogsAction {
552 /// Get captured console.log/warn/error entries.
553 Console,
554 /// Get intercepted fetch/XHR network requests.
555 Network,
556 /// Get IPC call log.
557 Ipc,
558 /// Get URL change history.
559 Navigation,
560 /// Get alert/confirm/prompt dialog events.
561 Dialogs,
562 /// Get combined event stream.
563 Events,
564 /// Find slow IPC calls exceeding a threshold.
565 SlowIpc,
566}
567
568impl fmt::Display for LogsAction {
569 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
570 match self {
571 Self::Console => f.write_str("console"),
572 Self::Network => f.write_str("network"),
573 Self::Ipc => f.write_str("ipc"),
574 Self::Navigation => f.write_str("navigation"),
575 Self::Dialogs => f.write_str("dialogs"),
576 Self::Events => f.write_str("events"),
577 Self::SlowIpc => f.write_str("slow_ipc"),
578 }
579 }
580}
581
582/// Parameters for the compound `logs` tool (console, network, ipc, navigation, dialogs, events).
583#[derive(Debug, Deserialize, JsonSchema)]
584pub struct LogsParams {
585 /// Action to perform: console, network, ipc, navigation, dialogs, events, `slow_ipc`.
586 pub action: LogsAction,
587 /// Only return entries after this Unix timestamp in milliseconds (for console, events).
588 pub since: Option<f64>,
589 /// Filter by URL substring (for network).
590 pub filter: Option<String>,
591 /// Maximum number of entries to return (for ipc, network, `slow_ipc`).
592 pub limit: Option<usize>,
593 /// Threshold in milliseconds for slow IPC calls (for `slow_ipc`).
594 pub threshold_ms: Option<u64>,
595 /// When true (for ipc action), await up to 500ms for the latest IPC entry's
596 /// response body to be fully captured. Uses event-driven signaling from the
597 /// fetch interceptor rather than polling.
598 pub wait_for_capture: Option<bool>,
599 /// Target webview label.
600 pub webview_label: Option<String>,
601}