Skip to main content

ContextApi

Struct ContextApi 

Source
pub struct ContextApi { /* private fields */ }

Implementations§

Source§

impl ContextApi

Source

pub fn new() -> Result<Self, Error>

Examples found in repository?
examples/runtime_capabilities.rs (line 4)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    let api = ContextApi::new()?;
5
6    println!(
7        "device={} platform={:?}",
8        api.device_context().device_id,
9        api.device_context().platform
10    );
11
12    for signal_type in [
13        SignalType::Clipboard,
14        SignalType::Selection,
15        SignalType::Focus,
16    ] {
17        println!("{signal_type:?}: {:?}", api.signal_support(signal_type));
18    }
19
20    println!("supported={:?}", api.supported_signals());
21    Ok(())
22}
More examples
Hide additional examples
examples/context_live_view.rs (line 12)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    let mut api = ContextApi::new()?;
13    let events = Arc::new(Mutex::new(VecDeque::<String>::new()));
14
15    for signal_type in [
16        SignalType::Clipboard,
17        SignalType::Selection,
18        SignalType::Focus,
19    ] {
20        if !matches!(api.signal_support(signal_type), SignalSupport::Supported) {
21            continue;
22        }
23
24        let events = Arc::clone(&events);
25        api.subscribe_enveloped(signal_type, move |envelope| {
26            let line = summarize_envelope(&envelope);
27            let mut queue = events.lock().expect("event queue mutex poisoned");
28            queue.push_front(line);
29            while queue.len() > MAX_EVENTS {
30                let _ = queue.pop_back();
31            }
32        })?;
33    }
34
35    loop {
36        draw_dashboard(&api, &events)?;
37        thread::sleep(Duration::from_millis(350));
38    }
39}
examples/clipboard_monitor.rs (line 6)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let mut api = ContextApi::new()?;
7
8    api.subscribe(SignalType::Clipboard, |signal| {
9        println!(
10            "clipboard changed: type={:?}, bytes={}, source={}, sensitive={}, command={}",
11            signal.content_type,
12            signal.size_bytes,
13            signal.source_app,
14            signal.likely_sensitive,
15            signal.likely_command
16        );
17    })?;
18
19    api.request_permission(
20        PermissionRequest::new(
21            Capability::ReadClipboardContent,
22            Scope::Session,
23            "Show how explicit content access works in the example",
24        )
25        .with_ttl(Duration::from_secs(300)),
26    )?;
27
28    if let Ok(content) = api.read_clipboard_content() {
29        println!("initial clipboard preview: {}", content.redacted_preview());
30    }
31
32    println!("Monitoring clipboard changes. Press Ctrl+C to exit.");
33    api.run_with_signals()?;
34    Ok(())
35}
examples/assistant_context_adapter.rs (line 23)
22fn main() -> Result<(), Box<dyn std::error::Error>> {
23    let mut api = ContextApi::new()?;
24    let state = Arc::new(Mutex::new(AdapterState::default()));
25
26    println!("LCSA Assistant Adapter Demo");
27    println!("Type a developer task and press Enter.");
28    println!("Commands: :help :context :grant-content :revoke-content :quit");
29    println!();
30
31    attach_signal_subscriptions(&mut api, Arc::clone(&state))?;
32
33    let stdin = io::stdin();
34    loop {
35        print!("ask> ");
36        io::stdout().flush()?;
37
38        let mut input = String::new();
39        stdin.read_line(&mut input)?;
40        let input = input.trim();
41        if input.is_empty() {
42            continue;
43        }
44
45        match input {
46            ":help" => print_help(),
47            ":context" => print_context_snapshot(&api, &state),
48            ":grant-content" => grant_clipboard_content(&mut api)?,
49            ":revoke-content" => {
50                let revoked = api.revoke_permission(Capability::ReadClipboardContent);
51                println!("clipboard content access revoked={revoked}");
52            }
53            ":quit" | ":exit" => break,
54            task => print_augmented_packet(&api, &state, task),
55        }
56    }
57
58    Ok(())
59}
Source

pub fn builder() -> ContextApiBuilder

