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 integrationAgent
: Simplified agent wrapperBaseAgent
: Abstract base for custom agent typesCodePipelineAgent
: 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¶
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.