pub struct ContextMerger { /* private fields */ }Expand description
Generic merger for already-normalized context contributions.
cel-context deliberately does not know how to read accessibility, CDP,
OCR, network, or other live streams. Those sources should emit
ContextElements / ScreenContexts and feed them here.
Implementations§
Source§impl ContextMerger
impl ContextMerger
Sourcepub fn new() -> Self
pub fn new() -> Self
Examples found in repository?
10fn main() {
11 let mut merger = ContextMerger::new().with_defaults("Example App", "Main");
12 merger.push(ContextContribution::new(
13 "test_source",
14 vec![ContextElement {
15 id: "button:submit".into(),
16 label: Some("Submit".into()),
17 description: None,
18 element_type: "button".into(),
19 value: None,
20 bounds: Some(Bounds {
21 x: 100,
22 y: 200,
23 width: 120,
24 height: 32,
25 }),
26 state: ElementState {
27 focused: true,
28 ..Default::default()
29 },
30 parent_id: None,
31 actions: Vec::new(),
32 confidence: 0.0,
33 source: ContextSource::NativeApi,
34 content_role: ContentRole::Interactive,
35 properties: Default::default(),
36 }],
37 ));
38
39 let ctx = merger.build();
40 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
41
42 let reference = ctx.elements[0].to_reference(1920, 1080);
43 let resolved = cel_context::resolve_reference(&ctx, &reference);
44 println!(
45 "resolved reference: {:?}",
46 resolved.map(|el| el.id.as_str())
47 );
48
49 let mut watchdog = ContextWatchdog::new();
50 assert!(watchdog.tick(&ctx, true).is_empty());
51
52 let mut changed = ctx.clone();
53 changed.elements[0].state.focused = false;
54 let events = watchdog.tick(&changed, true);
55 println!("watchdog events: {events:?}");
56}More examples
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}Sourcepub fn with_all<A, D, N>(_accessibility: A, _display: D, _network: N) -> Self
pub fn with_all<A, D, N>(_accessibility: A, _display: D, _network: N) -> Self
Compatibility constructor for runtimes that still wire concrete source
crates externally. cel-context ignores the source object and only
merges already-normalized contributions.
Sourcepub fn with_display<A, D>(_accessibility: A, _display: D) -> Self
pub fn with_display<A, D>(_accessibility: A, _display: D) -> Self
Compatibility constructor for a runtime-provided display source.
Sourcepub fn with_signals<S>(self, _signals: S) -> Self
pub fn with_signals<S>(self, _signals: S) -> Self
Compatibility hook for a runtime-provided signal source.
Sourcepub fn with_vision<V>(self, _vision: V) -> Self
pub fn with_vision<V>(self, _vision: V) -> Self
Compatibility hook for a runtime-provided vision source.
Sourcepub fn with_runtime<R>(self, _runtime: R) -> Self
pub fn with_runtime<R>(self, _runtime: R) -> Self
Compatibility hook for a runtime-provided async runtime handle.
Sourcepub fn with_cdp_screenshot_fallback<F, T>(self, _fallback: F) -> Self
pub fn with_cdp_screenshot_fallback<F, T>(self, _fallback: F) -> Self
Compatibility hook for a runtime-provided screenshot fallback.
Sourcepub fn run_ocr_fallback(
&mut self,
_existing: &[ContextElement],
) -> Vec<ContextElement>
pub fn run_ocr_fallback( &mut self, _existing: &[ContextElement], ) -> Vec<ContextElement>
Compatibility hook retained until the live runtime owns OCR fallback.
Sourcepub fn recent_network_events(&self) -> &[ConnectionEvent]
pub fn recent_network_events(&self) -> &[ConnectionEvent]
Network events are now carried on ScreenContext, not owned by the merger.
Sourcepub fn with_defaults(
self,
app: impl Into<String>,
window: impl Into<String>,
) -> Self
pub fn with_defaults( self, app: impl Into<String>, window: impl Into<String>, ) -> Self
Examples found in repository?
10fn main() {
11 let mut merger = ContextMerger::new().with_defaults("Example App", "Main");
12 merger.push(ContextContribution::new(
13 "test_source",
14 vec![ContextElement {
15 id: "button:submit".into(),
16 label: Some("Submit".into()),
17 description: None,
18 element_type: "button".into(),
19 value: None,
20 bounds: Some(Bounds {
21 x: 100,
22 y: 200,
23 width: 120,
24 height: 32,
25 }),
26 state: ElementState {
27 focused: true,
28 ..Default::default()
29 },
30 parent_id: None,
31 actions: Vec::new(),
32 confidence: 0.0,
33 source: ContextSource::NativeApi,
34 content_role: ContentRole::Interactive,
35 properties: Default::default(),
36 }],
37 ));
38
39 let ctx = merger.build();
40 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
41
42 let reference = ctx.elements[0].to_reference(1920, 1080);
43 let resolved = cel_context::resolve_reference(&ctx, &reference);
44 println!(
45 "resolved reference: {:?}",
46 resolved.map(|el| el.id.as_str())
47 );
48
49 let mut watchdog = ContextWatchdog::new();
50 assert!(watchdog.tick(&ctx, true).is_empty());
51
52 let mut changed = ctx.clone();
53 changed.elements[0].state.focused = false;
54 let events = watchdog.tick(&changed, true);
55 println!("watchdog events: {events:?}");
56}More examples
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}Sourcepub fn push(&mut self, contribution: ContextContribution)
pub fn push(&mut self, contribution: ContextContribution)
Examples found in repository?
10fn main() {
11 let mut merger = ContextMerger::new().with_defaults("Example App", "Main");
12 merger.push(ContextContribution::new(
13 "test_source",
14 vec![ContextElement {
15 id: "button:submit".into(),
16 label: Some("Submit".into()),
17 description: None,
18 element_type: "button".into(),
19 value: None,
20 bounds: Some(Bounds {
21 x: 100,
22 y: 200,
23 width: 120,
24 height: 32,
25 }),
26 state: ElementState {
27 focused: true,
28 ..Default::default()
29 },
30 parent_id: None,
31 actions: Vec::new(),
32 confidence: 0.0,
33 source: ContextSource::NativeApi,
34 content_role: ContentRole::Interactive,
35 properties: Default::default(),
36 }],
37 ));
38
39 let ctx = merger.build();
40 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
41
42 let reference = ctx.elements[0].to_reference(1920, 1080);
43 let resolved = cel_context::resolve_reference(&ctx, &reference);
44 println!(
45 "resolved reference: {:?}",
46 resolved.map(|el| el.id.as_str())
47 );
48
49 let mut watchdog = ContextWatchdog::new();
50 assert!(watchdog.tick(&ctx, true).is_empty());
51
52 let mut changed = ctx.clone();
53 changed.elements[0].state.focused = false;
54 let events = watchdog.tick(&changed, true);
55 println!("watchdog events: {events:?}");
56}More examples
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}pub fn extend( &mut self, contributions: impl IntoIterator<Item = ContextContribution>, )
pub fn stream_status(&self) -> StreamStatus
Sourcepub fn build(&self) -> ScreenContext
pub fn build(&self) -> ScreenContext
Examples found in repository?
10fn main() {
11 let mut merger = ContextMerger::new().with_defaults("Example App", "Main");
12 merger.push(ContextContribution::new(
13 "test_source",
14 vec![ContextElement {
15 id: "button:submit".into(),
16 label: Some("Submit".into()),
17 description: None,
18 element_type: "button".into(),
19 value: None,
20 bounds: Some(Bounds {
21 x: 100,
22 y: 200,
23 width: 120,
24 height: 32,
25 }),
26 state: ElementState {
27 focused: true,
28 ..Default::default()
29 },
30 parent_id: None,
31 actions: Vec::new(),
32 confidence: 0.0,
33 source: ContextSource::NativeApi,
34 content_role: ContentRole::Interactive,
35 properties: Default::default(),
36 }],
37 ));
38
39 let ctx = merger.build();
40 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
41
42 let reference = ctx.elements[0].to_reference(1920, 1080);
43 let resolved = cel_context::resolve_reference(&ctx, &reference);
44 println!(
45 "resolved reference: {:?}",
46 resolved.map(|el| el.id.as_str())
47 );
48
49 let mut watchdog = ContextWatchdog::new();
50 assert!(watchdog.tick(&ctx, true).is_empty());
51
52 let mut changed = ctx.clone();
53 changed.elements[0].state.focused = false;
54 let events = watchdog.tick(&changed, true);
55 println!("watchdog events: {events:?}");
56}More examples
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}Sourcepub fn get_context(&mut self) -> ScreenContext
pub fn get_context(&mut self) -> ScreenContext
Backwards-compatible alias for callers that think of merging as a read.
pub fn get_context_focused( &mut self, element_id: &str, ) -> Option<FocusedContext>
Trait Implementations§
Source§impl Clone for ContextMerger
impl Clone for ContextMerger
Source§fn clone(&self) -> ContextMerger
fn clone(&self) -> ContextMerger
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more