Examples found in repository?
examples/enveloped_clipboard_monitor.rs (line 9)
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9    let mut api = ContextApi::builder()
10        .device_context(DeviceContext {
11            device_id: "desktop:devbox".to_string(),
12            device_name: "devbox".to_string(),
13            platform: Platform::Linux,
14            device_class: DeviceClass::Desktop,
15            os_version: None,
16        })
17        .application_context(ApplicationContext {
18            app_id: "lcsa-demo".to_string(),
19            app_name: "lcsa-demo".to_string(),
20            app_version: Some("0.1.0".to_string()),
21        })
22        .build()?;
23
24    api.request_permission(
25        PermissionRequest::new(
26            Capability::ReadClipboardContent,
27            Scope::Session,
28            "Demonstrate cross-device envelopes plus gated content access",
29        )
30        .with_ttl(Duration::from_secs(300)),
31    )?;
32
33    api.subscribe_enveloped(SignalType::Clipboard, |envelope| {
34        println!(
35            "envelope={} device={} app={} source={:?}",
36            envelope.signal_id,
37            envelope.device.device_id,
38            envelope.application.app_id,
39            envelope.source
40        );
41    })?;
42
43    println!("Monitoring enveloped clipboard signals. Press Ctrl+C to exit.");
44    api.run_with_signals()?;
45    Ok(())
46}
Source

pub fn device_context(&self) -> &DeviceContext

Examples found in repository?
examples/runtime_capabilities.rs (line 8)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    let api = ContextApi::new()?;
5
6    println!(
7        "device={} platform={:?}",
8        api.device_context().device_id,
9        api.device_context().platform
10    );
11
12    for signal_type in [
13        SignalType::Clipboard,
14        SignalType::Selection,
15        SignalType::Focus,
16    ] {
17        println!("{signal_type:?}: {:?}", api.signal_support(signal_type));
18    }
19
20    println!("supported={:?}", api.supported_signals());
21    Ok(())
22}
More examples
Hide additional examples
examples/context_live_view.rs (line 49)
41fn draw_dashboard(
42    api: &ContextApi,
43    events: &Arc<Mutex<VecDeque<String>>>,
44) -> Result<(), Box<dyn std::error::Error>> {
45    print!("\x1B[2J\x1B[H");
46    println!("LCSA Live View");
47    println!(
48        "device={} platform={:?}",
49        api.device_context().device_name,
50        api.device_context().platform
51    );
52    println!();
53    println!("Signal Capabilities");
54    for signal_type in [
55        SignalType::Clipboard,
56        SignalType::Selection,
57        SignalType::Focus,
58    ] {
59        println!(
60            "  {:<10} {:?}",
61            format!("{signal_type:?}"),
62            api.signal_support(signal_type)
63        );
64    }
65    println!();
66    println!("Recent Context Events");
67    println!("  (copy text, select text, or switch windows to see updates)");
68
69    let queue = events.lock().expect("event queue mutex poisoned");
70    if queue.is_empty() {
71        println!("  - waiting for signals...");
72    } else {
73        for line in queue.iter() {
74            println!("  - {line}");
75        }
76    }
77
78    io::stdout().flush()?;
79    Ok(())
80}
examples/assistant_context_adapter.rs (line 192)
183fn build_context_packet(
184    api: &ContextApi,
185    snapshot: &AdapterState,
186    task: &str,
187    clipboard_preview: Option<String>,
188) -> serde_json::Value {
189    json!({
190        "task": task,
191        "device": {
192            "id": api.device_context().device_id,
193            "platform": format!("{:?}", api.device_context().platform),
194        },
195        "capabilities": {
196            "clipboard": format!("{:?}", api.signal_support(SignalType::Clipboard)),
197            "selection": format!("{:?}", api.signal_support(SignalType::Selection)),
198            "focus": format!("{:?}", api.signal_support(SignalType::Focus)),
199            "clipboard_content_access": api.can_access(Capability::ReadClipboardContent),
200        },
201        "context": {
202            "recent_focus": snapshot.recent_focus,
203            "recent_selection": snapshot.recent_selection,
204            "recent_clipboard_signal": snapshot.recent_clipboard,
205            "clipboard_content_preview": clipboard_preview,
206            "recent_events": snapshot.recent_events.iter().take(8).cloned().collect::<Vec<_>>(),
207        },
208        "hints": derive_hints(snapshot),
209    })
210}
Source

