Skip to main content

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}