@@ -544,7 +540,7 @@ Control whether the agent receives the prior conversation history.
# ... your tools here
)
```
-
+
* **`PlanReActPlanner`:** This planner instructs the model to follow a specific structure in its output: first create a plan, then execute actions (like calling tools), and provide reasoning for its steps. *It's particularly useful for models that don't have a built-in "thinking" feature*.
```python
@@ -703,9 +699,9 @@ call_agent("If it's raining in New York right now, what is the current temperatu
- **`code_executor` (Optional):** Provide a `BaseCodeExecutor` instance to allow the agent to execute code blocks found in the LLM's response. ([See Tools/Built-in tools](../tools/built-in-tools.md)).
-== "Python"
+=== "Python"
- ```py
+ ```python
--8<-- "examples/python/snippets/tools/built-in-tools/code_execution.py"
```
@@ -721,11 +717,17 @@ call_agent("If it's raining in New York right now, what is the current temperatu
Here's the complete basic `capital_agent`:
=== "Python"
-
+
```python
--8<-- "examples/python/snippets/agents/llm-agent/capital_agent.py"
```
-
+
+ === "Typescript"
+
+ ```javascript
+ --8<-- "examples/typescript/snippets/agents/llm-agent/capital_agent.ts"
+ ```
+
=== "Go"
```go
@@ -733,16 +735,10 @@ call_agent("If it's raining in New York right now, what is the current temperatu
```
=== "Java"
-
+
```java
--8<-- "examples/java/snippets/src/main/java/agents/LlmAgentExample.java:full_code"
```
-
- === "Typescript"
-
- ```javascript
- --8<-- "examples/typescript/snippets/agents/llm-agent/capital_agent.ts"
- ```
_(This example demonstrates the core concepts. More complex agents might incorporate schemas, context control, planning, etc.)_
diff --git a/docs/agents/models.md b/docs/agents/models.md
index 771318939..39854df17 100644
--- a/docs/agents/models.md
+++ b/docs/agents/models.md
@@ -1,7 +1,7 @@
# Using Different Models with ADK
- Supported in ADKPython v0.1.0Go v0.1.0Java v0.1.0
+ Supported in ADKPython v0.1.0TypeScript v0.1.0Go v0.1.0Java v0.1.0
The Agent Development Kit (ADK) is designed for flexibility, allowing you to
diff --git a/docs/agents/multi-agents.md b/docs/agents/multi-agents.md
index fa4e149c6..b98b2db60 100644
--- a/docs/agents/multi-agents.md
+++ b/docs/agents/multi-agents.md
@@ -1,11 +1,7 @@
# Multi-Agent Systems in ADK
- Supported in ADK
- Python v0.1.0
- Go v0.1.0
- Java v0.1.0
- TypeScript v0.1.0
+ Supported in ADKPython v0.1.0TypeScript v0.1.0Go v0.1.0Java v0.1.0
As agentic applications grow in complexity, structuring them as a single, monolithic agent can become challenging to develop, maintain, and reason about. The Agent Development Kit (ADK) supports building sophisticated applications by composing multiple, distinct `BaseAgent` instances into a **Multi-Agent System (MAS)**.
@@ -40,11 +36,11 @@ The foundation for structuring multi-agent systems is the parent-child relations
```python
# Conceptual Example: Defining Hierarchy
from google.adk.agents import LlmAgent, BaseAgent
-
+
# Define individual agents
greeter = LlmAgent(name="Greeter", model="gemini-2.0-flash")
task_doer = BaseAgent(name="TaskExecutor") # Custom non-LLM agent
-
+
# Create parent agent and assign children via sub_agents
coordinator = LlmAgent(
name="Coordinator",
@@ -55,47 +51,12 @@ The foundation for structuring multi-agent systems is the parent-child relations
task_doer
]
)
-
+
# Framework automatically sets:
# assert greeter.parent_agent == coordinator
# assert task_doer.parent_agent == coordinator
```
-=== "Go"
-
- ```go
- import (
- "google.golang.org/adk/agent"
- "google.golang.org/adk/agent/llmagent"
- )
-
- --8<-- "examples/go/snippets/agents/multi-agent/main.go:hierarchy"
- ```
-
-=== "Java"
-
- ```java
- // Conceptual Example: Defining Hierarchy
- import com.google.adk.agents.SequentialAgent;
- import com.google.adk.agents.LlmAgent;
-
- // Define individual agents
- LlmAgent greeter = LlmAgent.builder().name("Greeter").model("gemini-2.0-flash").build();
- SequentialAgent taskDoer = SequentialAgent.builder().name("TaskExecutor").subAgents(...).build(); // Sequential Agent
-
- // Create parent agent and assign sub_agents
- LlmAgent coordinator = LlmAgent.builder()
- .name("Coordinator")
- .model("gemini-2.0-flash")
- .description("I coordinate greetings and tasks")
- .subAgents(greeter, taskDoer) // Assign sub_agents here
- .build();
-
- // Framework automatically sets:
- // assert greeter.parentAgent().equals(coordinator);
- // assert taskDoer.parentAgent().equals(coordinator);
- ```
-
=== "Typescript"
```typescript
@@ -137,7 +98,42 @@ The foundation for structuring multi-agent systems is the parent-child relations
// Framework automatically sets:
// console.assert(greeter.parentAgent === coordinator);
// console.assert(taskDoer.parentAgent === coordinator);
+ ```
+
+=== "Go"
+
+ ```go
+ import (
+ "google.golang.org/adk/agent"
+ "google.golang.org/adk/agent/llmagent"
+ )
+
+ --8<-- "examples/go/snippets/agents/multi-agent/main.go:hierarchy"
+ ```
+
+=== "Java"
+ ```java
+ // Conceptual Example: Defining Hierarchy
+ import com.google.adk.agents.SequentialAgent;
+ import com.google.adk.agents.LlmAgent;
+
+ // Define individual agents
+ LlmAgent greeter = LlmAgent.builder().name("Greeter").model("gemini-2.0-flash").build();
+ SequentialAgent taskDoer = SequentialAgent.builder().name("TaskExecutor").subAgents(...).build(); // Sequential Agent
+
+ // Create parent agent and assign sub_agents
+ LlmAgent coordinator = LlmAgent.builder()
+ .name("Coordinator")
+ .model("gemini-2.0-flash")
+ .description("I coordinate greetings and tasks")
+ .subAgents(greeter, taskDoer) // Assign sub_agents here
+ .build();
+
+ // Framework automatically sets:
+ // assert greeter.parentAgent().equals(coordinator);
+ // assert taskDoer.parentAgent().equals(coordinator);
+ ```
### 1.2. Workflow Agents as Orchestrators { #workflow-agents-as-orchestrators }
@@ -159,6 +155,19 @@ ADK includes specialized agents derived from `BaseAgent` that don't perform task
# When pipeline runs, Step2 can access the state['data'] set by Step1.
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Example: Sequential Pipeline
+ import { SequentialAgent, LlmAgent } from '@google/adk';
+
+ const step1 = new LlmAgent({name: 'Step1_Fetch', outputKey: 'data'}); // Saves output to state['data']
+ const step2 = new LlmAgent({name: 'Step2_Process', instruction: 'Process data from {data}.'});
+
+ const pipeline = new SequentialAgent({name: 'MyPipeline', subAgents: [step1, step2]});
+ // When pipeline runs, Step2 can access the state['data'] set by Step1.
+ ```
+
=== "Go"
```go
@@ -185,19 +194,6 @@ ADK includes specialized agents derived from `BaseAgent` that don't perform task
// When pipeline runs, Step2 can access the state.get("data") set by Step1.
```
-=== "Typescript"
-
- ```typescript
- // Conceptual Example: Sequential Pipeline
- import { SequentialAgent, LlmAgent } from '@google/adk';
-
- const step1 = new LlmAgent({name: 'Step1_Fetch', outputKey: 'data'}); // Saves output to state['data']
- const step2 = new LlmAgent({name: 'Step2_Process', instruction: 'Process data from {data}.'});
-
- const pipeline = new SequentialAgent({name: 'MyPipeline', subAgents: [step1, step2]});
- // When pipeline runs, Step2 can access the state['data'] set by Step1.
-
-
* **[`ParallelAgent`](workflow-agents/parallel-agents.md):** Executes its `sub_agents` in parallel. Events from sub-agents may be interleaved.
* **Context:** Modifies the `InvocationContext.branch` for each child agent (e.g., `ParentBranch.ChildName`), providing a distinct contextual path which can be useful for isolating history in some memory implementations.
* **State:** Despite different branches, all parallel children access the *same shared* `session.state`, enabling them to read initial state and write results (use distinct keys to avoid race conditions).
@@ -215,7 +211,21 @@ ADK includes specialized agents derived from `BaseAgent` that don't perform task
# When gatherer runs, WeatherFetcher and NewsFetcher run concurrently.
# A subsequent agent could read state['weather'] and state['news'].
```
-
+
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Example: Parallel Execution
+ import { ParallelAgent, LlmAgent } from '@google/adk';
+
+ const fetchWeather = new LlmAgent({name: 'WeatherFetcher', outputKey: 'weather'});
+ const fetchNews = new LlmAgent({name: 'NewsFetcher', outputKey: 'news'});
+
+ const gatherer = new ParallelAgent({name: 'InfoGatherer', subAgents: [fetchWeather, fetchNews]});
+ // When gatherer runs, WeatherFetcher and NewsFetcher run concurrently.
+ // A subsequent agent could read state['weather'] and state['news'].
+ ```
+
=== "Go"
```go
@@ -234,39 +244,25 @@ ADK includes specialized agents derived from `BaseAgent` that don't perform task
// Conceptual Example: Parallel Execution
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.ParallelAgent;
-
+
LlmAgent fetchWeather = LlmAgent.builder()
.name("WeatherFetcher")
.outputKey("weather")
.build();
-
+
LlmAgent fetchNews = LlmAgent.builder()
.name("NewsFetcher")
.instruction("news")
.build();
-
+
ParallelAgent gatherer = ParallelAgent.builder()
.name("InfoGatherer")
.subAgents(fetchWeather, fetchNews)
.build();
-
- // When gatherer runs, WeatherFetcher and NewsFetcher run concurrently.
- // A subsequent agent could read state['weather'] and state['news'].
- ```
-
-=== "Typescript"
- ```typescript
- // Conceptual Example: Parallel Execution
- import { ParallelAgent, LlmAgent } from '@google/adk';
-
- const fetchWeather = new LlmAgent({name: 'WeatherFetcher', outputKey: 'weather'});
- const fetchNews = new LlmAgent({name: 'NewsFetcher', outputKey: 'news'});
-
- const gatherer = new ParallelAgent({name: 'InfoGatherer', subAgents: [fetchWeather, fetchNews]});
// When gatherer runs, WeatherFetcher and NewsFetcher run concurrently.
// A subsequent agent could read state['weather'] and state['news'].
-
+ ```
* **[`LoopAgent`](workflow-agents/loop-agents.md):** Executes its `sub_agents` sequentially in a loop.
* **Termination:** The loop stops if the optional `max_iterations` is reached, or if any sub-agent returns an [`Event`](../events/index.md) with `escalate=True` in it's Event Actions.
@@ -297,7 +293,52 @@ ADK includes specialized agents derived from `BaseAgent` that don't perform task
# When poller runs, it executes process_step then Checker repeatedly
# until Checker escalates (state['status'] == 'completed') or 10 iterations pass.
```
-
+
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Example: Loop with Condition
+ import { LoopAgent, LlmAgent, BaseAgent, InvocationContext } from '@google/adk';
+ import type { Event, createEventActions, EventActions } from '@google/adk';
+
+ class CheckConditionAgent extends BaseAgent { // Custom agent to check state
+ async *runAsyncImpl(ctx: InvocationContext): AsyncGenerator
{
+ const status = ctx.session.state['status'] || 'pending';
+ const isDone = status === 'completed';
+ yield createEvent({ author: 'check_condition', actions: createEventActions({ escalate: isDone }) });
+ }
+
+ async *runLiveImpl(ctx: InvocationContext): AsyncGenerator {
+ // This is not implemented.
+ }
+ };
+
+ const processStep = new LlmAgent({name: 'ProcessingStep'}); // Agent that might update state['status']
+
+ const poller = new LoopAgent({
+ name: 'StatusPoller',
+ maxIterations: 10,
+ // Executes its sub_agents sequentially in a loop
+ subAgents: [processStep, new CheckConditionAgent ({name: 'Checker'})]
+ });
+ // When poller runs, it executes processStep then Checker repeatedly
+ // until Checker escalates (state['status'] === 'completed') or 10 iterations pass.
+ ```
+
+=== "Go"
+
+ ```go
+ import (
+ "iter"
+ "google.golang.org/adk/agent"
+ "google.golang.org/adk/agent/llmagent"
+ "google.golang.org/adk/agent/workflowagents/loopagent"
+ "google.golang.org/adk/session"
+ )
+
+ --8<-- "examples/go/snippets/agents/multi-agent/main.go:loop-with-condition"
+ ```
+
=== "Java"
```java
@@ -307,7 +348,7 @@ ADK includes specialized agents derived from `BaseAgent` that don't perform task
public CheckConditionAgent(String name, String description) {
super(name, description, List.of(), null, null);
}
-
+
@Override
protected Flowable runAsyncImpl(InvocationContext ctx) {
String status = (String) ctx.session().state().getOrDefault("status", "pending");
@@ -323,7 +364,7 @@ ADK includes specialized agents derived from `BaseAgent` that don't perform task
return Flowable.just(checkEvent);
}
}
-
+
// Agent that might update state.put("status")
LlmAgent processingStepAgent = LlmAgent.builder().name("ProcessingStep").build();
// Custom agent instance for checking the condition
@@ -336,51 +377,6 @@ ADK includes specialized agents derived from `BaseAgent` that don't perform task
// until Checker escalates (state.get("status") == "completed") or 10 iterations pass.
```
-=== "Go"
-
- ```go
- import (
- "iter"
- "google.golang.org/adk/agent"
- "google.golang.org/adk/agent/llmagent"
- "google.golang.org/adk/agent/workflowagents/loopagent"
- "google.golang.org/adk/session"
- )
-
- --8<-- "examples/go/snippets/agents/multi-agent/main.go:loop-with-condition"
- ```
-
-=== "Typescript"
-
- ```typescript
- // Conceptual Example: Loop with Condition
- import { LoopAgent, LlmAgent, BaseAgent, InvocationContext } from '@google/adk';
- import type { Event, createEventActions, EventActions } from '@google/adk';
-
- class CheckConditionAgent extends BaseAgent { // Custom agent to check state
- async *runAsyncImpl(ctx: InvocationContext): AsyncGenerator {
- const status = ctx.session.state['status'] || 'pending';
- const isDone = status === 'completed';
- yield createEvent({ author: 'check_condition', actions: createEventActions({ escalate: isDone }) });
- }
-
- async *runLiveImpl(ctx: InvocationContext): AsyncGenerator {
- // This is not implemented.
- }
- };
-
- const processStep = new LlmAgent({name: 'ProcessingStep'}); // Agent that might update state['status']
-
- const poller = new LoopAgent({
- name: 'StatusPoller',
- maxIterations: 10,
- // Executes its sub_agents sequentially in a loop
- subAgents: [processStep, new CheckConditionAgent ({name: 'Checker'})]
- });
- // When poller runs, it executes processStep then Checker repeatedly
- // until Checker escalates (state['status'] === 'completed') or 10 iterations pass.
-
-
### 1.3. Interaction & Communication Mechanisms { #interaction-communication-mechanisms }
Agents within a system often need to exchange data or trigger actions in one another. ADK facilitates this through:
@@ -402,37 +398,27 @@ The most fundamental way for agents operating within the same invocation (and th
```python
# Conceptual Example: Using output_key and reading state
from google.adk.agents import LlmAgent, SequentialAgent
-
+
agent_A = LlmAgent(name="AgentA", instruction="Find the capital of France.", output_key="capital_city")
agent_B = LlmAgent(name="AgentB", instruction="Tell me about the city stored in {capital_city}.")
-
+
pipeline = SequentialAgent(name="CityInfo", sub_agents=[agent_A, agent_B])
# AgentA runs, saves "Paris" to state['capital_city'].
# AgentB runs, its instruction processor reads state['capital_city'] to get "Paris".
```
-=== "Java"
+=== "Typescript"
- ```java
+ ```typescript
// Conceptual Example: Using outputKey and reading state
- import com.google.adk.agents.LlmAgent;
- import com.google.adk.agents.SequentialAgent;
-
- LlmAgent agentA = LlmAgent.builder()
- .name("AgentA")
- .instruction("Find the capital of France.")
- .outputKey("capital_city")
- .build();
-
- LlmAgent agentB = LlmAgent.builder()
- .name("AgentB")
- .instruction("Tell me about the city stored in {capital_city}.")
- .outputKey("capital_city")
- .build();
-
- SequentialAgent pipeline = SequentialAgent.builder().name("CityInfo").subAgents(agentA, agentB).build();
- // AgentA runs, saves "Paris" to state('capital_city').
- // AgentB runs, its instruction processor reads state.get("capital_city") to get "Paris".
+ import { LlmAgent, SequentialAgent } from '@google/adk';
+
+ const agentA = new LlmAgent({name: 'AgentA', instruction: 'Find the capital of France.', outputKey: 'capital_city'});
+ const agentB = new LlmAgent({name: 'AgentB', instruction: 'Tell me about the city stored in {capital_city}.'});
+
+ const pipeline = new SequentialAgent({name: 'CityInfo', subAgents: [agentA, agentB]});
+ // AgentA runs, saves "Paris" to state['capital_city'].
+ // AgentB runs, its instruction processor reads state['capital_city'] to get "Paris".
```
=== "Go"
@@ -447,19 +433,29 @@ The most fundamental way for agents operating within the same invocation (and th
--8<-- "examples/go/snippets/agents/multi-agent/main.go:output-key-state"
```
-=== "Typescript"
+=== "Java"
- ```typescript
+ ```java
// Conceptual Example: Using outputKey and reading state
- import { LlmAgent, SequentialAgent } from '@google/adk';
+ import com.google.adk.agents.LlmAgent;
+ import com.google.adk.agents.SequentialAgent;
- const agentA = new LlmAgent({name: 'AgentA', instruction: 'Find the capital of France.', outputKey: 'capital_city'});
- const agentB = new LlmAgent({name: 'AgentB', instruction: 'Tell me about the city stored in {capital_city}.'});
+ LlmAgent agentA = LlmAgent.builder()
+ .name("AgentA")
+ .instruction("Find the capital of France.")
+ .outputKey("capital_city")
+ .build();
- const pipeline = new SequentialAgent({name: 'CityInfo', subAgents: [agentA, agentB]});
- // AgentA runs, saves "Paris" to state['capital_city'].
- // AgentB runs, its instruction processor reads state['capital_city'] to get "Paris".
+ LlmAgent agentB = LlmAgent.builder()
+ .name("AgentB")
+ .instruction("Tell me about the city stored in {capital_city}.")
+ .outputKey("capital_city")
+ .build();
+ SequentialAgent pipeline = SequentialAgent.builder().name("CityInfo").subAgents(agentA, agentB).build();
+ // AgentA runs, saves "Paris" to state('capital_city').
+ // AgentB runs, its instruction processor reads state.get("capital_city") to get "Paris".
+ ```
#### b) LLM-Driven Delegation (Agent Transfer)
@@ -475,10 +471,10 @@ Leverages an [`LlmAgent`](llm-agents.md)'s understanding to dynamically route ta
```python
# Conceptual Setup: LLM Transfer
from google.adk.agents import LlmAgent
-
+
booking_agent = LlmAgent(name="Booker", description="Handles flight and hotel bookings.")
info_agent = LlmAgent(name="Info", description="Provides general information and answers questions.")
-
+
coordinator = LlmAgent(
name="Coordinator",
model="gemini-2.0-flash",
@@ -492,22 +488,54 @@ Leverages an [`LlmAgent`](llm-agents.md)'s understanding to dynamically route ta
# ADK framework then routes execution to booking_agent.
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Setup: LLM Transfer
+ import { LlmAgent } from '@google/adk';
+
+ const bookingAgent = new LlmAgent({name: 'Booker', description: 'Handles flight and hotel bookings.'});
+ const infoAgent = new LlmAgent({name: 'Info', description: 'Provides general information and answers questions.'});
+
+ const coordinator = new LlmAgent({
+ name: 'Coordinator',
+ model: 'gemini-2.5-flash',
+ instruction: 'You are an assistant. Delegate booking tasks to Booker and info requests to Info.',
+ description: 'Main coordinator.',
+ // AutoFlow is typically used implicitly here
+ subAgents: [bookingAgent, infoAgent]
+ });
+ // If coordinator receives "Book a flight", its LLM should generate:
+ // {functionCall: {name: 'transfer_to_agent', args: {agent_name: 'Booker'}}}
+ // ADK framework then routes execution to bookingAgent.
+ ```
+
+=== "Go"
+
+ ```go
+ import (
+ "google.golang.org/adk/agent/llmagent"
+ )
+
+ --8<-- "examples/go/snippets/agents/multi-agent/main.go:llm-transfer"
+ ```
+
=== "Java"
```java
// Conceptual Setup: LLM Transfer
import com.google.adk.agents.LlmAgent;
-
+
LlmAgent bookingAgent = LlmAgent.builder()
.name("Booker")
.description("Handles flight and hotel bookings.")
.build();
-
+
LlmAgent infoAgent = LlmAgent.builder()
.name("Info")
.description("Provides general information and answers questions.")
.build();
-
+
// Define the coordinator agent
LlmAgent coordinator = LlmAgent.builder()
.name("Coordinator")
@@ -524,38 +552,6 @@ Leverages an [`LlmAgent`](llm-agents.md)'s understanding to dynamically route ta
// ADK framework then routes execution to bookingAgent.
```
-=== "Go"
-
- ```go
- import (
- "google.golang.org/adk/agent/llmagent"
- )
-
- --8<-- "examples/go/snippets/agents/multi-agent/main.go:llm-transfer"
- ```
-
-=== "Typescript"
-
- ```typescript
- // Conceptual Setup: LLM Transfer
- import { LlmAgent } from '@google/adk';
-
- const bookingAgent = new LlmAgent({name: 'Booker', description: 'Handles flight and hotel bookings.'});
- const infoAgent = new LlmAgent({name: 'Info', description: 'Provides general information and answers questions.'});
-
- const coordinator = new LlmAgent({
- name: 'Coordinator',
- model: 'gemini-2.5-flash',
- instruction: 'You are an assistant. Delegate booking tasks to Booker and info requests to Info.',
- description: 'Main coordinator.',
- // AutoFlow is typically used implicitly here
- subAgents: [bookingAgent, infoAgent]
- });
- // If coordinator receives "Book a flight", its LLM should generate:
- // {functionCall: {name: 'transfer_to_agent', args: {agent_name: 'Booker'}}}
- // ADK framework then routes execution to bookingAgent.
-
-
#### c) Explicit Invocation (`AgentTool`)
Allows an [`LlmAgent`](llm-agents.md) to treat another `BaseAgent` instance as a callable function or [Tool](../tools/index.md).
@@ -572,7 +568,7 @@ Allows an [`LlmAgent`](llm-agents.md) to treat another `BaseAgent` instance as a
from google.adk.agents import LlmAgent, BaseAgent
from google.adk.tools import agent_tool
from pydantic import BaseModel
-
+
# Define a target agent (could be LlmAgent or custom BaseAgent)
class ImageGeneratorAgent(BaseAgent): # Example custom agent
name: str = "ImageGen"
@@ -583,10 +579,10 @@ Allows an [`LlmAgent`](llm-agents.md) to treat another `BaseAgent` instance as a
# ... generate image bytes ...
image_bytes = b"..."
yield Event(author=self.name, content=types.Content(parts=[types.Part.from_bytes(image_bytes, "image/png")]))
-
+
image_agent = ImageGeneratorAgent()
image_tool = agent_tool.AgentTool(agent=image_agent) # Wrap the agent
-
+
# Parent agent uses the AgentTool
artist_agent = LlmAgent(
name="Artist",
@@ -600,6 +596,66 @@ Allows an [`LlmAgent`](llm-agents.md) to treat another `BaseAgent` instance as a
# The resulting image Part is returned to the Artist agent as the tool result.
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Setup: Agent as a Tool
+ import { LlmAgent, BaseAgent, AgentTool, InvocationContext } from '@google/adk';
+ import type { Part, createEvent, Event } from '@google/genai';
+
+ // Define a target agent (could be LlmAgent or custom BaseAgent)
+ class ImageGeneratorAgent extends BaseAgent { // Example custom agent
+ constructor() {
+ super({name: 'ImageGen', description: 'Generates an image based on a prompt.'});
+ }
+ // ... internal logic ...
+ async *runAsyncImpl(ctx: InvocationContext): AsyncGenerator { // Simplified run logic
+ const prompt = ctx.session.state['image_prompt'] || 'default prompt';
+ // ... generate image bytes ...
+ const imageBytes = new Uint8Array(); // placeholder
+ const imagePart: Part = {inlineData: {data: Buffer.from(imageBytes).toString('base64'), mimeType: 'image/png'}};
+ yield createEvent({content: {parts: [imagePart]}});
+ }
+
+ async *runLiveImpl(ctx: InvocationContext): AsyncGenerator {
+ // Not implemented for this agent.
+ }
+ }
+
+ const imageAgent = new ImageGeneratorAgent();
+ const imageTool = new AgentTool({agent: imageAgent}); // Wrap the agent
+
+ // Parent agent uses the AgentTool
+ const artistAgent = new LlmAgent({
+ name: 'Artist',
+ model: 'gemini-2.5-flash',
+ instruction: 'Create a prompt and use the ImageGen tool to generate the image.',
+ tools: [imageTool] // Include the AgentTool
+ });
+ // Artist LLM generates a prompt, then calls:
+ // {functionCall: {name: 'ImageGen', args: {image_prompt: 'a cat wearing a hat'}}}
+ // Framework calls imageTool.runAsync(...), which runs ImageGeneratorAgent.
+ // The resulting image Part is returned to the Artist agent as the tool result.
+ ```
+
+=== "Go"
+
+ ```go
+ import (
+ "fmt"
+ "iter"
+ "google.golang.org/adk/agent"
+ "google.golang.org/adk/agent/llmagent"
+ "google.golang.org/adk/model"
+ "google.golang.org/adk/session"
+ "google.golang.org/adk/tool"
+ "google.golang.org/adk/tool/agenttool"
+ "google.golang.org/genai"
+ )
+
+ --8<-- "examples/go/snippets/agents/multi-agent/main.go:agent-as-tool"
+ ```
+
=== "Java"
```java
@@ -610,26 +666,26 @@ Allows an [`LlmAgent`](llm-agents.md) to treat another `BaseAgent` instance as a
// Example custom agent (could be LlmAgent or custom BaseAgent)
public class ImageGeneratorAgent extends BaseAgent {
-
+
public ImageGeneratorAgent(String name, String description) {
super(name, description, List.of(), null, null);
}
-
+
// ... internal logic ...
@Override
protected Flowable runAsyncImpl(InvocationContext invocationContext) { // Simplified run logic
invocationContext.session().state().get("image_prompt");
// Generate image bytes
// ...
-
+
Event responseEvent = Event.builder()
.author(this.name())
.content(Content.fromParts(Part.fromText("...")))
.build();
-
+
return Flowable.just(responseEvent);
}
-
+
@Override
protected Flowable runLiveImpl(InvocationContext invocationContext) {
return null;
@@ -639,7 +695,7 @@ Allows an [`LlmAgent`](llm-agents.md) to treat another `BaseAgent` instance as a
// Wrap the agent using AgentTool
ImageGeneratorAgent imageAgent = new ImageGeneratorAgent("image_agent", "generates images");
AgentTool imageTool = AgentTool.create(imageAgent);
-
+
// Parent agent uses the AgentTool
LlmAgent artistAgent = LlmAgent.builder()
.name("Artist")
@@ -652,74 +708,14 @@ Allows an [`LlmAgent`](llm-agents.md) to treat another `BaseAgent` instance as a
"'result' field, containing 'image_base64', 'mime_type', and 'status'."
)
.description("An agent that can create images using a generation tool.")
- .tools(imageTool) // Include the AgentTool
- .build();
-
- // Artist LLM generates a prompt, then calls:
- // FunctionCall(name='ImageGen', args={'imagePrompt': 'a cat wearing a hat'})
- // Framework calls imageTool.runAsync(...), which runs ImageGeneratorAgent.
- // The resulting image Part is returned to the Artist agent as the tool result.
- ```
-
-=== "Go"
-
- ```go
- import (
- "fmt"
- "iter"
- "google.golang.org/adk/agent"
- "google.golang.org/adk/agent/llmagent"
- "google.golang.org/adk/model"
- "google.golang.org/adk/session"
- "google.golang.org/adk/tool"
- "google.golang.org/adk/tool/agenttool"
- "google.golang.org/genai"
- )
-
- --8<-- "examples/go/snippets/agents/multi-agent/main.go:agent-as-tool"
- ```
-
-=== "Typescript"
-
- ```typescript
- // Conceptual Setup: Agent as a Tool
- import { LlmAgent, BaseAgent, AgentTool, InvocationContext } from '@google/adk';
- import type { Part, createEvent, Event } from '@google/genai';
-
- // Define a target agent (could be LlmAgent or custom BaseAgent)
- class ImageGeneratorAgent extends BaseAgent { // Example custom agent
- constructor() {
- super({name: 'ImageGen', description: 'Generates an image based on a prompt.'});
- }
- // ... internal logic ...
- async *runAsyncImpl(ctx: InvocationContext): AsyncGenerator { // Simplified run logic
- const prompt = ctx.session.state['image_prompt'] || 'default prompt';
- // ... generate image bytes ...
- const imageBytes = new Uint8Array(); // placeholder
- const imagePart: Part = {inlineData: {data: Buffer.from(imageBytes).toString('base64'), mimeType: 'image/png'}};
- yield createEvent({content: {parts: [imagePart]}});
- }
-
- async *runLiveImpl(ctx: InvocationContext): AsyncGenerator {
- // Not implemented for this agent.
- }
-}
-
- const imageAgent = new ImageGeneratorAgent();
- const imageTool = new AgentTool({agent: imageAgent}); // Wrap the agent
-
- // Parent agent uses the AgentTool
- const artistAgent = new LlmAgent({
- name: 'Artist',
- model: 'gemini-2.5-flash',
- instruction: 'Create a prompt and use the ImageGen tool to generate the image.',
- tools: [imageTool] // Include the AgentTool
- });
+ .tools(imageTool) // Include the AgentTool
+ .build();
+
// Artist LLM generates a prompt, then calls:
- // {functionCall: {name: 'ImageGen', args: {image_prompt: 'a cat wearing a hat'}}}
+ // FunctionCall(name='ImageGen', args={'imagePrompt': 'a cat wearing a hat'})
// Framework calls imageTool.runAsync(...), which runs ImageGeneratorAgent.
// The resulting image Part is returned to the Artist agent as the tool result.
-
+ ```
These primitives provide the flexibility to design multi-agent interactions ranging from tightly coupled sequential workflows to dynamic, LLM-driven delegation networks.
@@ -740,10 +736,10 @@ By combining ADK's composition primitives, you can implement various established
```python
# Conceptual Code: Coordinator using LLM Transfer
from google.adk.agents import LlmAgent
-
+
billing_agent = LlmAgent(name="Billing", description="Handles billing inquiries.")
support_agent = LlmAgent(name="Support", description="Handles technical support requests.")
-
+
coordinator = LlmAgent(
name="HelpDeskCoordinator",
model="gemini-2.0-flash",
@@ -756,6 +752,27 @@ By combining ADK's composition primitives, you can implement various established
# User asks "I can't log in" -> Coordinator's LLM should call transfer_to_agent(agent_name='Support')
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Code: Coordinator using LLM Transfer
+ import { LlmAgent } from '@google/adk';
+
+ const billingAgent = new LlmAgent({name: 'Billing', description: 'Handles billing inquiries.'});
+ const supportAgent = new LlmAgent({name: 'Support', description: 'Handles technical support requests.'});
+
+ const coordinator = new LlmAgent({
+ name: 'HelpDeskCoordinator',
+ model: 'gemini-2.5-flash',
+ instruction: 'Route user requests: Use Billing agent for payment issues, Support agent for technical problems.',
+ description: 'Main help desk router.',
+ // allowTransfer=true is often implicit with subAgents in AutoFlow
+ subAgents: [billingAgent, supportAgent]
+ });
+ // User asks "My payment failed" -> Coordinator's LLM should call {functionCall: {name: 'transfer_to_agent', args: {agent_name: 'Billing'}}}
+ // User asks "I can't log in" -> Coordinator's LLM should call {functionCall: {name: 'transfer_to_agent', args: {agent_name: 'Support'}}}
+ ```
+
=== "Go"
```go
@@ -799,26 +816,6 @@ By combining ADK's composition primitives, you can implement various established
// transferToAgent(agentName='Support')
```
-=== "Typescript"
-
- ```typescript
- // Conceptual Code: Coordinator using LLM Transfer
- import { LlmAgent } from '@google/adk';
-
- const billingAgent = new LlmAgent({name: 'Billing', description: 'Handles billing inquiries.'});
- const supportAgent = new LlmAgent({name: 'Support', description: 'Handles technical support requests.'});
-
- const coordinator = new LlmAgent({
- name: 'HelpDeskCoordinator',
- model: 'gemini-2.5-flash',
- instruction: 'Route user requests: Use Billing agent for payment issues, Support agent for technical problems.',
- description: 'Main help desk router.',
- // allowTransfer=true is often implicit with subAgents in AutoFlow
- subAgents: [billingAgent, supportAgent]
- });
- // User asks "My payment failed" -> Coordinator's LLM should call {functionCall: {name: 'transfer_to_agent', args: {agent_name: 'Billing'}}}
- // User asks "I can't log in" -> Coordinator's LLM should call {functionCall: {name: 'transfer_to_agent', args: {agent_name: 'Support'}}}
-
### Sequential Pipeline Pattern
* **Structure:** A [`SequentialAgent`](workflow-agents/sequential-agents.md) contains `sub_agents` executed in a fixed order.
@@ -832,11 +829,11 @@ By combining ADK's composition primitives, you can implement various established
```python
# Conceptual Code: Sequential Data Pipeline
from google.adk.agents import SequentialAgent, LlmAgent
-
+
validator = LlmAgent(name="ValidateInput", instruction="Validate the input.", output_key="validation_status")
processor = LlmAgent(name="ProcessData", instruction="Process data if {validation_status} is 'valid'.", output_key="result")
reporter = LlmAgent(name="ReportResult", instruction="Report the result from {result}.")
-
+
data_pipeline = SequentialAgent(
name="DataPipeline",
sub_agents=[validator, processor, reporter]
@@ -846,6 +843,25 @@ By combining ADK's composition primitives, you can implement various established
# reporter runs -> reads state['result']
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Code: Sequential Data Pipeline
+ import { SequentialAgent, LlmAgent } from '@google/adk';
+
+ const validator = new LlmAgent({name: 'ValidateInput', instruction: 'Validate the input.', outputKey: 'validation_status'});
+ const processor = new LlmAgent({name: 'ProcessData', instruction: 'Process data if {validation_status} is "valid".', outputKey: 'result'});
+ const reporter = new LlmAgent({name: 'ReportResult', instruction: 'Report the result from {result}.'});
+
+ const dataPipeline = new SequentialAgent({
+ name: 'DataPipeline',
+ subAgents: [validator, processor, reporter]
+ });
+ // validator runs -> saves to state['validation_status']
+ // processor runs -> reads state['validation_status'], saves to state['result']
+ // reporter runs -> reads state['result']
+ ```
+
=== "Go"
```go
@@ -863,51 +879,33 @@ By combining ADK's composition primitives, you can implement various established
```java
// Conceptual Code: Sequential Data Pipeline
import com.google.adk.agents.SequentialAgent;
-
+
LlmAgent validator = LlmAgent.builder()
.name("ValidateInput")
.instruction("Validate the input")
.outputKey("validation_status") // Saves its main text output to session.state["validation_status"]
.build();
-
+
LlmAgent processor = LlmAgent.builder()
.name("ProcessData")
.instruction("Process data if {validation_status} is 'valid'")
.outputKey("result") // Saves its main text output to session.state["result"]
.build();
-
+
LlmAgent reporter = LlmAgent.builder()
.name("ReportResult")
.instruction("Report the result from {result}")
.build();
-
+
SequentialAgent dataPipeline = SequentialAgent.builder()
.name("DataPipeline")
.subAgents(validator, processor, reporter)
.build();
-
- // validator runs -> saves to state['validation_status']
- // processor runs -> reads state['validation_status'], saves to state['result']
- // reporter runs -> reads state['result']
- ```
-
-=== "Typescript"
-
- ```typescript
- // Conceptual Code: Sequential Data Pipeline
- import { SequentialAgent, LlmAgent } from '@google/adk';
-
- const validator = new LlmAgent({name: 'ValidateInput', instruction: 'Validate the input.', outputKey: 'validation_status'});
- const processor = new LlmAgent({name: 'ProcessData', instruction: 'Process data if {validation_status} is "valid".', outputKey: 'result'});
- const reporter = new LlmAgent({name: 'ReportResult', instruction: 'Report the result from {result}.'});
- const dataPipeline = new SequentialAgent({
- name: 'DataPipeline',
- subAgents: [validator, processor, reporter]
- });
// validator runs -> saves to state['validation_status']
// processor runs -> reads state['validation_status'], saves to state['result']
// reporter runs -> reads state['result']
+ ```
### Parallel Fan-Out/Gather Pattern
@@ -922,20 +920,20 @@ By combining ADK's composition primitives, you can implement various established
```python
# Conceptual Code: Parallel Information Gathering
from google.adk.agents import SequentialAgent, ParallelAgent, LlmAgent
-
+
fetch_api1 = LlmAgent(name="API1Fetcher", instruction="Fetch data from API 1.", output_key="api1_data")
fetch_api2 = LlmAgent(name="API2Fetcher", instruction="Fetch data from API 2.", output_key="api2_data")
-
+
gather_concurrently = ParallelAgent(
name="ConcurrentFetch",
sub_agents=[fetch_api1, fetch_api2]
)
-
+
synthesizer = LlmAgent(
name="Synthesizer",
instruction="Combine results from {api1_data} and {api2_data}."
)
-
+
overall_workflow = SequentialAgent(
name="FetchAndSynthesize",
sub_agents=[gather_concurrently, synthesizer] # Run parallel fetch, then synthesize
@@ -944,6 +942,33 @@ By combining ADK's composition primitives, you can implement various established
# synthesizer runs afterwards, reading state['api1_data'] and state['api2_data'].
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Code: Parallel Information Gathering
+ import { SequentialAgent, ParallelAgent, LlmAgent } from '@google/adk';
+
+ const fetchApi1 = new LlmAgent({name: 'API1Fetcher', instruction: 'Fetch data from API 1.', outputKey: 'api1_data'});
+ const fetchApi2 = new LlmAgent({name: 'API2Fetcher', instruction: 'Fetch data from API 2.', outputKey: 'api2_data'});
+
+ const gatherConcurrently = new ParallelAgent({
+ name: 'ConcurrentFetch',
+ subAgents: [fetchApi1, fetchApi2]
+ });
+
+ const synthesizer = new LlmAgent({
+ name: 'Synthesizer',
+ instruction: 'Combine results from {api1_data} and {api2_data}.'
+ });
+
+ const overallWorkflow = new SequentialAgent({
+ name: 'FetchAndSynthesize',
+ subAgents: [gatherConcurrently, synthesizer] // Run parallel fetch, then synthesize
+ });
+ // fetchApi1 and fetchApi2 run concurrently, saving to state.
+ // synthesizer runs afterwards, reading state['api1_data'] and state['api2_data'].
+ ```
+
=== "Go"
```go
@@ -996,32 +1021,6 @@ By combining ADK's composition primitives, you can implement various established
// synthesizer runs afterwards, reading state['api1_data'] and state['api2_data'].
```
-=== "Typescript"
-
- ```typescript
- // Conceptual Code: Parallel Information Gathering
- import { SequentialAgent, ParallelAgent, LlmAgent } from '@google/adk';
-
- const fetchApi1 = new LlmAgent({name: 'API1Fetcher', instruction: 'Fetch data from API 1.', outputKey: 'api1_data'});
- const fetchApi2 = new LlmAgent({name: 'API2Fetcher', instruction: 'Fetch data from API 2.', outputKey: 'api2_data'});
-
- const gatherConcurrently = new ParallelAgent({
- name: 'ConcurrentFetch',
- subAgents: [fetchApi1, fetchApi2]
- });
-
- const synthesizer = new LlmAgent({
- name: 'Synthesizer',
- instruction: 'Combine results from {api1_data} and {api2_data}.'
- });
-
- const overallWorkflow = new SequentialAgent({
- name: 'FetchAndSynthesize',
- subAgents: [gatherConcurrently, synthesizer] // Run parallel fetch, then synthesize
- });
- // fetchApi1 and fetchApi2 run concurrently, saving to state.
- // synthesizer runs afterwards, reading state['api1_data'] and state['api2_data'].
-
### Hierarchical Task Decomposition
* **Structure:** A multi-level tree of agents where higher-level agents break down complex goals and delegate sub-tasks to lower-level agents.
@@ -1036,11 +1035,11 @@ By combining ADK's composition primitives, you can implement various established
# Conceptual Code: Hierarchical Research Task
from google.adk.agents import LlmAgent
from google.adk.tools import agent_tool
-
+
# Low-level tool-like agents
web_searcher = LlmAgent(name="WebSearch", description="Performs web searches for facts.")
summarizer = LlmAgent(name="Summarizer", description="Summarizes text.")
-
+
# Mid-level agent combining tools
research_assistant = LlmAgent(
name="ResearchAssistant",
@@ -1048,7 +1047,7 @@ By combining ADK's composition primitives, you can implement various established
description="Finds and summarizes information on a topic.",
tools=[agent_tool.AgentTool(agent=web_searcher), agent_tool.AgentTool(agent=summarizer)]
)
-
+
# High-level agent delegating research
report_writer = LlmAgent(
name="ReportWriter",
@@ -1063,6 +1062,38 @@ By combining ADK's composition primitives, you can implement various established
# Results flow back up.
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Code: Hierarchical Research Task
+ import { LlmAgent, AgentTool } from '@google/adk';
+
+ // Low-level tool-like agents
+ const webSearcher = new LlmAgent({name: 'WebSearch', description: 'Performs web searches for facts.'});
+ const summarizer = new LlmAgent({name: 'Summarizer', description: 'Summarizes text.'});
+
+ // Mid-level agent combining tools
+ const researchAssistant = new LlmAgent({
+ name: 'ResearchAssistant',
+ model: 'gemini-2.5-flash',
+ description: 'Finds and summarizes information on a topic.',
+ tools: [new AgentTool({agent: webSearcher}), new AgentTool({agent: summarizer})]
+ });
+
+ // High-level agent delegating research
+ const reportWriter = new LlmAgent({
+ name: 'ReportWriter',
+ model: 'gemini-2.5-flash',
+ instruction: 'Write a report on topic X. Use the ResearchAssistant to gather information.',
+ tools: [new AgentTool({agent: researchAssistant})]
+ // Alternatively, could use LLM Transfer if researchAssistant is a subAgent
+ });
+ // User interacts with ReportWriter.
+ // ReportWriter calls ResearchAssistant tool.
+ // ResearchAssistant calls WebSearch and Summarizer tools.
+ // Results flow back up.
+ ```
+
=== "Go"
```go
@@ -1081,18 +1112,18 @@ By combining ADK's composition primitives, you can implement various established
// Conceptual Code: Hierarchical Research Task
import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.AgentTool;
-
+
// Low-level tool-like agents
LlmAgent webSearcher = LlmAgent.builder()
.name("WebSearch")
.description("Performs web searches for facts.")
.build();
-
+
LlmAgent summarizer = LlmAgent.builder()
.name("Summarizer")
.description("Summarizes text.")
.build();
-
+
// Mid-level agent combining tools
LlmAgent researchAssistant = LlmAgent.builder()
.name("ResearchAssistant")
@@ -1100,7 +1131,7 @@ By combining ADK's composition primitives, you can implement various established
.description("Finds and summarizes information on a topic.")
.tools(AgentTool.create(webSearcher), AgentTool.create(summarizer))
.build();
-
+
// High-level agent delegating research
LlmAgent reportWriter = LlmAgent.builder()
.name("ReportWriter")
@@ -1109,43 +1140,12 @@ By combining ADK's composition primitives, you can implement various established
.tools(AgentTool.create(researchAssistant))
// Alternatively, could use LLM Transfer if research_assistant is a subAgent
.build();
-
- // User interacts with ReportWriter.
- // ReportWriter calls ResearchAssistant tool.
- // ResearchAssistant calls WebSearch and Summarizer tools.
- // Results flow back up.
- ```
-
-=== "Typescript"
-
- ```typescript
- // Conceptual Code: Hierarchical Research Task
- import { LlmAgent, AgentTool } from '@google/adk';
-
- // Low-level tool-like agents
- const webSearcher = new LlmAgent({name: 'WebSearch', description: 'Performs web searches for facts.'});
- const summarizer = new LlmAgent({name: 'Summarizer', description: 'Summarizes text.'});
-
- // Mid-level agent combining tools
- const researchAssistant = new LlmAgent({
- name: 'ResearchAssistant',
- model: 'gemini-2.5-flash',
- description: 'Finds and summarizes information on a topic.',
- tools: [new AgentTool({agent: webSearcher}), new AgentTool({agent: summarizer})]
- });
- // High-level agent delegating research
- const reportWriter = new LlmAgent({
- name: 'ReportWriter',
- model: 'gemini-2.5-flash',
- instruction: 'Write a report on topic X. Use the ResearchAssistant to gather information.',
- tools: [new AgentTool({agent: researchAssistant})]
- // Alternatively, could use LLM Transfer if researchAssistant is a subAgent
- });
// User interacts with ReportWriter.
// ReportWriter calls ResearchAssistant tool.
// ResearchAssistant calls WebSearch and Summarizer tools.
// Results flow back up.
+ ```
### Review/Critique Pattern (Generator-Critic)
@@ -1160,21 +1160,21 @@ By combining ADK's composition primitives, you can implement various established
```python
# Conceptual Code: Generator-Critic
from google.adk.agents import SequentialAgent, LlmAgent
-
+
generator = LlmAgent(
name="DraftWriter",
instruction="Write a short paragraph about subject X.",
output_key="draft_text"
)
-
+
reviewer = LlmAgent(
name="FactChecker",
instruction="Review the text in {draft_text} for factual accuracy. Output 'valid' or 'invalid' with reasons.",
output_key="review_status"
)
-
+
# Optional: Further steps based on review_status
-
+
review_pipeline = SequentialAgent(
name="WriteAndReview",
sub_agents=[generator, reviewer]
@@ -1183,6 +1183,34 @@ By combining ADK's composition primitives, you can implement various established
# reviewer runs -> reads state['draft_text'], saves status to state['review_status']
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Code: Generator-Critic
+ import { SequentialAgent, LlmAgent } from '@google/adk';
+
+ const generator = new LlmAgent({
+ name: 'DraftWriter',
+ instruction: 'Write a short paragraph about subject X.',
+ outputKey: 'draft_text'
+ });
+
+ const reviewer = new LlmAgent({
+ name: 'FactChecker',
+ instruction: 'Review the text in {draft_text} for factual accuracy. Output "valid" or "invalid" with reasons.',
+ outputKey: 'review_status'
+ });
+
+ // Optional: Further steps based on review_status
+
+ const reviewPipeline = new SequentialAgent({
+ name: 'WriteAndReview',
+ subAgents: [generator, reviewer]
+ });
+ // generator runs -> saves draft to state['draft_text']
+ // reviewer runs -> reads state['draft_text'], saves status to state['review_status']
+ ```
+
=== "Go"
```go
@@ -1201,57 +1229,29 @@ By combining ADK's composition primitives, you can implement various established
// Conceptual Code: Generator-Critic
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.SequentialAgent;
-
+
LlmAgent generator = LlmAgent.builder()
.name("DraftWriter")
.instruction("Write a short paragraph about subject X.")
.outputKey("draft_text")
.build();
-
+
LlmAgent reviewer = LlmAgent.builder()
.name("FactChecker")
.instruction("Review the text in {draft_text} for factual accuracy. Output 'valid' or 'invalid' with reasons.")
.outputKey("review_status")
.build();
-
+
// Optional: Further steps based on review_status
-
+
SequentialAgent reviewPipeline = SequentialAgent.builder()
.name("WriteAndReview")
.subAgents(generator, reviewer)
.build();
-
- // generator runs -> saves draft to state['draft_text']
- // reviewer runs -> reads state['draft_text'], saves status to state['review_status']
- ```
-
-=== "Typescript"
-
- ```typescript
- // Conceptual Code: Generator-Critic
- import { SequentialAgent, LlmAgent } from '@google/adk';
-
- const generator = new LlmAgent({
- name: 'DraftWriter',
- instruction: 'Write a short paragraph about subject X.',
- outputKey: 'draft_text'
- });
-
- const reviewer = new LlmAgent({
- name: 'FactChecker',
- instruction: 'Review the text in {draft_text} for factual accuracy. Output "valid" or "invalid" with reasons.',
- outputKey: 'review_status'
- });
-
- // Optional: Further steps based on review_status
- const reviewPipeline = new SequentialAgent({
- name: 'WriteAndReview',
- subAgents: [generator, reviewer]
- });
// generator runs -> saves draft to state['draft_text']
// reviewer runs -> reads state['draft_text'], saves status to state['review_status']
-
+ ```
### Iterative Refinement Pattern
@@ -1270,28 +1270,28 @@ By combining ADK's composition primitives, you can implement various established
from google.adk.events import Event, EventActions
from google.adk.agents.invocation_context import InvocationContext
from typing import AsyncGenerator
-
+
# Agent to generate/refine code based on state['current_code'] and state['requirements']
code_refiner = LlmAgent(
name="CodeRefiner",
instruction="Read state['current_code'] (if exists) and state['requirements']. Generate/refine Python code to meet requirements. Save to state['current_code'].",
output_key="current_code" # Overwrites previous code in state
)
-
+
# Agent to check if the code meets quality standards
quality_checker = LlmAgent(
name="QualityChecker",
instruction="Evaluate the code in state['current_code'] against state['requirements']. Output 'pass' or 'fail'.",
output_key="quality_status"
)
-
+
# Custom agent to check the status and escalate if 'pass'
class CheckStatusAndEscalate(BaseAgent):
async def _run_async_impl(self, ctx: InvocationContext) -> AsyncGenerator[Event, None]:
status = ctx.session.state.get("quality_status", "fail")
should_stop = (status == "pass")
yield Event(author=self.name, actions=EventActions(escalate=should_stop))
-
+
refinement_loop = LoopAgent(
name="CodeRefinementLoop",
max_iterations=5,
@@ -1302,6 +1302,56 @@ By combining ADK's composition primitives, you can implement various established
# Loop stops if QualityChecker outputs 'pass' (leading to StopChecker escalating) or after 5 iterations.
```
+=== "Typescript"
+
+ ```typescript
+ // Conceptual Code: Iterative Code Refinement
+ import { LoopAgent, LlmAgent, BaseAgent, InvocationContext } from '@google/adk';
+ import type { Event, createEvent, createEventActions } from '@google/genai';
+
+ // Agent to generate/refine code based on state['current_code'] and state['requirements']
+ const codeRefiner = new LlmAgent({
+ name: 'CodeRefiner',
+ instruction: 'Read state["current_code"] (if exists) and state["requirements"]. Generate/refine Typescript code to meet requirements. Save to state["current_code"].',
+ outputKey: 'current_code' // Overwrites previous code in state
+ });
+
+ // Agent to check if the code meets quality standards
+ const qualityChecker = new LlmAgent({
+ name: 'QualityChecker',
+ instruction: 'Evaluate the code in state["current_code"] against state["requirements"]. Output "pass" or "fail".',
+ outputKey: 'quality_status'
+ });
+
+ // Custom agent to check the status and escalate if 'pass'
+ class CheckStatusAndEscalate extends BaseAgent {
+ async *runAsyncImpl(ctx: InvocationContext): AsyncGenerator {
+ const status = ctx.session.state.quality_status;
+ const shouldStop = status === 'pass';
+ if (shouldStop) {
+ yield createEvent({
+ author: 'StopChecker',
+ actions: createEventActions(),
+ });
+ }
+ }
+
+ async *runLiveImpl(ctx: InvocationContext): AsyncGenerator {
+ // This agent doesn't have a live implementation
+ yield createEvent({ author: 'StopChecker' });
+ }
+ }
+
+ // Loop runs: Refiner -> Checker -> StopChecker
+ // State['current_code'] is updated each iteration.
+ // Loop stops if QualityChecker outputs 'pass' (leading to StopChecker escalating) or after 5 iterations.
+ const refinementLoop = new LoopAgent({
+ name: 'CodeRefinementLoop',
+ maxIterations: 5,
+ subAgents: [codeRefiner, qualityChecker, new CheckStatusAndEscalate({name: 'StopChecker'})]
+ });
+ ```
+
=== "Go"
```go
@@ -1328,29 +1378,29 @@ By combining ADK's composition primitives, you can implement various established
import com.google.adk.agents.InvocationContext;
import io.reactivex.rxjava3.core.Flowable;
import java.util.List;
-
+
// Agent to generate/refine code based on state['current_code'] and state['requirements']
LlmAgent codeRefiner = LlmAgent.builder()
.name("CodeRefiner")
.instruction("Read state['current_code'] (if exists) and state['requirements']. Generate/refine Java code to meet requirements. Save to state['current_code'].")
.outputKey("current_code") // Overwrites previous code in state
.build();
-
+
// Agent to check if the code meets quality standards
LlmAgent qualityChecker = LlmAgent.builder()
.name("QualityChecker")
.instruction("Evaluate the code in state['current_code'] against state['requirements']. Output 'pass' or 'fail'.")
.outputKey("quality_status")
.build();
-
+
BaseAgent checkStatusAndEscalate = new BaseAgent(
"StopChecker","Checks quality_status and escalates if 'pass'.", List.of(), null, null) {
-
+
@Override
protected Flowable runAsyncImpl(InvocationContext invocationContext) {
String status = (String) invocationContext.session().state().getOrDefault("quality_status", "fail");
boolean shouldStop = "pass".equals(status);
-
+
EventActions actions = EventActions.builder().escalate(shouldStop).build();
Event event = Event.builder()
.author(this.name())
@@ -1359,68 +1409,19 @@ By combining ADK's composition primitives, you can implement various established
return Flowable.just(event);
}
};
-
+
LoopAgent refinementLoop = LoopAgent.builder()
.name("CodeRefinementLoop")
.maxIterations(5)
.subAgents(codeRefiner, qualityChecker, checkStatusAndEscalate)
.build();
-
+
// Loop runs: Refiner -> Checker -> StopChecker
// State['current_code'] is updated each iteration.
// Loop stops if QualityChecker outputs 'pass' (leading to StopChecker escalating) or after 5
// iterations.
```
-=== "Typescript"
-
- ```typescript
- // Conceptual Code: Iterative Code Refinement
- import { LoopAgent, LlmAgent, BaseAgent, InvocationContext } from '@google/adk';
- import type { Event, createEvent, createEventActions } from '@google/genai';
-
- // Agent to generate/refine code based on state['current_code'] and state['requirements']
- const codeRefiner = new LlmAgent({
- name: 'CodeRefiner',
- instruction: 'Read state["current_code"] (if exists) and state["requirements"]. Generate/refine Typescript code to meet requirements. Save to state["current_code"].',
- outputKey: 'current_code' // Overwrites previous code in state
- });
-
- // Agent to check if the code meets quality standards
- const qualityChecker = new LlmAgent({
- name: 'QualityChecker',
- instruction: 'Evaluate the code in state["current_code"] against state["requirements"]. Output "pass" or "fail".',
- outputKey: 'quality_status'
- });
-
- // Custom agent to check the status and escalate if 'pass'
- class CheckStatusAndEscalate extends BaseAgent {
- async *runAsyncImpl(ctx: InvocationContext): AsyncGenerator {
- const status = ctx.session.state.quality_status;
- const shouldStop = status === 'pass';
- if (shouldStop) {
- yield createEvent({
- author: 'StopChecker',
- actions: createEventActions(),
- });
- }
- }
-
- async *runLiveImpl(ctx: InvocationContext): AsyncGenerator {
- // This agent doesn't have a live implementation
- yield createEvent({ author: 'StopChecker' });
- }
- }
-
- // Loop runs: Refiner -> Checker -> StopChecker
- // State['current_code'] is updated each iteration.
- // Loop stops if QualityChecker outputs 'pass' (leading to StopChecker escalating) or after 5 iterations.
- const refinementLoop = new LoopAgent({
- name: 'CodeRefinementLoop',
- maxIterations: 5,
- subAgents: [codeRefiner, qualityChecker, new CheckStatusAndEscalate({name: 'StopChecker'})]
- });
-
### Human-in-the-Loop Pattern
* **Structure:** Integrates human intervention points within an agent workflow.
@@ -1437,7 +1438,7 @@ By combining ADK's composition primitives, you can implement various established
# Conceptual Code: Using a Tool for Human Approval
from google.adk.agents import LlmAgent, SequentialAgent
from google.adk.tools import FunctionTool
-
+
# --- Assume external_approval_tool exists ---
# This tool would:
# 1. Take details (e.g., request_id, amount, reason).
@@ -1446,14 +1447,14 @@ By combining ADK's composition primitives, you can implement various established
# 4. Return the human's decision.
# async def external_approval_tool(amount: float, reason: str) -> str: ...
approval_tool = FunctionTool(func=external_approval_tool)
-
+
# Agent that prepares the request
prepare_request = LlmAgent(
name="PrepareApproval",
instruction="Prepare the approval request details based on user input. Store amount and reason in state.",
# ... likely sets state['approval_amount'] and state['approval_reason'] ...
)
-
+
# Agent that calls the human approval tool
request_approval = LlmAgent(
name="RequestHumanApproval",
@@ -1461,76 +1462,19 @@ By combining ADK's composition primitives, you can implement various established
tools=[approval_tool],
output_key="human_decision"
)
-
+
# Agent that proceeds based on human decision
process_decision = LlmAgent(
name="ProcessDecision",
instruction="Check {human_decision}. If 'approved', proceed. If 'rejected', inform user."
)
-
+
approval_workflow = SequentialAgent(
name="HumanApprovalWorkflow",
sub_agents=[prepare_request, request_approval, process_decision]
)
```
-=== "Java"
-
- ```java
- // Conceptual Code: Using a Tool for Human Approval
- import com.google.adk.agents.LlmAgent;
- import com.google.adk.agents.SequentialAgent;
- import com.google.adk.tools.FunctionTool;
-
- // --- Assume external_approval_tool exists ---
- // This tool would:
- // 1. Take details (e.g., request_id, amount, reason).
- // 2. Send these details to a human review system (e.g., via API).
- // 3. Poll or wait for the human response (approved/rejected).
- // 4. Return the human's decision.
- // public boolean externalApprovalTool(float amount, String reason) { ... }
- FunctionTool approvalTool = FunctionTool.create(externalApprovalTool);
-
- // Agent that prepares the request
- LlmAgent prepareRequest = LlmAgent.builder()
- .name("PrepareApproval")
- .instruction("Prepare the approval request details based on user input. Store amount and reason in state.")
- // ... likely sets state['approval_amount'] and state['approval_reason'] ...
- .build();
-
- // Agent that calls the human approval tool
- LlmAgent requestApproval = LlmAgent.builder()
- .name("RequestHumanApproval")
- .instruction("Use the external_approval_tool with amount from state['approval_amount'] and reason from state['approval_reason'].")
- .tools(approvalTool)
- .outputKey("human_decision")
- .build();
-
- // Agent that proceeds based on human decision
- LlmAgent processDecision = LlmAgent.builder()
- .name("ProcessDecision")
- .instruction("Check {human_decision}. If 'approved', proceed. If 'rejected', inform user.")
- .build();
-
- SequentialAgent approvalWorkflow = SequentialAgent.builder()
- .name("HumanApprovalWorkflow")
- .subAgents(prepareRequest, requestApproval, processDecision)
- .build();
- ```
-
-=== "Go"
-
- ```go
- import (
- "google.golang.org/adk/agent"
- "google.golang.org/adk/agent/llmagent"
- "google.golang.org/adk/agent/workflowagents/sequentialagent"
- "google.golang.org/adk/tool"
- )
-
- --8<-- "examples/go/snippets/agents/multi-agent/main.go:human-in-loop-pattern"
- ```
-
=== "Typescript"
```typescript
@@ -1587,6 +1531,63 @@ By combining ADK's composition primitives, you can implement various established
});
```
+=== "Go"
+
+ ```go
+ import (
+ "google.golang.org/adk/agent"
+ "google.golang.org/adk/agent/llmagent"
+ "google.golang.org/adk/agent/workflowagents/sequentialagent"
+ "google.golang.org/adk/tool"
+ )
+
+ --8<-- "examples/go/snippets/agents/multi-agent/main.go:human-in-loop-pattern"
+ ```
+
+=== "Java"
+
+ ```java
+ // Conceptual Code: Using a Tool for Human Approval
+ import com.google.adk.agents.LlmAgent;
+ import com.google.adk.agents.SequentialAgent;
+ import com.google.adk.tools.FunctionTool;
+
+ // --- Assume external_approval_tool exists ---
+ // This tool would:
+ // 1. Take details (e.g., request_id, amount, reason).
+ // 2. Send these details to a human review system (e.g., via API).
+ // 3. Poll or wait for the human response (approved/rejected).
+ // 4. Return the human's decision.
+ // public boolean externalApprovalTool(float amount, String reason) { ... }
+ FunctionTool approvalTool = FunctionTool.create(externalApprovalTool);
+
+ // Agent that prepares the request
+ LlmAgent prepareRequest = LlmAgent.builder()
+ .name("PrepareApproval")
+ .instruction("Prepare the approval request details based on user input. Store amount and reason in state.")
+ // ... likely sets state['approval_amount'] and state['approval_reason'] ...
+ .build();
+
+ // Agent that calls the human approval tool
+ LlmAgent requestApproval = LlmAgent.builder()
+ .name("RequestHumanApproval")
+ .instruction("Use the external_approval_tool with amount from state['approval_amount'] and reason from state['approval_reason'].")
+ .tools(approvalTool)
+ .outputKey("human_decision")
+ .build();
+
+ // Agent that proceeds based on human decision
+ LlmAgent processDecision = LlmAgent.builder()
+ .name("ProcessDecision")
+ .instruction("Check {human_decision}. If 'approved', proceed. If 'rejected', inform user.")
+ .build();
+
+ SequentialAgent approvalWorkflow = SequentialAgent.builder()
+ .name("HumanApprovalWorkflow")
+ .subAgents(prepareRequest, requestApproval, processDecision)
+ .build();
+ ```
+
#### Human in the Loop with Policy
A more advanced and structured way to implement Human-in-the-Loop is by using a `PolicyEngine`. This approach allows you to define policies that can trigger a confirmation step from a user before a tool is executed. The `SecurityPlugin` intercepts a tool call, consults the `PolicyEngine`, and if the policy dictates, it will automatically request user confirmation. This pattern is more robust for enforcing governance and security rules.
@@ -1606,7 +1607,7 @@ A conceptual example of using a `CustomPolicyEngine` to require user confirmatio
=== "TypeScript"
- ```typescript
+ ```typescript
const rootAgent = new LlmAgent({
name: 'weather_time_agent',
model: 'gemini-2.5-flash',
@@ -1616,7 +1617,7 @@ A conceptual example of using a `CustomPolicyEngine` to require user confirmatio
'You are a helpful agent who can answer user questions about the time and weather in a city.',
tools: [getWeatherTool],
});
-
+
class CustomPolicyEngine implements BasePolicyEngine {
async evaluate(_context: ToolCallPolicyContext): Promise {
// Default permissive implementation
@@ -1631,12 +1632,11 @@ A conceptual example of using a `CustomPolicyEngine` to require user confirmatio
agent: rootAgent,
appName,
plugins: [new SecurityPlugin({policyEngine: new CustomPolicyEngine()})]
- });
+ });
```
-You can find the full code sample [here](../../examples/typescript/snippets/agents/workflow-agents/hitl_confirmation_agent.ts).
+ You can find the full code sample [here](../../examples/typescript/snippets/agents/workflow-agents/hitl_confirmation_agent.ts).
### Combining Patterns
These patterns provide starting points for structuring your multi-agent systems. You can mix and match them as needed to create the most effective architecture for your specific application.
-
diff --git a/docs/agents/workflow-agents/index.md b/docs/agents/workflow-agents/index.md
index ea32a762d..6ba7420ef 100644
--- a/docs/agents/workflow-agents/index.md
+++ b/docs/agents/workflow-agents/index.md
@@ -1,10 +1,10 @@
# Workflow Agents
- Supported in ADKPythonGoJava
+ Supported in ADKPythonTypeScriptGoJava
-This section introduces "*workflow agents*" - **specialized agents that control the execution flow of its sub-agents**.
+This section introduces "*workflow agents*" - **specialized agents that control the execution flow of its sub-agents**.
Workflow agents are specialized components in ADK designed purely for **orchestrating the execution flow of sub-agents**. Their primary role is to manage *how* and *when* other agents run, defining the control flow of a process.
diff --git a/docs/agents/workflow-agents/loop-agents.md b/docs/agents/workflow-agents/loop-agents.md
index c4e1aa3ea..69696f480 100644
--- a/docs/agents/workflow-agents/loop-agents.md
+++ b/docs/agents/workflow-agents/loop-agents.md
@@ -1,7 +1,7 @@
# Loop agents
- Supported in ADKPython v0.1.0Go v0.1.0Java v0.2.0
+ Supported in ADKPython v0.1.0TypeScript v0.1.0Go v0.1.0Java v0.2.0
The `LoopAgent` is a workflow agent that executes its sub-agents in a loop (i.e. iteratively). It **_repeatedly runs_ a sequence of agents** for a specified number of iterations or until a termination condition is met.
@@ -48,6 +48,11 @@ In this setup, the `LoopAgent` would manage the iterative process. The `CriticA
--8<-- "examples/python/snippets/agents/workflow-agents/loop_agent_doc_improv_agent.py:init"
```
+ === "Typescript"
+ ```typescript
+ --8<-- "examples/typescript/snippets/agents/workflow/loop_agent_doc_improv_agent.ts:init"
+ ```
+
=== "Go"
```go
--8<-- "examples/go/snippets/agents/workflow-agents/loop/main.go:init"
@@ -57,8 +62,3 @@ In this setup, the `LoopAgent` would manage the iterative process. The `CriticA
```java
--8<-- "examples/java/snippets/src/main/java/agents/workflow/LoopAgentExample.java:init"
```
-
- === "Typescript"
- ```typescript
- --8<-- "examples/typescript/snippets/agents/workflow/loop_agent_doc_improv_agent.ts:init"
- ```
diff --git a/docs/agents/workflow-agents/parallel-agents.md b/docs/agents/workflow-agents/parallel-agents.md
index 426d69590..edb501f04 100644
--- a/docs/agents/workflow-agents/parallel-agents.md
+++ b/docs/agents/workflow-agents/parallel-agents.md
@@ -1,7 +1,7 @@
# Parallel agents
- Supported in ADKPython v0.1.0Go v0.1.0Java v0.2.0
+ Supported in ADKPython v0.1.0TypeScript v0.1.0Go v0.1.0Java v0.2.0
The `ParallelAgent` is a [workflow agent](index.md) that executes its sub-agents *concurrently*. This dramatically speeds up workflows where tasks can be performed independently.
@@ -53,6 +53,11 @@ These research tasks are independent. Using a `ParallelAgent` allows them to ru
--8<-- "examples/python/snippets/agents/workflow-agents/parallel_agent_web_research.py:init"
```
+ === "Typescript"
+ ```typescript
+ --8<-- "examples/typescript/snippets/agents/workflow-agents/parallel_agent_web_research.ts:init"
+ ```
+
=== "Go"
```go
--8<-- "examples/go/snippets/agents/workflow-agents/parallel/main.go:init"
@@ -62,7 +67,3 @@ These research tasks are independent. Using a `ParallelAgent` allows them to ru
```java
--8<-- "examples/java/snippets/src/main/java/agents/workflow/ParallelResearchPipeline.java:full_code"
```
- === "Typescript"
- ```typescript
- --8<-- "examples/typescript/snippets/agents/workflow-agents/parallel_agent_web_research.ts:init"
- ```
\ No newline at end of file
diff --git a/docs/agents/workflow-agents/sequential-agents.md b/docs/agents/workflow-agents/sequential-agents.md
index c1cc4a390..1fef381cb 100644
--- a/docs/agents/workflow-agents/sequential-agents.md
+++ b/docs/agents/workflow-agents/sequential-agents.md
@@ -1,7 +1,7 @@
# Sequential agents
- Supported in ADKPython v0.1.0Go v0.1.0Java v0.2.0
+ Supported in ADKPython v0.1.0TypeScript v0.1.0Go v0.1.0Java v0.2.0
The `SequentialAgent` is a [workflow agent](index.md) that executes its sub-agents in the order they are specified in the list.
@@ -48,6 +48,11 @@ This ensures the code is written, *then* reviewed, and *finally* refactored, in
--8<-- "examples/python/snippets/agents/workflow-agents/sequential_agent_code_development_agent.py:init"
```
+ === "Typescript"
+ ```typescript
+ --8<-- "examples/typescript/snippets/agents/workflow/sequential_agent_code_development_agent.ts:init"
+ ```
+
=== "Go"
```go
--8<-- "examples/go/snippets/agents/workflow-agents/sequential/main.go:init"
@@ -57,8 +62,3 @@ This ensures the code is written, *then* reviewed, and *finally* refactored, in
```java
--8<-- "examples/java/snippets/src/main/java/agents/workflow/SequentialAgentExample.java:init"
```
-
- === "Typescript"
- ```typescript
- --8<-- "examples/typescript/snippets/agents/workflow/sequential_agent_code_development_agent.ts:init"
- ```
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index e76defb44..6a9be39d3 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -50,6 +50,12 @@ from simple tasks to complex workflows.
pip install google-adk
+=== "TypeScript"
+
+
+ npm install @google/adk
+
+
=== "Go"
@@ -72,17 +78,11 @@ from simple tasks to complex workflows.
}
```
-=== "TypeScript"
-
-
- npm install @google/adk
-
-