pub fn application_context(&self) -> &ApplicationContext

Source

pub fn subscribe_enveloped<F>( &mut self, signal_type: SignalType, handler: F, ) -> Result<SubscriptionHandle, Error>
where F: Fn(SignalEnvelope) + Send + 'static,

Subscribe to signals with envelope wrapping (includes device/app context). The handler is called on the event bus dispatcher thread.

Examples found in repository?
examples/assistant_context_adapter.rs (lines 73-75)
61fn attach_signal_subscriptions(
62    api: &mut ContextApi,
63    state: Arc<Mutex<AdapterState>>,
64) -> Result<(), Box<dyn std::error::Error>> {
65    for signal_type in [
66        SignalType::Clipboard,
67        SignalType::Selection,
68        SignalType::Focus,
69    ] {
70        match api.signal_support(signal_type) {
71            SignalSupport::Supported => {
72                let state = Arc::clone(&state);
73                api.subscribe_enveloped(signal_type, move |envelope| {
74                    ingest_envelope(&state, envelope);
75                })?;
76                println!("{signal_type:?}: subscribed");
77            }
78            unsupported => {
79                println!("{signal_type:?}: {unsupported:?}");
80            }
81        }
82    }
83
84    println!();
85    Ok(())
86}
More examples
Hide additional examples
examples/context_live_view.rs (lines 25-32)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    let mut api = ContextApi::new()?;
13    let events = Arc::new(Mutex::new(VecDeque::<String>::new()));
14
15    for signal_type in [
16        SignalType::Clipboard,
17        SignalType::Selection,
18        SignalType::Focus,
19    ] {
20        if !matches!(api.signal_support(signal_type), SignalSupport::Supported) {
21            continue;
22        }
23
24        let events = Arc::clone(&events);
25        api.subscribe_enveloped(signal_type, move |envelope| {
26            let line = summarize_envelope(&envelope);
27            let mut queue = events.lock().expect("event queue mutex poisoned");
28            queue.push_front(line);
29            while queue.len() > MAX_EVENTS {
30                let _ = queue.pop_back();
31            }
32        })?;
33    }
34
35    loop {
36        draw_dashboard(&api, &events)?;
37        thread::sleep(Duration::from_millis(350));
38    }
39}
examples/enveloped_clipboard_monitor.rs (lines 33-41)
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9    let mut api = ContextApi::builder()
10        .device_context(DeviceContext {
11            device_id: "desktop:devbox".to_string(),
12            device_name: "devbox".to_string(),
13            platform: Platform::Linux,
14            device_class: DeviceClass::Desktop,
15            os_version: None,
16        })
17        .application_context(ApplicationContext {
18            app_id: "lcsa-demo".to_string(),
19            app_name: "lcsa-demo".to_string(),
20            app_version: Some("0.1.0".to_string()),
21        })
22        .build()?;
23
24    api.request_permission(
25        PermissionRequest::new(
26            Capability::ReadClipboardContent,
27            Scope::Session,
28            "Demonstrate cross-device envelopes plus gated content access",
29        )
30        .with_ttl(Duration::from_secs(300)),
31    )?;
32
33    api.subscribe_enveloped(SignalType::Clipboard, |envelope| {
34        println!(
35            "envelope={} device={} app={} source={:?}",
36            envelope.signal_id,
37            envelope.device.device_id,
38            envelope.application.app_id,
39            envelope.source
40        );
41    })?;
42
43    println!("Monitoring enveloped clipboard signals. Press Ctrl+C to exit.");
44    api.run_with_signals()?;
45    Ok(())
46}
Source

pub fn read_clipboard_content(&self) -> Result<ClipboardContent, Error>

