context_snapshot/
context_snapshot.rs1use std::collections::HashMap;
8
9use cel_context::{
10 Bounds, ContentRole, ContextContribution, ContextElement, ContextMerger, ContextSource,
11 ElementState, StreamStatus,
12};
13
14fn main() {
15 let json_output = std::env::args().any(|arg| arg == "--json");
16
17 let mut merger = ContextMerger::new().with_defaults("Example CRM", "Customer Detail");
18 merger.push(
19 ContextContribution::new(
20 "crm_api",
21 vec![
22 element(
23 "crm:title",
24 "heading",
25 "Customer: Acme Corp",
26 ContextSource::NativeApi,
27 None,
28 ),
29 element(
30 "crm:button:save",
31 "button",
32 "Save changes",
33 ContextSource::NativeApi,
34 Some(Bounds {
35 x: 720,
36 y: 64,
37 width: 128,
38 height: 36,
39 }),
40 ),
41 ],
42 )
43 .with_app("Example CRM")
44 .with_window("Customer Detail")
45 .with_stream_status(StreamStatus {
46 accessibility: false,
47 display: false,
48 network: false,
49 signals: false,
50 vision: false,
51 audio_capture: false,
52 }),
53 );
54 merger.push(ContextContribution::new(
55 "browser_dom",
56 vec![element(
57 "dom:input:notes",
58 "textbox",
59 "Internal notes",
60 ContextSource::Cdp,
61 Some(Bounds {
62 x: 160,
63 y: 420,
64 width: 520,
65 height: 120,
66 }),
67 )],
68 ));
69
70 let ctx = merger.build();
71
72 if json_output {
73 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
74 return;
75 }
76
77 println!("=== CEL Context Snapshot ===");
78 println!("App: {}", ctx.app);
79 println!("Window: {}", ctx.window);
80 println!("Timestamp: {} ms", ctx.timestamp_ms);
81 println!("Elements: {}", ctx.elements.len());
82 println!();
83
84 for (i, elem) in ctx.elements.iter().enumerate() {
85 let label = elem.label.as_deref().unwrap_or("(no label)");
86 let bounds = elem
87 .bounds
88 .as_ref()
89 .map(|b| format!("[{},{} {}x{}]", b.x, b.y, b.width, b.height))
90 .unwrap_or_else(|| "(no bounds)".into());
91 println!(
92 " {:>2}. [{:.2}] {:12} {:22} {} {:?}",
93 i + 1,
94 elem.confidence,
95 elem.element_type,
96 label,
97 bounds,
98 elem.source
99 );
100 }
101}
102
103fn element(
104 id: &str,
105 element_type: &str,
106 label: &str,
107 source: ContextSource,
108 bounds: Option<Bounds>,
109) -> ContextElement {
110 ContextElement {
111 id: id.into(),
112 label: Some(label.into()),
113 description: None,
114 element_type: element_type.into(),
115 value: None,
116 bounds,
117 state: ElementState::default(),
118 parent_id: None,
119 actions: Vec::new(),
120 confidence: 0.0,
121 source,
122 content_role: ContentRole::Interactive,
123 properties: HashMap::new(),
124 }
125}