Skip to content

Google ADK Analysis: Primitives, Style, and JAF Integration Plan

Executive Summary

Google ADK (Agent Development Kit) represents a mature, production-ready framework for building AI agents with a rich ecosystem of tools, session management, and streaming capabilities. This document analyzes ADK's core primitives and programming patterns to design a JAF ADK Layer that brings ADK-style functionality to JAF's functional paradigm.

ADK Programming Style Analysis

1. Architecture Philosophy

  • Composition over Inheritance: ADK uses classes but emphasizes composition
  • Event-Driven Design: Built around async events and streaming
  • Declarative Configuration: Agents defined through configuration objects
  • Service-Oriented: Clear separation of concerns with injected services

2. Programming Patterns

# Typical ADK Agent Definition
agent = LlmAgent(
    name="weather_agent",
    model="gemini-2.0-flash",
    instruction="You are a weather assistant...",
    tools=[weather_tool, location_tool],
    input_schema=WeatherQuery,
    output_schema=WeatherResponse
)

# Execution Pattern
runner = Runner(agent=agent, session_service=session_service)
events = runner.run_async(user_id="123", session_id="456", new_message=content)

3. Key Design Principles

  • Async-First: All operations are async by default
  • Type Safety: Heavy use of Pydantic models and schemas
  • Dependency Injection: Services are injected, not created internally
  • Immutable Configuration: Agents are configured once, then used
  • Event Streaming: Real-time interaction through event streams

ADK Core Primitives

1. Agent System

Primary Classes

  • LlmAgent: Core agent implementation with LLM integration
  • Agent: Simplified agent wrapper
  • BaseAgent: Abstract base for custom agent types
  • CodePipelineAgent: Specialized multi-step agent

Key Properties

LlmAgent(
    name: str,              # Agent identifier
    model: str,             # LLM model specification
    instruction: str,       # Natural language behavior definition
    description: str,       # Agent purpose description
    tools: List[Tool],      # Available tools
    sub_agents: List[Agent], # Child agents for delegation
    input_schema: BaseModel, # Input validation schema
    output_schema: BaseModel, # Output validation schema
    output_key: str         # Result storage key
)

2. Execution System

Runner Pattern

class Runner:
    def __init__(self, agent: Agent, session_service: SessionService)

    async def run_async(self, user_id: str, session_id: str, 
                       new_message: Content) -> AsyncIterator[Event]

    def run_live(self, session: Session, 
                live_request_queue: LiveRequestQueue) -> AsyncIterator[Event]

Session Management

class InMemorySessionService:
    async def create_session(self, app_name: str, user_id: str, 
                           session_id: str) -> Session
    async def get_session(self, user_id: str, session_id: str) -> Session
    async def list_sessions(self, user_id: str) -> List[Session]

3. Tool System

Tool Hierarchy

# Function Tools
FunctionTool(func=python_function)

# Toolsets
OpenAPIToolset(spec_str=openapi_spec, spec_str_type='json')
CrewaiTool(name="search", tool=serper_tool)
LangchainTool(tool=tavily_search)
MCPToolset(connection_params=stdio_params)

# Base Classes
class BaseTool:
    async def invoke(self, **kwargs) -> Any

class BaseToolset:
    async def get_tools(self, context: ReadonlyContext) -> List[BaseTool]
    async def close(self) -> None

Tool Context

class ToolContext:
    actions: ToolActions  # Flow control (transfer_to_agent, etc.)
    session: Session      # Current session
    # Runtime context for tools

4. Content and Communication

Content System

# Message Structure
Content(
    role='user'|'model',
    parts=[Part(text="message content")]
)

# Events
class Event:
    def is_final_response(self) -> bool
    def get_function_calls(self) -> List[FunctionCall]
    def get_function_responses(self) -> List[FunctionResponse]
    @property
    def content(self) -> Content

Streaming

# Live Interaction
LiveRequestQueue()  # Bidirectional communication
RunConfig(response_modalities=["TEXT"|"AUDIO"])

5. Schema and Validation

Pydantic Integration

class WeatherQuery(BaseModel):
    location: str = Field(description="City or location name")
    units: str = Field(default="celsius", description="Temperature units")

class WeatherResponse(BaseModel):
    temperature: float
    conditions: str
    humidity: int

6. Advanced Features

Multi-Agent Systems

coordinator = LlmAgent(
    name="coordinator",
    sub_agents=[specialist1, specialist2, specialist3]
)

Callbacks and Guardrails

def guardrail_callback(context: CallbackContext) -> Optional[LlmResponse]:
    if "forbidden" in context.llm_request.prompt:
        return LlmResponse(text="Cannot process this request")
    return None

agent.add_callback("before_model", guardrail_callback)

Example System

ExampleTool(examples=[
    Example(
        input=Content(role='user', parts=[Part(text="What's 2+2?")]),
        output=[Content(role='model', parts=[Part(text="4")])]
    )
])

JAF vs ADK Feature Comparison

ADK Strengths

Rich Tool Ecosystem: OpenAPI, CrewAI, LangChain, MCP integrations
Session Management: Built-in conversation state handling
Streaming Support: Native real-time interaction
Multi-Agent Systems: Hierarchical agent composition
Schema Validation: Pydantic input/output schemas
Guardrails: Built-in safety mechanisms
Example System: Few-shot learning support
Artifact Management: Persistent data handling
Live Interaction: Bidirectional communication
Web UI: Built-in agent testing interface

JAF Strengths

Functional Purity: No classes, immutable functions
Simplicity: Minimal API surface
Memory Providers: Pluggable persistence layer
Lightweight: Minimal dependencies
TypeScript Native: Strong typing throughout

JAF Missing Features (Present in ADK)

Rich Tool Integrations: Limited to basic function tools
Session Management: Basic conversation handling
Streaming: Manual implementation required
Multi-Agent: No built-in agent delegation
Schema Validation: No input/output validation
Guardrails: No safety mechanisms
Example System: No few-shot support
Live Interaction: No bidirectional communication
Web UI: No built-in testing interface
Artifact Management: No persistent data system

ADK Integration Patterns

1. Tool Integration Ecosystem

# Multiple integration patterns
tools = [
    google_search,                    # Built-in tools
    FunctionTool(func=custom_func),   # Function wrapping
    OpenAPIToolset(...),              # API integration
    CrewaiTool(...),                  # CrewAI tools
    LangchainTool(...),               # LangChain tools
    MCPToolset(...)                   # MCP protocol
]

2. Service Architecture

# Dependency injection pattern
runner = Runner(
    agent=agent,
    session_service=session_service,
    artifact_service=artifact_service
)

3. Configuration-Driven Design

# Declarative agent configuration
agent = LlmAgent(
    model="gemini-2.0-flash",
    instruction="""
    You are a {role} assistant.
    Use tools to {task}.
    Follow these constraints: {constraints}
    """,
    tools=dynamic_tools,
    input_schema=RequestSchema,
    output_schema=ResponseSchema
)

Next Steps

This analysis provides the foundation for designing a JAF ADK Layer that brings ADK's rich feature set to JAF's functional paradigm while maintaining JAF's core principles of functional purity and simplicity.