Examples found in repository?
examples/assistant_context_adapter.rs (line 162)
160fn print_augmented_packet(api: &ContextApi, state: &Arc<Mutex<AdapterState>>, task: &str) {
161    let snapshot = state.lock().expect("adapter state mutex poisoned").clone();
162    let clipboard_preview = api.read_clipboard_content().ok().map(|content| {
163        // The preview intentionally keeps sensitive content redacted when needed.
164        content.redacted_preview()
165    });
166
167    let packet = build_context_packet(api, &snapshot, task, clipboard_preview.clone());
168    println!();
169    println!("=== Augmented Context Packet ===");
170    println!(
171        "{}",
172        serde_json::to_string_pretty(&packet).unwrap_or_default()
173    );
174    println!();
175    println!("=== Prompt Preview ===");
176    println!(
177        "{}",
178        build_prompt_preview(task, &snapshot, clipboard_preview)
179    );
180    println!();
181}
More examples
Hide additional examples
examples/clipboard_monitor.rs (line 28)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let mut api = ContextApi::new()?;
7
8    api.subscribe(SignalType::Clipboard, |signal| {
9        println!(
10            "clipboard changed: type={:?}, bytes={}, source={}, sensitive={}, command={}",
11            signal.content_type,
12            signal.size_bytes,
13            signal.source_app,
14            signal.likely_sensitive,
15            signal.likely_command
16        );
17    })?;
18
19    api.request_permission(
20        PermissionRequest::new(
21            Capability::ReadClipboardContent,
22            Scope::Session,
23            "Show how explicit content access works in the example",
24        )
25        .with_ttl(Duration::from_secs(300)),
26    )?;
27
28    if let Ok(content) = api.read_clipboard_content() {
29        println!("initial clipboard preview: {}", content.redacted_preview());
30    }
31
32    println!("Monitoring clipboard changes. Press Ctrl+C to exit.");
33    api.run_with_signals()?;
34    Ok(())
35}
Source

pub fn is_signal_supported(&self, signal_type: SignalType) -> bool

Source

pub fn signal_support(&self, signal_type: SignalType) -> SignalSupport

