Runtime & Execution
Understanding the agent execution engine and event-driven architecture
The ADK Runtime is the execution engine that powers agent applications during user interactions. It orchestrates agents, tools, and services through an event-driven architecture.
Overview
The Runtime serves as the coordination layer that connects all components of your agent application and manages their interactions through a cooperative async generator pattern.
Core Responsibilities
- Execution Orchestration: Coordinate agent, tool, and callback execution
- Event Processing: Handle event flow between components
- State Management: Manage session state changes and persistence
- Service Integration: Connect with LLMs, storage, and external services
- Resource Management: Handle lifecycle and resource allocation
Event-Driven Architecture
The Runtime operates on events - agents yield events to communicate with the Runner, which processes them and coordinates with services before allowing agents to continue.
Quick Start
Here's a basic example of how the Runtime works:
import { LlmAgent, Runner, InMemorySessionService } from '@iqai/adk';
// Create an agent
const agent = new LlmAgent({
name: "assistant",
model: "gemini-2.5-flash",
description: "A helpful assistant",
instruction: "You are a helpful assistant"
});
// Set up runtime components
const sessionService = new InMemorySessionService();
const session = await sessionService.createSession("example", "user_123");
const runner = new Runner({
appName: "example",
agent,
sessionService
});
// Process user input through the runtime
for await (const event of runner.runAsync({
userId: "user_123",
sessionId: session.id,
newMessage: { parts: [{ text: "Hello!" }] }
})) {
console.log('Event:', event.author, event.content?.parts);
}Even simpler with AgentBuilder (ADK‑TS)
If you prefer an even simpler API, you can use the AgentBuilder to get up and running quickly without wiring sessions and the runner yourself. See the full guide: Agent Builder.
import { AgentBuilder } from '@iqai/adk';
// One-liner execution with automatic in-memory session and smart defaults
const response = await AgentBuilder
.withModel('gemini-2.5-flash')
.ask('Hello!');
console.log(response);You can also keep a handle to the runner and session if you want streaming events and state control while still using the builder:
import { AgentBuilder } from '@iqai/adk';
const { runner, session } = await AgentBuilder
.create('example-assistant')
.withModel('gemini-2.5-flash')
.withInstruction('You are a helpful assistant')
.build();
for await (const event of runner.runAsync({
userId: 'user_123',
sessionId: session.id,
newMessage: { parts: [{ text: 'Hello!' }] }
})) {
console.log('Event:', event.author, event.content?.parts);
}Automatic session management
AgentBuilder auto-creates and manages an in-memory session by default — no setup required. Switch to a persistent SessionService (e.g., Redis/DB) only when you need durable sessions. You can always fall back to the lower-level Runtime pattern above for full control.
What’s happening under the hood?
Both versions above follow the same Runtime model:
- A
Sessionis created (in-memory by default) and identified byappName(here, "example") anduserId. - The
Runnerorchestrates execution. It appends the new user message, iterates the agent’s async generator, and persists non-partial events. - The
Agentyields events (model output, tool calls/results, state deltas), which theRunnerprocesses and then continues execution. - The AgentBuilder shortcut simply constructs the agent, session, and runner with smart defaults and, when using
ask(), consumes the event stream to return the final response directly.
Key components of the Runtime
Several components work together within the ADK Runtime to execute an agent invocation. Understanding their roles clarifies how the event loop functions:
- Role: The main entry point and orchestrator for a single user query (
runAsync). - Function: Manages the overall event loop, receives events yielded by the execution logic (agents/flows), coordinates with services to persist effects, and forwards processed events upstream (e.g., to the UI). It drives each turn by:
- Loading the
SessionviaSessionService - Creating an
InvocationContextwith aninvocationId - Appending the new user message as an event
- Iterating the agent’s
runAsyncgenerator, appending non-partial events and updating memory - Yielding events to callers as they occur
- Loading the
- Role: Your custom reasoning code and core agent capabilities.
- Components:
Agent(BaseAgent,LlmAgent, etc.): Primary logic units that process information and decide on actions. They implement therunAsyncImplmethod and yieldEventobjects to communicate progress, tool calls, state deltas, and final replies.Tools(BaseTool,FunctionTool,AgentTool, etc.): External capabilities invoked by agents. They execute and return results which are wrapped in events; some tools can run other agents (AgentTool).Callbacks: Hook points for customizing behavior. OnBaseAgentyou can setbeforeAgentCallbackandafterAgentCallback; onLlmAgentyou can also usebeforeModelCallback,afterModelCallback,beforeToolCallback, andafterToolCallbackto shape requests/responses.
- Function: Perform the “thinking,” calculations, and external interactions. They communicate via yielded
Events and pause until theRunnerprocesses/persists effects.
- Role: The message passed between the
Runnerand execution logic. - Function: Represents an atomic occurrence (user input, agent text, tool call/result, state change request, control signal). An
Eventcontains content plusactions(EventActions) describing intended side effects, for example:stateDelta: keys to merge into session state (keys prefixed withtemp_are treated as ephemeral and not persisted into state)artifactDelta: artifact file/version updates associated with the sessiontransferToAgent,escalate, andskipSummarizationcontrol signals
- Role: Backend components for persistent/shared resources. Primarily used by the
Runnerduring event processing. - Components:
SessionService(BaseSessionService,InMemorySessionService, etc.): ManagesSessionobjects, appliesstateDeltato session state, and appends events to the history.ArtifactService(BaseArtifactService,InMemoryArtifactService, etc.): Stores and retrieves binary data. TheRunnercan save uploaded blobs as artifacts and events can recordartifactDeltato reflect updates.MemoryService(BaseMemoryService,InMemoryMemoryService, etc.): Optional long-term semantic memory; theRunnercan update memory after appending events.
- Function: Provide persistence and retrieval guarantees so that changes signaled by
event.actionsare reliably stored before execution continues.
- Role: The data container for one specific conversation between a user and the app.
- Function: Holds the current
stateobject, orderedeventshistory, and metadata. Managed bySessionServiceand used byRunnerand agents to maintain context across turns.
- Role: Everything that happens in response to a single user query, from receipt to completion.
- Function: Represented at runtime by
InvocationContext(with a stableinvocationId). An invocation may include multiple agent runs (e.g., transfers,AgentTool), several LLM calls, tool executions, and callbacks. Temporary variables intended only for the current turn should be scoped under keys prefixed withtemp_instateDelta.
These components interact continuously through the event loop to process the user’s request.
Related Topics
How is this guide?