1use std::collections::HashMap;
4use std::sync::Arc;
5
6use indexmap::IndexMap;
7use parking_lot::Mutex;
8use serde_json::Value;
9use uuid::Uuid;
10
11use crate::genai_types::Content;
12
13use crate::core::cancel::CancellationToken;
14use crate::core::run_config::RunConfig;
15use crate::core::services::{ArtifactService, CredentialService, MemoryService, SessionService};
16use crate::core::session::Session;
17use crate::core::state::StateDelta;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22pub enum InvocationOrigin {
23 #[default]
25 Api,
26 Cli,
28 Web,
30}
31
32#[derive(Clone)]
34pub struct InvocationContext {
35 pub app_name: String,
37 pub user_id: String,
39 pub invocation_id: String,
41 pub session: Arc<Mutex<Session>>,
44 pub session_service: Arc<dyn SessionService>,
46 pub artifact_service: Option<Arc<dyn ArtifactService>>,
48 pub memory_service: Option<Arc<dyn MemoryService>>,
50 pub credential_service: Option<Arc<dyn CredentialService>>,
52 pub run_config: RunConfig,
54 pub origin: InvocationOrigin,
56 pub user_content: Option<Content>,
58 pub llm_call_count: Arc<Mutex<u32>>,
60 pub cancellation: CancellationToken,
66 pub attributes: Arc<Mutex<HashMap<String, Value>>>,
68 pub root_agent: Option<Arc<dyn crate::agents::BaseAgent>>,
72}
73
74impl std::fmt::Debug for InvocationContext {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 f.debug_struct("InvocationContext")
77 .field("app_name", &self.app_name)
78 .field("user_id", &self.user_id)
79 .field("invocation_id", &self.invocation_id)
80 .field("origin", &self.origin)
81 .finish()
82 }
83}
84
85impl InvocationContext {
86 #[must_use]
88 pub fn new_id() -> String {
89 format!("inv-{}", Uuid::new_v4())
90 }
91
92 pub fn check_and_inc_llm_call(&self) -> crate::error::Result<()> {
95 let mut n = self.llm_call_count.lock();
96 if let Some(cap) = self.run_config.max_llm_calls {
97 if *n >= cap {
98 return Err(crate::error::Error::config(format!(
99 "max_llm_calls={cap} reached"
100 )));
101 }
102 }
103 *n += 1;
104 Ok(())
105 }
106
107 #[must_use]
111 pub fn is_cancelled(&self) -> bool {
112 self.cancellation.is_cancelled()
113 }
114}
115
116pub struct ToolContext {
118 pub invocation: Arc<InvocationContext>,
120 pub function_call_id: Option<String>,
122 pub state_delta: StateDelta,
124 pub artifact_delta: IndexMap<String, u64>,
126 pub skip_summarization: bool,
128 pub transfer_to_agent: Option<String>,
130 pub escalate: bool,
132 pub long_running: bool,
134 pub auth_credential: Option<crate::auth::AuthCredential>,
138 pub tool_confirmation: Option<crate::core::tool_confirmation::ToolConfirmation>,
142}
143
144impl ToolContext {
145 pub fn new(invocation: Arc<InvocationContext>) -> Self {
147 Self {
148 invocation,
149 function_call_id: None,
150 state_delta: StateDelta::new(),
151 artifact_delta: IndexMap::new(),
152 skip_summarization: false,
153 transfer_to_agent: None,
154 escalate: false,
155 long_running: false,
156 auth_credential: None,
157 tool_confirmation: None,
158 }
159 }
160
161 #[must_use]
163 pub fn with_function_call_id(mut self, id: impl Into<String>) -> Self {
164 self.function_call_id = Some(id.into());
165 self
166 }
167
168 pub async fn save_artifact(
171 &mut self,
172 filename: &str,
173 part: crate::genai_types::Part,
174 ) -> crate::error::Result<u64> {
175 let svc = self
176 .invocation
177 .artifact_service
178 .as_ref()
179 .ok_or_else(|| crate::error::Error::config("no artifact service configured"))?;
180 let key = crate::core::artifact::ArtifactKey::new(
181 &self.invocation.app_name,
182 &self.invocation.user_id,
183 &self.invocation.session.lock().id,
184 filename,
185 );
186 let v = svc.save_artifact(key, part).await?;
187 self.artifact_delta.insert(filename.to_string(), v);
188 Ok(v)
189 }
190
191 pub async fn load_artifact(
193 &self,
194 filename: &str,
195 version: Option<u64>,
196 ) -> crate::error::Result<Option<crate::genai_types::Part>> {
197 let svc = self
198 .invocation
199 .artifact_service
200 .as_ref()
201 .ok_or_else(|| crate::error::Error::config("no artifact service configured"))?;
202 let key = crate::core::artifact::ArtifactKey::new(
203 &self.invocation.app_name,
204 &self.invocation.user_id,
205 &self.invocation.session.lock().id,
206 filename,
207 );
208 svc.load_artifact(key, version).await
209 }
210}