Examples found in repository?
examples/runtime_capabilities.rs (line 17)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    let api = ContextApi::new()?;
5
6    println!(
7        "device={} platform={:?}",
8        api.device_context().device_id,
9        api.device_context().platform
10    );
11
12    for signal_type in [
13        SignalType::Clipboard,
14        SignalType::Selection,
15        SignalType::Focus,
16    ] {
17        println!("{signal_type:?}: {:?}", api.signal_support(signal_type));
18    }
19
20    println!("supported={:?}", api.supported_signals());
21    Ok(())
22}
More examples
Hide additional examples
examples/assistant_context_adapter.rs (line 70)
61fn attach_signal_subscriptions(
62    api: &mut ContextApi,
63    state: Arc<Mutex<AdapterState>>,
64) -> Result<(), Box<dyn std::error::Error>> {
65    for signal_type in [
66        SignalType::Clipboard,
67        SignalType::Selection,
68        SignalType::Focus,
69    ] {
70        match api.signal_support(signal_type) {
71            SignalSupport::Supported => {
72                let state = Arc::clone(&state);
73                api.subscribe_enveloped(signal_type, move |envelope| {
74                    ingest_envelope(&state, envelope);
75                })?;
76                println!("{signal_type:?}: subscribed");
77            }
78            unsupported => {
79                println!("{signal_type:?}: {unsupported:?}");
80            }
81        }
82    }
83
84    println!();
85    Ok(())
86}
87
88fn ingest_envelope(state: &Arc<Mutex<AdapterState>>, envelope: SignalEnvelope) {
89    let mut state = state.lock().expect("adapter state mutex poisoned");
90    let ts = unix_secs(envelope.emitted_at);
91
92    match envelope.payload {
93        StructuralSignal::Clipboard(signal) => {
94            let summary = format!(
95                "clipboard type={:?} bytes={} sensitive={} command={} source={}",
96                signal.content_type,
97                signal.size_bytes,
98                signal.likely_sensitive,
99                signal.likely_command,
100                signal.source_app
101            );
102            state.recent_clipboard = Some(summary.clone());
103            push_event(&mut state.recent_events, format!("{ts} {summary}"));
104        }
105        StructuralSignal::Selection(signal) => {
106            let preview = format!(
107                "selection type={:?} bytes={} editable={} source={}",
108                signal.content_type, signal.size_bytes, signal.is_editable, signal.source_app
109            );
110            state.recent_selection = Some(preview.clone());
111            push_event(&mut state.recent_events, format!("{ts} {preview}"));
112        }
113        StructuralSignal::Focus(signal) => {
114            let summary = format!(
115                "focus target={:?} editable={} source={}",
116                signal.target, signal.is_editable, signal.source_app
117            );
118            state.recent_focus = Some(summary.clone());
119            push_event(&mut state.recent_events, format!("{ts} {summary}"));
120        }
121        StructuralSignal::Filesystem(signal) => {
122            push_event(
123                &mut state.recent_events,
124                format!(
125                    "{ts} filesystem {} {:?}",
126                    signal.event_name(),
127                    signal.action
128                ),
129            );
130        }
131    }
132}
133
134fn print_help() {
135    println!(":context         show current signal snapshot");
136    println!(":grant-content   grant clipboard content access for this session");
137    println!(":revoke-content  revoke clipboard content access");
138    println!(":quit            exit");
139}
140
141fn print_context_snapshot(api: &ContextApi, state: &Arc<Mutex<AdapterState>>) {
142    let snapshot = state.lock().expect("adapter state mutex poisoned").clone();
143    let packet = build_context_packet(api, &snapshot, "(snapshot)", None);
144    println!(
145        "{}",
146        serde_json::to_string_pretty(&packet).unwrap_or_default()
147    );
148}
149
150fn grant_clipboard_content(api: &mut ContextApi) -> Result<(), Box<dyn std::error::Error>> {
151    api.request_permission(PermissionRequest::new(
152        Capability::ReadClipboardContent,
153        Scope::Session,
154        "Enable content-level context in assistant adapter demo",
155    ))?;
156    println!("clipboard content access granted for current session");
157    Ok(())
158}
159
160fn print_augmented_packet(api: &ContextApi, state: &Arc<Mutex<AdapterState>>, task: &str) {
161    let snapshot = state.lock().expect("adapter state mutex poisoned").clone();
162    let clipboard_preview = api.read_clipboard_content().ok().map(|content| {
163        // The preview intentionally keeps sensitive content redacted when needed.
164        content.redacted_preview()
165    });
166
167    let packet = build_context_packet(api, &snapshot, task, clipboard_preview.clone());
168    println!();
169    println!("=== Augmented Context Packet ===");
170    println!(
171        "{}",
172        serde_json::to_string_pretty(&packet).unwrap_or_default()
173    );
174    println!();
175    println!("=== Prompt Preview ===");
176    println!(
177        "{}",
178        build_prompt_preview(task, &snapshot, clipboard_preview)
179    );
180    println!();
181}
182
183fn build_context_packet(
184    api: &ContextApi,
185    snapshot: &AdapterState,
186    task: &str,
187    clipboard_preview: Option<String>,
188) -> serde_json::Value {
189    json!({
190        "task": task,
191        "device": {
192            "id": api.device_context().device_id,
193            "platform": format!("{:?}", api.device_context().platform),
194        },
195        "capabilities": {
196            "clipboard": format!("{:?}", api.signal_support(SignalType::Clipboard)),
197            "selection": format!("{:?}", api.signal_support(SignalType::Selection)),
198            "focus": format!("{:?}", api.signal_support(SignalType::Focus)),
199            "clipboard_content_access": api.can_access(Capability::ReadClipboardContent),
200        },
201        "context": {
202            "recent_focus": snapshot.recent_focus,
203            "recent_selection": snapshot.recent_selection,
204            "recent_clipboard_signal": snapshot.recent_clipboard,
205            "clipboard_content_preview": clipboard_preview,
206            "recent_events": snapshot.recent_events.iter().take(8).cloned().collect::<Vec<_>>(),
207        },
208        "hints": derive_hints(snapshot),
209    })
210}
examples/context_live_view.rs (line 20)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    let mut api = ContextApi::new()?;
13    let events = Arc::new(Mutex::new(VecDeque::<String>::new()));
14
15    for signal_type in [
16        SignalType::Clipboard,
17        SignalType::Selection,
18        SignalType::Focus,
19    ] {
20        if !matches!(api.signal_support(signal_type), SignalSupport::Supported) {
21            continue;
22        }
23
24        let events = Arc::clone(&events);
25        api.subscribe_enveloped(signal_type, move |envelope| {
26            let line = summarize_envelope(&envelope);
27            let mut queue = events.lock().expect("event queue mutex poisoned");
28            queue.push_front(line);
29            while queue.len() > MAX_EVENTS {
30                let _ = queue.pop_back();
31            }
32        })?;
33    }
34
35    loop {
36        draw_dashboard(&api, &events)?;
37        thread::sleep(Duration::from_millis(350));
38    }
39}
40
41fn draw_dashboard(
42    api: &ContextApi,
43    events: &Arc<Mutex<VecDeque<String>>>,
44) -> Result<(), Box<dyn std::error::Error>> {
45    print!("\x1B[2J\x1B[H");
46    println!("LCSA Live View");
47    println!(
48        "device={} platform={:?}",
49        api.device_context().device_name,
50        api.device_context().platform
51    );
52    println!();
53    println!("Signal Capabilities");
54    for signal_type in [
55        SignalType::Clipboard,
56        SignalType::Selection,
57        SignalType::Focus,
58    ] {
59        println!(
60            "  {:<10} {:?}",
61            format!("{signal_type:?}"),
62            api.signal_support(signal_type)
63        );
64    }
65    println!();
66    println!("Recent Context Events");
67    println!("  (copy text, select text, or switch windows to see updates)");
68
69    let queue = events.lock().expect("event queue mutex poisoned");
70    if queue.is_empty() {
71        println!("  - waiting for signals...");
72    } else {
73        for line in queue.iter() {
74            println!("  - {line}");
75        }
76    }
77
78    io::stdout().flush()?;
79    Ok(())
80}
Source

