adk-core 2.0.0

Core traits and types for Rust Agent Development Kit (ADK-Rust) agents, tools, sessions, and events
Documentation

adk-core

Core traits and types for ADK-Rust agents, tools, sessions, and events.

Crates.io Documentation License

Overview

adk-core provides the foundational abstractions for ADK-Rust. It defines the core traits and types that all other ADK crates build upon:

  • Agent trait - The fundamental abstraction for all agents
  • Tool / Toolset traits - For extending agents with custom capabilities
  • Llm trait - For LLM provider integrations
  • SchemaAdapter trait - Provider-aware JSON Schema normalization for MCP tools
  • Context hierarchy - ReadonlyContext → CallbackContext → ToolContext/InvocationContext
  • Content / Part - Message content structures
  • Event system - For streaming agent responses
  • Session / State - For managing conversation context
  • Error types - Unified error handling

This crate is model-agnostic and contains no LLM-specific code.

Installation

[dependencies]
adk-core = "2.0.0"

Or use the meta-crate:

[dependencies]
adk-rust = "2.0.0"

Core Traits

Agent

#[async_trait]
pub trait Agent: Send + Sync {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn sub_agents(&self) -> &[Arc<dyn Agent>];
    async fn run(&self, ctx: Arc<dyn InvocationContext>) -> Result<EventStream>;
}

Tool

#[async_trait]
pub trait Tool: Send + Sync {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn parameters_schema(&self) -> Option<Value>;
    fn is_long_running(&self) -> bool;
    fn is_read_only(&self) -> bool;           // default: false
    fn is_concurrency_safe(&self) -> bool;    // default: false
    async fn execute(&self, ctx: Arc<dyn ToolContext>, args: Value) -> Result<Value>;
}

ToolExecutionStrategy::Auto includes a call in its concurrent subset only when the selected tool returns true from both is_read_only() and is_concurrency_safe(). It runs that safe subset first, then executes the remaining calls sequentially. Both methods default to false, so existing implementations remain sequential.

Toolset

#[async_trait]
pub trait Toolset: Send + Sync {
    fn name(&self) -> &str;
    async fn tools(&self, ctx: Arc<dyn ReadonlyContext>) -> Result<Vec<Arc<dyn Tool>>>;
}

Llm

#[async_trait]
pub trait Llm: Send + Sync {
    fn name(&self) -> &str;
    async fn generate_content(&self, request: LlmRequest, stream: bool) -> Result<LlmResponseStream>;
    fn schema_adapter(&self) -> &dyn SchemaAdapter; // default: GenericSchemaAdapter
}

SchemaAdapter

pub trait SchemaAdapter: Send + Sync + Debug {
    fn normalize_schema(&self, schema: Value) -> Value;
    fn normalize_tool_name<'a>(&self, name: &'a str) -> Cow<'a, str>;
    fn empty_schema(&self) -> Value;
}

Provider-specific schema normalization for MCP tools. Each Llm implementation returns its adapter via schema_adapter(). See GenericSchemaAdapter for the default implementation.

Key Types

Content & Part

// Message content with role and parts
let content = Content::new("user")
    .with_text("Hello!")
    .with_inline_data("image/png", image_bytes)
    .with_file_uri("image/jpeg", "https://example.com/image.jpg");

// Part variants
enum Part {
    Text { text: String },
    InlineData { mime_type: String, data: Vec<u8>, uri: Option<String>, annotations: Option<Value> },
    FileData { mime_type: String, file_uri: String, annotations: Option<Value> },
    FunctionCall { name: String, args: Value, id: Option<String> },
    FunctionResponse { function_response: FunctionResponseData, id: Option<String>, annotations: Option<Value> },
}

Multimodal Function Responses

Tools can return images, audio, or file references alongside JSON:

// Tool returns JSON with inline_data — framework extracts automatically
Ok(json!({
    "response": { "title": "Q4 Chart" },
    "inline_data": [{ "mime_type": "image/png", "data": png_bytes }]
}))

// Direct construction
let frd = FunctionResponseData::with_inline_data(
    "chart_tool",
    json!({"title": "Q4 Chart"}),
    vec![InlineDataPart {
        mime_type: "image/png".into(),
        data: png_bytes,
        uri: None,
        annotations: None,
    }],
);

// File references (URIs to external files)
let frd = FunctionResponseData::with_file_data(
    "doc_tool",
    json!({"status": "ok"}),
    vec![FileDataPart {
        mime_type: "application/pdf".into(),
        file_uri: "gs://bucket/report.pdf".into(),
        annotations: None,
    }],
);

Event

// Events stream from agent execution
let event = Event::new("invocation_123");
event.content()  // Access response content
event.actions    // State changes, transfers, escalation

// Provider-specific metadata (replaces GCP-specific fields)
event.provider_metadata  // HashMap<String, String>

First-class tool events

Events expose typed, render-ready views of tool activity, so UIs consume tool calls and results generically without matching Part internals:

for call in event.tool_calls() {       // Vec<ToolCallView>
    println!("{} {}", call.name, call.args);
}
for result in event.tool_results() {   // Vec<ToolResultView>
    println!("{} {}", result.name, result.response);
}

Because a tool's result is an ordinary event, the output of any tool — streaming or one-shot — is renderable. Use call_id to correlate a call with its result (and progress chunks).

Streaming tool progress

A tool can push intermediate output while still running via ToolContext::emit_progress("stdout", chunk). The framework forwards each chunk as a partial event on the same EventStream; detect them with:

