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, logs, traces, metrics, tickets, or other streams. Those
sources should emit ContextElements / ContextSnapshots 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("Incident Review", "Payment API");
12 merger.push(ContextContribution::new(
13 "trace_stream",
14 vec![ContextElement {
15 id: "trace:payment-api:slow-span".into(),
16 label: Some("payment-api span exceeded latency budget".into()),
17 description: None,
18 element_type: "trace_span".into(),
19 value: Some("duration_ms=1840".into()),
20 bounds: None,
21 state: ElementState::default(),
22 parent_id: None,
23 actions: Vec::new(),
24 confidence: 0.0,
25 source: ContextSource::External,
26 content_role: ContentRole::Content,
27 properties: Default::default(),
28 }],
29 ));
30
31 let ctx = merger.build();
32 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
33
34 let mut watchdog = ContextWatchdog::new();
35 assert!(watchdog.tick(&ctx, true).is_empty());
36
37 let mut changed = ctx.clone();
38 changed.elements.push(ContextElement {
39 id: "log:payment-api:retry".into(),
40 label: Some("payment-api retried card processor request".into()),
41 description: None,
42 element_type: "log_event".into(),
43 value: Some("attempt=2".into()),
44 bounds: None,
45 state: ElementState::default(),
46 parent_id: None,
47 actions: Vec::new(),
48 confidence: 0.0,
49 source: ContextSource::External,
50 content_role: ContentRole::Content,
51 properties: Default::default(),
52 });
53 let events = watchdog.tick(&changed, true);
54 println!("watchdog events: {events:?}");
55}More examples
14fn main() {
15 let json_output = std::env::args().any(|arg| arg == "--json");
16
17 let mut merger = ContextMerger::new().with_defaults("Incident Review", "Checkout Flow");
18 merger.push(
19 ContextContribution::new(
20 "metrics_stream",
21 vec![
22 element(
23 "metric:checkout:error_rate",
24 "metric",
25 "Checkout error rate is above threshold",
26 Some("7.2%"),
27 ContextSource::External,
28 ContentRole::Content,
29 ),
30 element(
31 "metric:checkout:p95_latency",
32 "metric",
33 "Checkout p95 latency is elevated",
34 Some("1840ms"),
35 ContextSource::External,
36 ContentRole::Content,
37 ),
38 ],
39 )
40 .with_app("Incident Review")
41 .with_window("Checkout Flow")
42 .with_stream_status(StreamStatus {
43 accessibility: false,
44 display: false,
45 network: true,
46 signals: true,
47 vision: false,
48 audio_capture: false,
49 }),
50 );
51 merger.push(ContextContribution::new(
52 "support_tickets",
53 vec![element(
54 "ticket:1842",
55 "ticket",
56 "Users report payment confirmation page timing out",
57 Some("priority=high"),
58 ContextSource::External,
59 ContentRole::Content,
60 )],
61 ));
62 merger.push(ContextContribution::new(
63 "browser_dom",
64 vec![element(
65 "dom:button:retry-payment",
66 "button",
67 "Retry payment",
68 None,
69 ContextSource::Cdp,
70 ContentRole::Interactive,
71 )],
72 ));
73 merger.push(ContextContribution::new(
74 "service_logs",
75 vec![element(
76 "log:payment-service:timeout",
77 "log_event",
78 "payment-service timed out calling card processor",
79 Some("Timeout after 3000ms"),
80 ContextSource::External,
81 ContentRole::Content,
82 )],
83 ));
84
85 let ctx = merger.build();
86
87 if json_output {
88 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
89 return;
90 }
91
92 println!("=== Agent Context Snapshot ===");
93 println!("App: {}", ctx.app);
94 println!("Window: {}", ctx.window);
95 println!("Timestamp: {} ms", ctx.timestamp_ms);
96 println!("Elements: {}", ctx.elements.len());
97 println!();
98
99 for (i, elem) in ctx.elements.iter().enumerate() {
100 let label = elem.label.as_deref().unwrap_or("(no label)");
101 let value = elem.value.as_deref().unwrap_or("");
102 println!(
103 " {:>2}. [{:.2}] {:12} {:48} {:18} {:?}",
104 i + 1,
105 elem.confidence,
106 elem.element_type,
107 label,
108 value,
109 elem.source
110 );
111 }
112}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 carried on ContextSnapshot, 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("Incident Review", "Payment API");
12 merger.push(ContextContribution::new(
13 "trace_stream",
14 vec![ContextElement {
15 id: "trace:payment-api:slow-span".into(),
16 label: Some("payment-api span exceeded latency budget".into()),
17 description: None,
18 element_type: "trace_span".into(),
19 value: Some("duration_ms=1840".into()),
20 bounds: None,
21 state: ElementState::default(),
22 parent_id: None,
23 actions: Vec::new(),
24 confidence: 0.0,
25 source: ContextSource::External,
26 content_role: ContentRole::Content,
27 properties: Default::default(),
28 }],
29 ));
30
31 let ctx = merger.build();
32 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
33
34 let mut watchdog = ContextWatchdog::new();
35 assert!(watchdog.tick(&ctx, true).is_empty());
36
37 let mut changed = ctx.clone();
38 changed.elements.push(ContextElement {
39 id: "log:payment-api:retry".into(),
40 label: Some("payment-api retried card processor request".into()),
41 description: None,
42 element_type: "log_event".into(),
43 value: Some("attempt=2".into()),
44 bounds: None,
45 state: ElementState::default(),
46 parent_id: None,
47 actions: Vec::new(),
48 confidence: 0.0,
49 source: ContextSource::External,
50 content_role: ContentRole::Content,
51 properties: Default::default(),
52 });
53 let events = watchdog.tick(&changed, true);
54 println!("watchdog events: {events:?}");
55}More examples
14fn main() {
15 let json_output = std::env::args().any(|arg| arg == "--json");
16
17 let mut merger = ContextMerger::new().with_defaults("Incident Review", "Checkout Flow");
18 merger.push(
19 ContextContribution::new(
20 "metrics_stream",
21 vec![
22 element(
23 "metric:checkout:error_rate",
24 "metric",
25 "Checkout error rate is above threshold",
26 Some("7.2%"),
27 ContextSource::External,
28 ContentRole::Content,
29 ),
30 element(
31 "metric:checkout:p95_latency",
32 "metric",
33 "Checkout p95 latency is elevated",
34 Some("1840ms"),
35 ContextSource::External,
36 ContentRole::Content,
37 ),
38 ],
39 )
40 .with_app("Incident Review")
41 .with_window("Checkout Flow")
42 .with_stream_status(StreamStatus {
43 accessibility: false,
44 display: false,
45 network: true,
46 signals: true,
47 vision: false,
48 audio_capture: false,
49 }),
50 );
51 merger.push(ContextContribution::new(
52 "support_tickets",
53 vec![element(
54 "ticket:1842",
55 "ticket",
56 "Users report payment confirmation page timing out",
57 Some("priority=high"),
58 ContextSource::External,
59 ContentRole::Content,
60 )],
61 ));
62 merger.push(ContextContribution::new(
63 "browser_dom",
64 vec![element(
65 "dom:button:retry-payment",
66 "button",
67 "Retry payment",
68 None,
69 ContextSource::Cdp,
70 ContentRole::Interactive,
71 )],
72 ));
73 merger.push(ContextContribution::new(
74 "service_logs",
75 vec![element(
76 "log:payment-service:timeout",
77 "log_event",
78 "payment-service timed out calling card processor",
79 Some("Timeout after 3000ms"),
80 ContextSource::External,
81 ContentRole::Content,
82 )],
83 ));
84
85 let ctx = merger.build();
86
87 if json_output {
88 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
89 return;
90 }
91
92 println!("=== Agent Context Snapshot ===");
93 println!("App: {}", ctx.app);
94 println!("Window: {}", ctx.window);
95 println!("Timestamp: {} ms", ctx.timestamp_ms);
96 println!("Elements: {}", ctx.elements.len());
97 println!();
98
99 for (i, elem) in ctx.elements.iter().enumerate() {
100 let label = elem.label.as_deref().unwrap_or("(no label)");
101 let value = elem.value.as_deref().unwrap_or("");
102 println!(
103 " {:>2}. [{:.2}] {:12} {:48} {:18} {:?}",
104 i + 1,
105 elem.confidence,
106 elem.element_type,
107 label,
108 value,
109 elem.source
110 );
111 }
112}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("Incident Review", "Payment API");
12 merger.push(ContextContribution::new(
13 "trace_stream",
14 vec![ContextElement {
15 id: "trace:payment-api:slow-span".into(),
16 label: Some("payment-api span exceeded latency budget".into()),
17 description: None,
18 element_type: "trace_span".into(),
19 value: Some("duration_ms=1840".into()),
20 bounds: None,
21 state: ElementState::default(),
22 parent_id: None,
23 actions: Vec::new(),
24 confidence: 0.0,
25 source: ContextSource::External,
26 content_role: ContentRole::Content,
27 properties: Default::default(),
28 }],
29 ));
30
31 let ctx = merger.build();
32 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
33
34 let mut watchdog = ContextWatchdog::new();
35 assert!(watchdog.tick(&ctx, true).is_empty());
36
37 let mut changed = ctx.clone();
38 changed.elements.push(ContextElement {
39 id: "log:payment-api:retry".into(),
40 label: Some("payment-api retried card processor request".into()),
41 description: None,
42 element_type: "log_event".into(),
43 value: Some("attempt=2".into()),
44 bounds: None,
45 state: ElementState::default(),
46 parent_id: None,
47 actions: Vec::new(),
48 confidence: 0.0,
49 source: ContextSource::External,
50 content_role: ContentRole::Content,
51 properties: Default::default(),
52 });
53 let events = watchdog.tick(&changed, true);
54 println!("watchdog events: {events:?}");
55}More examples
14fn main() {
15 let json_output = std::env::args().any(|arg| arg == "--json");
16
17 let mut merger = ContextMerger::new().with_defaults("Incident Review", "Checkout Flow");
18 merger.push(
19 ContextContribution::new(
20 "metrics_stream",
21 vec![
22 element(
23 "metric:checkout:error_rate",
24 "metric",
25 "Checkout error rate is above threshold",
26 Some("7.2%"),
27 ContextSource::External,
28 ContentRole::Content,
29 ),
30 element(
31 "metric:checkout:p95_latency",
32 "metric",
33 "Checkout p95 latency is elevated",
34 Some("1840ms"),
35 ContextSource::External,
36 ContentRole::Content,
37 ),
38 ],
39 )
40 .with_app("Incident Review")
41 .with_window("Checkout Flow")
42 .with_stream_status(StreamStatus {
43 accessibility: false,
44 display: false,
45 network: true,
46 signals: true,
47 vision: false,
48 audio_capture: false,
49 }),
50 );
51 merger.push(ContextContribution::new(
52 "support_tickets",
53 vec![element(
54 "ticket:1842",
55 "ticket",
56 "Users report payment confirmation page timing out",
57 Some("priority=high"),
58 ContextSource::External,
59 ContentRole::Content,
60 )],
61 ));
62 merger.push(ContextContribution::new(
63 "browser_dom",
64 vec![element(
65 "dom:button:retry-payment",
66 "button",
67 "Retry payment",
68 None,
69 ContextSource::Cdp,
70 ContentRole::Interactive,
71 )],
72 ));
73 merger.push(ContextContribution::new(
74 "service_logs",
75 vec![element(
76 "log:payment-service:timeout",
77 "log_event",
78 "payment-service timed out calling card processor",
79 Some("Timeout after 3000ms"),
80 ContextSource::External,
81 ContentRole::Content,
82 )],
83 ));
84
85 let ctx = merger.build();
86
87 if json_output {
88 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
89 return;
90 }
91
92 println!("=== Agent Context Snapshot ===");
93 println!("App: {}", ctx.app);
94 println!("Window: {}", ctx.window);
95 println!("Timestamp: {} ms", ctx.timestamp_ms);
96 println!("Elements: {}", ctx.elements.len());
97 println!();
98
99 for (i, elem) in ctx.elements.iter().enumerate() {
100 let label = elem.label.as_deref().unwrap_or("(no label)");
101 let value = elem.value.as_deref().unwrap_or("");
102 println!(
103 " {:>2}. [{:.2}] {:12} {:48} {:18} {:?}",
104 i + 1,
105 elem.confidence,
106 elem.element_type,
107 label,
108 value,
109 elem.source
110 );
111 }
112}pub fn extend( &mut self, contributions: impl IntoIterator<Item = ContextContribution>, )
pub fn stream_status(&self) -> StreamStatus
Sourcepub fn build(&self) -> ContextSnapshot
pub fn build(&self) -> ContextSnapshot
Examples found in repository?
10fn main() {
11 let mut merger = ContextMerger::new().with_defaults("Incident Review", "Payment API");
12 merger.push(ContextContribution::new(
13 "trace_stream",
14 vec![ContextElement {
15 id: "trace:payment-api:slow-span".into(),
16 label: Some("payment-api span exceeded latency budget".into()),
17 description: None,
18 element_type: "trace_span".into(),
19 value: Some("duration_ms=1840".into()),
20 bounds: None,
21 state: ElementState::default(),
22 parent_id: None,
23 actions: Vec::new(),
24 confidence: 0.0,
25 source: ContextSource::External,
26 content_role: ContentRole::Content,
27 properties: Default::default(),
28 }],
29 ));
30
31 let ctx = merger.build();
32 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
33
34 let mut watchdog = ContextWatchdog::new();
35 assert!(watchdog.tick(&ctx, true).is_empty());
36
37 let mut changed = ctx.clone();
38 changed.elements.push(ContextElement {
39 id: "log:payment-api:retry".into(),
40 label: Some("payment-api retried card processor request".into()),
41 description: None,
42 element_type: "log_event".into(),
43 value: Some("attempt=2".into()),
44 bounds: None,
45 state: ElementState::default(),
46 parent_id: None,
47 actions: Vec::new(),
48 confidence: 0.0,
49 source: ContextSource::External,
50 content_role: ContentRole::Content,
51 properties: Default::default(),
52 });
53 let events = watchdog.tick(&changed, true);
54 println!("watchdog events: {events:?}");
55}More examples
14fn main() {
15 let json_output = std::env::args().any(|arg| arg == "--json");
16
17 let mut merger = ContextMerger::new().with_defaults("Incident Review", "Checkout Flow");
18 merger.push(
19 ContextContribution::new(
20 "metrics_stream",
21 vec![
22 element(
23 "metric:checkout:error_rate",
24 "metric",
25 "Checkout error rate is above threshold",
26 Some("7.2%"),
27 ContextSource::External,
28 ContentRole::Content,
29 ),
30 element(
31 "metric:checkout:p95_latency",
32 "metric",
33 "Checkout p95 latency is elevated",
34 Some("1840ms"),
35 ContextSource::External,
36 ContentRole::Content,
37 ),
38 ],
39 )
40 .with_app("Incident Review")
41 .with_window("Checkout Flow")
42 .with_stream_status(StreamStatus {
43 accessibility: false,
44 display: false,
45 network: true,
46 signals: true,
47 vision: false,
48 audio_capture: false,
49 }),
50 );
51 merger.push(ContextContribution::new(
52 "support_tickets",
53 vec![element(
54 "ticket:1842",
55 "ticket",
56 "Users report payment confirmation page timing out",
57 Some("priority=high"),
58 ContextSource::External,
59 ContentRole::Content,
60 )],
61 ));
62 merger.push(ContextContribution::new(
63 "browser_dom",
64 vec![element(
65 "dom:button:retry-payment",
66 "button",
67 "Retry payment",
68 None,
69 ContextSource::Cdp,
70 ContentRole::Interactive,
71 )],
72 ));
73 merger.push(ContextContribution::new(
74 "service_logs",
75 vec![element(
76 "log:payment-service:timeout",
77 "log_event",
78 "payment-service timed out calling card processor",
79 Some("Timeout after 3000ms"),
80 ContextSource::External,
81 ContentRole::Content,
82 )],
83 ));
84
85 let ctx = merger.build();
86
87 if json_output {
88 println!("{}", serde_json::to_string_pretty(&ctx).unwrap());
89 return;
90 }
91
92 println!("=== Agent Context Snapshot ===");
93 println!("App: {}", ctx.app);
94 println!("Window: {}", ctx.window);
95 println!("Timestamp: {} ms", ctx.timestamp_ms);
96 println!("Elements: {}", ctx.elements.len());
97 println!();
98
99 for (i, elem) in ctx.elements.iter().enumerate() {
100 let label = elem.label.as_deref().unwrap_or("(no label)");
101 let value = elem.value.as_deref().unwrap_or("");
102 println!(
103 " {:>2}. [{:.2}] {:12} {:48} {:18} {:?}",
104 i + 1,
105 elem.confidence,
106 elem.element_type,
107 label,
108 value,
109 elem.source
110 );
111 }
112}Sourcepub fn get_context(&mut self) -> ContextSnapshot
pub fn get_context(&mut self) -> ContextSnapshot
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