pub fn supported_signals(&self) -> Vec<SignalType>

Examples found in repository?
examples/runtime_capabilities.rs (line 20)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    let api = ContextApi::new()?;
5
6    println!(
7        "device={} platform={:?}",
8        api.device_context().device_id,
9        api.device_context().platform
10    );
11
12    for signal_type in [
13        SignalType::Clipboard,
14        SignalType::Selection,
15        SignalType::Focus,
16    ] {
17        println!("{signal_type:?}: {:?}", api.signal_support(signal_type));
18    }
19
20    println!("supported={:?}", api.supported_signals());
21    Ok(())
22}
Source

pub fn subscribe<F>( &mut self, signal_type: SignalType, handler: F, ) -> Result<SubscriptionHandle, Error>
where F: Fn(ClipboardSignal) + Send + 'static,

Subscribe to clipboard signals only. The handler is called on the event bus dispatcher thread.

Examples found in repository?
examples/clipboard_monitor.rs (lines 8-17)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let mut api = ContextApi::new()?;
7
8    api.subscribe(SignalType::Clipboard, |signal| {
9        println!(
10            "clipboard changed: type={:?}, bytes={}, source={}, sensitive={}, command={}",
11            signal.content_type,
12            signal.size_bytes,
13            signal.source_app,
14            signal.likely_sensitive,
15            signal.likely_command
16        );
17    })?;
18
19    api.request_permission(
20        PermissionRequest::new(
21            Capability::ReadClipboardContent,
22            Scope::Session,
23            "Show how explicit content access works in the example",
24        )
25        .with_ttl(Duration::from_secs(300)),
26    )?;
27
28    if let Ok(content) = api.read_clipboard_content() {
29        println!("initial clipboard preview: {}", content.redacted_preview());
30    }
31
32    println!("Monitoring clipboard changes. Press Ctrl+C to exit.");
33    api.run_with_signals()?;
34    Ok(())
35}
Source

pub fn unsubscribe(&mut self, handle: SubscriptionHandle)

Source

pub fn request_permission( &mut self, request: PermissionRequest, ) -> Result<Grant, Error>