if let Some(stream_name) = event.tool_progress_stream() {  // "stdout" | "stderr" | custom
    // render a live terminal line
}

The default emit_progress is a no-op, so non-streaming tools are unaffected.

EventActions

pub struct EventActions {
    pub state_delta: HashMap<String, Value>,  // State updates
    pub artifact_delta: HashMap<String, i64>, // Artifact changes
    pub skip_summarization: bool,
    pub transfer_to_agent: Option<String>,    // Agent transfer
    pub escalate: bool,                       // Escalate to parent
    pub tool_confirmation: Option<ToolConfirmationRequest>,  // Pending tool confirmation
    pub tool_confirmation_decision: Option<ToolConfirmationDecision>,
    pub compaction: Option<EventCompaction>,  // Context compaction summary
}

EventCompaction

When context compaction is enabled, older events are summarized into a single compacted event:

pub struct EventCompaction {
    pub start_timestamp: DateTime<Utc>,   // Earliest compacted event
    pub end_timestamp: DateTime<Utc>,     // Latest compacted event
    pub compacted_content: Content,       // The summary replacing original events
}

High-Stakes Tooling & Context Engineering

For production agents, adk-core provides types to ensure that an agent's instructions (the cognitive frame) always match its tool capabilities (the physical frame).

ResolvedContext

An "atomic unit" containing the final system instruction and the collection of verified, binary Arc<dyn Tool> instances. This prevents "Phantom Tool" hallucinations.

ToolRegistry

A foundational trait for mapping string-based tool names (from config or skills) to concrete executable tool instances.

ValidationMode

Defines how the framework handles cases where a requested tool is missing:

  • Strict: Rejects the match/operation if any tool is missing.
  • Permissive: Binds available tools, omits missing ones, and logs a warning.

Context Hierarchy

ReadonlyContext (read-only access)
    ├── invocation_id, agent_name, user_id, app_name, session_id
    └── user_content()

CallbackContext (extends ReadonlyContext)
    └── artifacts()

ToolContext (extends CallbackContext)
    ├── function_call_id()
    ├── actions() / set_actions()
    └── search_memory()

InvocationContext (extends CallbackContext)
    ├── agent(), memory(), session()
    ├── run_config()
    └── end_invocation() / ended()

Security

Inline Data Size Limit

Content::with_inline_data() and Part::inline_data() enforce a 10 MB limit (MAX_INLINE_DATA_SIZE) to prevent oversized payloads.

State Key Validation

validate_state_key() rejects keys that are empty, exceed 256 bytes (MAX_STATE_KEY_LEN), contain path separators (/, \, ..), or null bytes.

use adk_core::context::validate_state_key;

assert!(validate_state_key("user_name").is_ok());
assert!(validate_state_key("../etc/passwd").is_err());

Provider Metadata

The Event struct uses a generic provider_metadata: HashMap<String, String> field for provider-specific data (e.g., GCP Vertex, Azure OpenAI), keeping the core type provider-agnostic.

State Management

State uses typed prefixes for organization:

Prefix Scope Persistence
user: User preferences Across sessions
app: Application state Application-wide
temp: Temporary data Cleared each turn
// Access state via session
let value = session.state().get("user:preference");
session.state().set("temp:counter".to_string(), json!(42));

State keys are validated with validate_state_key() — max length is MAX_STATE_KEY_LEN (256 bytes), and keys must be valid UTF-8 with no control characters.

Callbacks

// Callback type aliases
pub type BeforeAgentCallback = Box<dyn Fn(...) -> ... + Send + Sync>;
pub type AfterAgentCallback = Box<dyn Fn(...) -> ... + Send + Sync>;
pub type BeforeModelCallback = Box<dyn Fn(...) -> ... + Send + Sync>;
pub type AfterModelCallback = Box<dyn Fn(...) -> ... + Send + Sync>;
pub type BeforeToolCallback = Box<dyn Fn(...) -> ... + Send + Sync>;
pub type AfterToolCallback = Box<dyn Fn(...) -> ... + Send + Sync>;

// Instruction providers
pub type InstructionProvider = Box<dyn Fn(...) -> ... + Send + Sync>;
pub type GlobalInstructionProvider = Box<dyn Fn(...) -> ... + Send + Sync>;

Context Compaction

Types for sliding-window context compaction (summarizing older events to reduce LLM context size):

/// Trait for summarizing events during compaction.
#[async_trait]
pub trait BaseEventsSummarizer: Send + Sync {
    async fn summarize_events(&self, events: &[Event]) -> Result<Option<Event>>;
}

/// Configuration for automatic context compaction.
pub struct EventsCompactionConfig {
    pub compaction_interval: u32,  // Invocations between compactions
    pub overlap_size: u32,         // Events to carry over for continuity
    pub summarizer: Arc<dyn BaseEventsSummarizer>,
}

Streaming Modes

pub enum StreamingMode {
    None,  // Complete responses only
    SSE,   // Server-Sent Events (default)
    Bidi,  // Bidirectional (realtime)
}

ToolExecutionStrategy

Controls how multiple tool calls from a single LLM response are dispatched:

pub enum ToolExecutionStrategy {
    Sequential,  // One at a time, in order (default)
    Parallel,    // All concurrently; caller owns safety
    Auto,        // Safe read-only subset concurrently, then the rest sequentially
}

Set per-agent via LlmAgentBuilder::tool_execution_strategy(). Parallel is an explicit override that does not inspect tool metadata.

Related Crates

License

Apache-2.0

Part of ADK-Rust

This crate is part of the ADK-Rust framework for building AI agents in Rust.