soma_provider_core/
call.rs1use std::sync::{Arc, Mutex};
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::ProviderSurface;
7
8#[derive(Debug, Clone, Default, PartialEq, Eq)]
10pub struct ProviderInvocationContext {
11 pub request_id: String,
12 pub actor_id: Option<String>,
13 pub actor_scopes: Vec<String>,
14 pub traceparent: Option<String>,
15 pub tracestate: Option<String>,
16 pub progress: ProviderProgressReporter,
19}
20
21#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
23pub struct ProviderProgressEvent {
24 pub current: u64,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub total: Option<u64>,
27 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub message: Option<String>,
29}
30
31#[derive(Debug, Clone, Default)]
36pub struct ProviderProgressReporter(Arc<Mutex<Vec<ProviderProgressEvent>>>);
37
38impl ProviderProgressReporter {
39 const MAX_EVENTS: usize = 256;
40 const MAX_MESSAGE_CHARS: usize = 1_024;
41
42 pub fn report(&self, current: u64, total: Option<u64>, message: Option<&str>) {
43 let mut events = self
44 .0
45 .lock()
46 .expect("provider progress lock should not be poisoned");
47 if events.len() == Self::MAX_EVENTS {
48 events.remove(0);
49 }
50 events.push(ProviderProgressEvent {
51 current,
52 total,
53 message: message.map(|value| value.chars().take(Self::MAX_MESSAGE_CHARS).collect()),
54 });
55 }
56
57 #[must_use]
58 pub fn events(&self) -> Vec<ProviderProgressEvent> {
59 self.0
60 .lock()
61 .expect("provider progress lock should not be poisoned")
62 .clone()
63 }
64}
65
66impl PartialEq for ProviderProgressReporter {
67 fn eq(&self, other: &Self) -> bool {
68 self.events() == other.events()
69 }
70}
71
72impl Eq for ProviderProgressReporter {}
73
74#[derive(Debug, Clone)]
75pub struct ProviderCall {
76 pub provider: String,
77 pub action: String,
78 pub params: Value,
79 pub surface: ProviderSurface,
80 pub snapshot_id: String,
81 pub context: ProviderInvocationContext,
82}
83
84impl ProviderCall {
85 pub fn new(action: impl Into<String>, arguments: Value) -> Self {
86 Self {
87 provider: String::new(),
88 action: action.into(),
89 params: arguments,
90 surface: ProviderSurface::Internal,
91 snapshot_id: String::new(),
92 context: ProviderInvocationContext::default(),
93 }
94 }
95
96 #[must_use]
97 pub fn with_surface(mut self, surface: ProviderSurface) -> Self {
98 self.surface = surface;
99 self
100 }
101
102 pub fn tool(&self) -> &str {
103 &self.action
104 }
105
106 pub fn arguments(&self) -> &Value {
107 &self.params
108 }
109
110 #[must_use]
111 pub fn with_context(mut self, context: ProviderInvocationContext) -> Self {
112 self.context = context;
113 self
114 }
115}