adk_core/callbacks.rs
1use crate::{CallbackContext, Content, LlmRequest, LlmResponse, ReadonlyContext, Result, Tool};
2use std::future::Future;
3use std::pin::Pin;
4use std::sync::Arc;
5
6// Agent callbacks
7pub type BeforeAgentCallback = Box<
8 dyn Fn(
9 Arc<dyn CallbackContext>,
10 ) -> Pin<Box<dyn Future<Output = Result<Option<Content>>> + Send>>
11 + Send
12 + Sync,
13>;
14pub type AfterAgentCallback = Box<
15 dyn Fn(
16 Arc<dyn CallbackContext>,
17 ) -> Pin<Box<dyn Future<Output = Result<Option<Content>>> + Send>>
18 + Send
19 + Sync,
20>;
21
22/// Result from a BeforeModel callback
23#[derive(Debug)]
24pub enum BeforeModelResult {
25 /// Continue with the (possibly modified) request
26 Continue(LlmRequest),
27 /// Skip the model call and use this response instead
28 Skip(LlmResponse),
29}
30
31// Model callbacks
32// BeforeModelCallback can modify the request or skip the model call entirely
33pub type BeforeModelCallback = Box<
34 dyn Fn(
35 Arc<dyn CallbackContext>,
36 LlmRequest,
37 ) -> Pin<Box<dyn Future<Output = Result<BeforeModelResult>> + Send>>
38 + Send
39 + Sync,
40>;
41pub type AfterModelCallback = Box<
42 dyn Fn(
43 Arc<dyn CallbackContext>,
44 LlmResponse,
45 ) -> Pin<Box<dyn Future<Output = Result<Option<LlmResponse>>> + Send>>
46 + Send
47 + Sync,
48>;
49
50// Tool callbacks
51pub type BeforeToolCallback = Box<
52 dyn Fn(
53 Arc<dyn CallbackContext>,
54 ) -> Pin<Box<dyn Future<Output = Result<Option<Content>>> + Send>>
55 + Send
56 + Sync,
57>;
58pub type AfterToolCallback = Box<
59 dyn Fn(
60 Arc<dyn CallbackContext>,
61 ) -> Pin<Box<dyn Future<Output = Result<Option<Content>>> + Send>>
62 + Send
63 + Sync,
64>;
65
66/// Rich after-tool callback that receives the tool, arguments, and response.
67///
68/// Aligned with the Python/Go ADK model where `after_tool_callback` receives
69/// the full tool execution context: the tool itself, the arguments it was
70/// called with, and the response it produced (or error JSON).
71///
72/// This is the V2 callback surface for first-class tool result handling.
73/// Unlike [`AfterToolCallback`] (which only receives `CallbackContext`),
74/// this callback can inspect and modify tool results without relying on
75/// `ToolOutcome` inspection.
76///
77/// Return `Ok(None)` to keep the original response, or `Ok(Some(value))`
78/// to replace the function response sent to the LLM.
79pub type AfterToolCallbackFull = Box<
80 dyn Fn(
81 Arc<dyn CallbackContext>,
82 Arc<dyn Tool>,
83 serde_json::Value, // args
84 serde_json::Value, // tool response (success result or error JSON)
85 ) -> Pin<Box<dyn Future<Output = Result<Option<serde_json::Value>>> + Send>>
86 + Send
87 + Sync,
88>;
89
90// Instruction providers - dynamic instruction generation
91pub type InstructionProvider = Box<
92 dyn Fn(Arc<dyn ReadonlyContext>) -> Pin<Box<dyn Future<Output = Result<String>> + Send>>
93 + Send
94 + Sync,
95>;
96pub type GlobalInstructionProvider = InstructionProvider;
97
98// ===== Error Callbacks =====
99
100/// Callback invoked when a tool execution fails (after retries are exhausted).
101///
102/// This is the canonical, framework-level tool-error callback type shared by
103/// `adk-agent` (builder registration) and `adk-plugin` (plugin hooks).
104///
105/// Returns `Ok(Some(value))` to substitute a fallback result as the function
106/// response to the LLM, or `Ok(None)` to let the next callback (or the
107/// original error) propagate.
108pub type OnToolErrorCallback = Box<
109 dyn Fn(
110 Arc<dyn CallbackContext>,
111 Arc<dyn Tool>,
112 serde_json::Value, // args
113 String, // error message
114 ) -> Pin<Box<dyn Future<Output = Result<Option<serde_json::Value>>> + Send>>
115 + Send
116 + Sync,
117>;
118
119// ===== Context Compaction =====
120
121use crate::Event;
122use async_trait::async_trait;
123
124/// Trait for summarizing events during context compaction.
125///
126/// Implementations receive a window of events and produce a single
127/// compacted event containing a summary. The runner calls this when
128/// the compaction interval is reached.
129#[async_trait]
130pub trait BaseEventsSummarizer: Send + Sync {
131 /// Summarize the given events into a single compacted event.
132 /// Returns `None` if no compaction is needed (e.g., empty input).
133 async fn summarize_events(&self, events: &[Event]) -> Result<Option<Event>>;
134}
135
136/// Configuration for automatic context compaction.
137///
138/// Mirrors ADK Python's `EventsCompactionConfig`:
139/// - `compaction_interval`: Number of invocations before triggering compaction
140/// - `overlap_size`: Events from the previous window to include in the next summary
141/// - `summarizer`: The strategy used to produce summaries
142#[derive(Clone)]
143pub struct EventsCompactionConfig {
144 /// Number of completed invocations that triggers compaction.
145 pub compaction_interval: u32,
146 /// How many events from the previous compacted window to include
147 /// in the next compaction for continuity.
148 pub overlap_size: u32,
149 /// The summarizer implementation (e.g., LLM-based).
150 pub summarizer: Arc<dyn BaseEventsSummarizer>,
151}