systemprompt_models/execution/context/
mod.rs1mod call_source;
4mod context_error;
5mod context_types;
6mod propagation;
7
8pub use call_source::CallSource;
9pub use context_error::{ContextExtractionError, ContextIdSource, TASK_BASED_CONTEXT_MARKER};
10pub use context_types::{
11 AuthContext, ExecutionContext, ExecutionSettings, RequestMetadata, UserInteractionMode,
12};
13
14use crate::ai::ToolModelConfig;
15use crate::auth::{AuthenticatedUser, RateLimitTier, UserType};
16use serde::{Deserialize, Serialize};
17use std::time::{Duration, Instant};
18use systemprompt_identifiers::{
19 AgentName, AiToolCallId, ClientId, ContextId, JwtToken, McpExecutionId, SessionId, TaskId,
20 TraceId, UserId,
21};
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct RequestContext {
25 pub auth: AuthContext,
26 pub request: RequestMetadata,
27 pub execution: ExecutionContext,
28 pub settings: ExecutionSettings,
29
30 #[serde(skip)]
31 pub user: Option<AuthenticatedUser>,
32
33 #[serde(skip, default = "Instant::now")]
34 pub start_time: Instant,
35}
36
37impl RequestContext {
38 pub fn new(
76 session_id: SessionId,
77 trace_id: TraceId,
78 context_id: ContextId,
79 agent_name: AgentName,
80 ) -> Self {
81 Self {
82 auth: AuthContext {
83 auth_token: JwtToken::new(""),
84 user_id: UserId::anonymous(),
85 user_type: UserType::Anon,
86 },
87 request: RequestMetadata {
88 session_id,
89 timestamp: Instant::now(),
90 client_id: None,
91 is_tracked: true,
92 fingerprint_hash: None,
93 },
94 execution: ExecutionContext {
95 trace_id,
96 context_id,
97 task_id: None,
98 ai_tool_call_id: None,
99 mcp_execution_id: None,
100 call_source: None,
101 agent_name,
102 tool_model_config: None,
103 },
104 settings: ExecutionSettings::default(),
105 user: None,
106 start_time: Instant::now(),
107 }
108 }
109
110 pub fn with_user(mut self, user: AuthenticatedUser) -> Self {
111 self.auth.user_id = UserId::new(user.id.to_string());
112 self.user = Some(user);
113 self
114 }
115
116 pub fn with_user_id(mut self, user_id: UserId) -> Self {
117 self.auth.user_id = user_id;
118 self
119 }
120
121 pub fn with_agent_name(mut self, agent_name: AgentName) -> Self {
122 self.execution.agent_name = agent_name;
123 self
124 }
125
126 pub fn with_context_id(mut self, context_id: ContextId) -> Self {
127 self.execution.context_id = context_id;
128 self
129 }
130
131 pub fn with_task_id(mut self, task_id: TaskId) -> Self {
132 self.execution.task_id = Some(task_id);
133 self
134 }
135
136 pub fn with_task(mut self, task_id: TaskId, call_source: CallSource) -> Self {
137 self.execution.task_id = Some(task_id);
138 self.execution.call_source = Some(call_source);
139 self
140 }
141
142 pub fn with_ai_tool_call_id(mut self, ai_tool_call_id: AiToolCallId) -> Self {
143 self.execution.ai_tool_call_id = Some(ai_tool_call_id);
144 self
145 }
146
147 pub fn with_mcp_execution_id(mut self, mcp_execution_id: McpExecutionId) -> Self {
148 self.execution.mcp_execution_id = Some(mcp_execution_id);
149 self
150 }
151
152 pub fn with_client_id(mut self, client_id: ClientId) -> Self {
153 self.request.client_id = Some(client_id);
154 self
155 }
156
157 pub const fn with_user_type(mut self, user_type: UserType) -> Self {
158 self.auth.user_type = user_type;
159 self
160 }
161
162 pub fn with_auth_token(mut self, token: impl Into<String>) -> Self {
163 self.auth.auth_token = JwtToken::new(token.into());
164 self
165 }
166
167 pub const fn with_call_source(mut self, call_source: CallSource) -> Self {
168 self.execution.call_source = Some(call_source);
169 self
170 }
171
172 pub const fn with_budget(mut self, cents: i32) -> Self {
173 self.settings.max_budget_cents = Some(cents);
174 self
175 }
176
177 pub const fn with_interaction_mode(mut self, mode: UserInteractionMode) -> Self {
178 self.settings.user_interaction_mode = Some(mode);
179 self
180 }
181
182 pub const fn with_tracked(mut self, is_tracked: bool) -> Self {
183 self.request.is_tracked = is_tracked;
184 self
185 }
186
187 pub fn with_fingerprint_hash(mut self, hash: impl Into<String>) -> Self {
188 self.request.fingerprint_hash = Some(hash.into());
189 self
190 }
191
192 pub fn fingerprint_hash(&self) -> Option<&str> {
193 self.request.fingerprint_hash.as_deref()
194 }
195
196 pub fn with_tool_model_config(mut self, config: ToolModelConfig) -> Self {
197 self.execution.tool_model_config = Some(config);
198 self
199 }
200
201 pub const fn tool_model_config(&self) -> Option<&ToolModelConfig> {
202 self.execution.tool_model_config.as_ref()
203 }
204
205 pub const fn session_id(&self) -> &SessionId {
206 &self.request.session_id
207 }
208
209 pub const fn user_id(&self) -> &UserId {
210 &self.auth.user_id
211 }
212
213 pub const fn trace_id(&self) -> &TraceId {
214 &self.execution.trace_id
215 }
216
217 pub const fn context_id(&self) -> &ContextId {
218 &self.execution.context_id
219 }
220
221 pub const fn agent_name(&self) -> &AgentName {
222 &self.execution.agent_name
223 }
224
225 pub const fn auth_token(&self) -> &JwtToken {
226 &self.auth.auth_token
227 }
228
229 pub const fn user_type(&self) -> UserType {
230 self.auth.user_type
231 }
232
233 pub const fn rate_limit_tier(&self) -> RateLimitTier {
234 self.auth.user_type.rate_tier()
235 }
236
237 pub const fn task_id(&self) -> Option<&TaskId> {
238 self.execution.task_id.as_ref()
239 }
240
241 pub const fn client_id(&self) -> Option<&ClientId> {
242 self.request.client_id.as_ref()
243 }
244
245 pub const fn ai_tool_call_id(&self) -> Option<&AiToolCallId> {
246 self.execution.ai_tool_call_id.as_ref()
247 }
248
249 pub const fn mcp_execution_id(&self) -> Option<&McpExecutionId> {
250 self.execution.mcp_execution_id.as_ref()
251 }
252
253 pub const fn call_source(&self) -> Option<CallSource> {
254 self.execution.call_source
255 }
256
257 pub const fn is_authenticated(&self) -> bool {
258 self.user.is_some()
259 }
260
261 pub fn is_system(&self) -> bool {
262 self.auth.user_id.is_system() && self.execution.context_id.is_system()
263 }
264
265 pub fn elapsed(&self) -> Duration {
266 self.start_time.elapsed()
267 }
268
269 pub fn validate_task_execution(&self) -> Result<(), String> {
270 if self.execution.task_id.is_none() {
271 return Err("Missing task_id for task execution".to_string());
272 }
273 if self.execution.context_id.as_str().is_empty() {
274 return Err("Missing context_id for task execution".to_string());
275 }
276 Ok(())
277 }
278
279 pub fn validate_authenticated(&self) -> Result<(), String> {
280 if self.auth.auth_token.as_str().is_empty() {
281 return Err("Missing authentication token".to_string());
282 }
283 if self.auth.user_id.is_anonymous() {
284 return Err("User is not authenticated".to_string());
285 }
286 Ok(())
287 }
288}