Examples found in repository?
examples/assistant_context_adapter.rs (lines 151-155)
150fn grant_clipboard_content(api: &mut ContextApi) -> Result<(), Box<dyn std::error::Error>> {
151    api.request_permission(PermissionRequest::new(
152        Capability::ReadClipboardContent,
153        Scope::Session,
154        "Enable content-level context in assistant adapter demo",
155    ))?;
156    println!("clipboard content access granted for current session");
157    Ok(())
158}
More examples
Hide additional examples
examples/clipboard_monitor.rs (lines 19-26)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let mut api = ContextApi::new()?;
7
8    api.subscribe(SignalType::Clipboard, |signal| {
9        println!(
10            "clipboard changed: type={:?}, bytes={}, source={}, sensitive={}, command={}",
11            signal.content_type,
12            signal.size_bytes,
13            signal.source_app,
14            signal.likely_sensitive,
15            signal.likely_command
16        );
17    })?;
18
19    api.request_permission(
20        PermissionRequest::new(
21            Capability::ReadClipboardContent,
22            Scope::Session,
23            "Show how explicit content access works in the example",
24        )
25        .with_ttl(Duration::from_secs(300)),
26    )?;
27
28    if let Ok(content) = api.read_clipboard_content() {
29        println!("initial clipboard preview: {}", content.redacted_preview());
30    }
31
32    println!("Monitoring clipboard changes. Press Ctrl+C to exit.");
33    api.run_with_signals()?;
34    Ok(())
35}
examples/enveloped_clipboard_monitor.rs (lines 24-31)
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9    let mut api = ContextApi::builder()
10        .device_context(DeviceContext {
11            device_id: "desktop:devbox".to_string(),
12            device_name: "devbox".to_string(),
13            platform: Platform::Linux,
14            device_class: DeviceClass::Desktop,
15            os_version: None,
16        })
17        .application_context(ApplicationContext {
18            app_id: "lcsa-demo".to_string(),
19            app_name: "lcsa-demo".to_string(),
20            app_version: Some("0.1.0".to_string()),
21        })
22        .build()?;
23
24    api.request_permission(
25        PermissionRequest::new(
26            Capability::ReadClipboardContent,
27            Scope::Session,
28            "Demonstrate cross-device envelopes plus gated content access",
29        )
30        .with_ttl(Duration::from_secs(300)),
31    )?;
32
33    api.subscribe_enveloped(SignalType::Clipboard, |envelope| {
34        println!(
35            "envelope={} device={} app={} source={:?}",
36            envelope.signal_id,
37            envelope.device.device_id,
38            envelope.application.app_id,
39            envelope.source
40        );
41    })?;
42
43    println!("Monitoring enveloped clipboard signals. Press Ctrl+C to exit.");
44    api.run_with_signals()?;
45    Ok(())
46}
Source

pub fn revoke_permission(&mut self, capability: Capability) -> bool

Examples found in repository?
examples/assistant_context_adapter.rs (line 50)
22fn main() -> Result<(), Box<dyn std::error::Error>> {
23    let mut api = ContextApi::new()?;
24    let state = Arc::new(Mutex::new(AdapterState::default()));
25
26    println!("LCSA Assistant Adapter Demo");
27    println!("Type a developer task and press Enter.");
28    println!("Commands: :help :context :grant-content :revoke-content :quit");
29    println!();
30
31    attach_signal_subscriptions(&mut api, Arc::clone(&state))?;
32
33    let stdin = io::stdin();
34    loop {
35        print!("ask> ");
36        io::stdout().flush()?;
37
38        let mut input = String::new();
39        stdin.read_line(&mut input)?;
40        let input = input.trim();
41        if input.is_empty() {
42            continue;
43        }
44
45        match input {
46            ":help" => print_help(),
47            ":context" => print_context_snapshot(&api, &state),
48            ":grant-content" => grant_clipboard_content(&mut api)?,
49            ":revoke-content" => {
50                let revoked = api.revoke_permission(Capability::ReadClipboardContent);
51                println!("clipboard content access revoked={revoked}");
52            }
53            ":quit" | ":exit" => break,
54            task => print_augmented_packet(&api, &state, task),
55        }
56    }
57
58    Ok(())
59}
Source

