Skip to main content

ContextMerger

Struct ContextMerger 

Source
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

Source

pub fn new() -> Self

Examples found in repository?
examples/dump_context.rs (line 11)
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
Hide additional examples
examples/context_snapshot.rs (line 17)
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}
Source

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.

Source

pub fn with_display<A, D>(_accessibility: A, _display: D) -> Self

Compatibility constructor for a runtime-provided display source.

Source

pub fn with_signals<S>(self, _signals: S) -> Self

Compatibility hook for a runtime-provided signal source.

Source

pub fn with_vision<V>(self, _vision: V) -> Self

Compatibility hook for a runtime-provided vision source.

Source

pub fn with_runtime<R>(self, _runtime: R) -> Self

Compatibility hook for a runtime-provided async runtime handle.

Source

pub fn with_cdp_screenshot_fallback<F, T>(self, _fallback: F) -> Self
where F: Fn() -> Option<T> + Send + Sync + 'static,

Compatibility hook for a runtime-provided screenshot fallback.

Source

pub fn run_ocr_fallback( &mut self, _existing: &[ContextElement], ) -> Vec<ContextElement>

Compatibility hook retained until the live runtime owns OCR fallback.

Source

pub fn recent_network_events(&self) -> &[ConnectionEvent]

Network events are carried on ContextSnapshot, not owned by the merger.

Source

pub fn with_defaults( self, app: impl Into<String>, window: impl Into<String>, ) -> Self

Examples found in repository?
examples/dump_context.rs (line 11)
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
Hide additional examples
examples/context_snapshot.rs (line 17)
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}
Source

pub fn push(&mut self, contribution: ContextContribution)

Examples found in repository?
examples/dump_context.rs (lines 12-29)
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
Hide additional examples
examples/context_snapshot.rs (lines 18-50)
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}
Source

pub fn extend( &mut self, contributions: impl IntoIterator<Item = ContextContribution>, )

Source

pub fn stream_status(&self) -> StreamStatus

Source

pub fn build(&self) -> ContextSnapshot

Examples found in repository?
examples/dump_context.rs (line 31)
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
Hide additional examples
examples/context_snapshot.rs (line 85)
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}
Source

pub fn get_context(&mut self) -> ContextSnapshot

Backwards-compatible alias for callers that think of merging as a read.

Source

pub fn get_context_focused( &mut self, element_id: &str, ) -> Option<FocusedContext>

Trait Implementations§

Source§

impl Clone for ContextMerger

Source§

fn clone(&self) -> ContextMerger

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ContextMerger

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ContextMerger

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.