pub fn can_access(&self, capability: Capability) -> bool

Examples found in repository?
examples/assistant_context_adapter.rs (line 199)
183fn build_context_packet(
184    api: &ContextApi,
185    snapshot: &AdapterState,
186    task: &str,
187    clipboard_preview: Option<String>,
188) -> serde_json::Value {
189    json!({
190        "task": task,
191        "device": {
192            "id": api.device_context().device_id,
193            "platform": format!("{:?}", api.device_context().platform),
194        },
195        "capabilities": {
196            "clipboard": format!("{:?}", api.signal_support(SignalType::Clipboard)),
197            "selection": format!("{:?}", api.signal_support(SignalType::Selection)),
198            "focus": format!("{:?}", api.signal_support(SignalType::Focus)),
199            "clipboard_content_access": api.can_access(Capability::ReadClipboardContent),
200        },
201        "context": {
202            "recent_focus": snapshot.recent_focus,
203            "recent_selection": snapshot.recent_selection,
204            "recent_clipboard_signal": snapshot.recent_clipboard,
205            "clipboard_content_preview": clipboard_preview,
206            "recent_events": snapshot.recent_events.iter().take(8).cloned().collect::<Vec<_>>(),
207        },
208        "hints": derive_hints(snapshot),
209    })
210}
Source

pub fn run(&self)

Run the context API, blocking until shutdown is called.

Source

pub fn shutdown(&self)

Signal shutdown and wait for completion.

Source

pub fn is_shutdown(&self) -> bool

Check if shutdown has been requested.

Source

pub fn run_with_signals(&self) -> Result<(), Error>

Run with Unix signal handling (SIGINT, SIGTERM). This method blocks until a signal is received or shutdown() is called.

Examples found in repository?
examples/clipboard_monitor.rs (line 33)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let mut api = ContextApi::new()?;
7
8    api.subscribe(SignalType::Clipboard, |signal| {
9        println!(
10            "clipboard changed: type={:?}, bytes={}, source={}, sensitive={}, command={}",
11            signal.content_type,
12            signal.size_bytes,
13            signal.source_app,
14            signal.likely_sensitive,
15            signal.likely_command
16        );
17    })?;
18
19    api.request_permission(
20        PermissionRequest::new(
21            Capability::ReadClipboardContent,
22            Scope::Session,
23            "Show how explicit content access works in the example",
24        )
25        .with_ttl(Duration::from_secs(300)),
26    )?;
27
28    if let Ok(content) = api.read_clipboard_content() {
29        println!("initial clipboard preview: {}", content.redacted_preview());
30    }
31
32    println!("Monitoring clipboard changes. Press Ctrl+C to exit.");
33    api.run_with_signals()?;
34    Ok(())
35}
More examples
Hide additional examples
examples/enveloped_clipboard_monitor.rs (line 44)
8fn main() -> Result<(), Box<dyn std::error::Error>> {
9    let mut api = ContextApi::builder()
10        .device_context(DeviceContext {
11            device_id: "desktop:devbox".to_string(),
12            device_name: "devbox".to_string(),
13            platform: Platform::Linux,
14            device_class: DeviceClass::Desktop,
15            os_version: None,
16        })
17        .application_context(ApplicationContext {
18            app_id: "lcsa-demo".to_string(),
19            app_name: "lcsa-demo".to_string(),
20            app_version: Some("0.1.0".to_string()),
21        })
22        .build()?;
23
24    api.request_permission(
25        PermissionRequest::new(
26            Capability::ReadClipboardContent,
27            Scope::Session,
28            "Demonstrate cross-device envelopes plus gated content access",
29        )
30        .with_ttl(Duration::from_secs(300)),
31    )?;
32
33    api.subscribe_enveloped(SignalType::Clipboard, |envelope| {
34        println!(
35            "envelope={} device={} app={} source={:?}",
36            envelope.signal_id,
37            envelope.device.device_id,
38            envelope.application.app_id,
39            envelope.source
40        );
41    })?;
42
43    println!("Monitoring enveloped clipboard signals. Press Ctrl+C to exit.");
44    api.run_with_signals()?;
45    Ok(())
46}

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> 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, 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.