Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/agents/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ To setup ADK for use with Agent Config:
1. Install the ADK Python libraries by following the
[Installation](/adk-docs/get-started/installation/#python)
instructions. *Python is currently required.* For more information, see the
[Known limitations](?tab=t.0#heading=h.xefmlyt7zh0i).
[Known limitations](#known-limitations).
1. Verify that ADK is installed by running the following command in your
terminal:

Expand Down
141 changes: 19 additions & 122 deletions docs/agents/multi-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,20 @@ The foundation for structuring multi-agent systems is the parent-child relations

* **Establishing Hierarchy:** You create a tree structure by passing a list of agent instances to the `sub_agents` argument when initializing a parent agent. ADK automatically sets the `parent_agent` attribute on each child agent during initialization.
* **Single Parent Rule:** An agent instance can only be added as a sub-agent once. Attempting to assign a second parent will result in a `ValueError`.
* **Importance:** This hierarchy defines the scope for [Workflow Agents](#12-workflow-agents-as-orchestrators) and influences the potential targets for LLM-Driven Delegation. You can navigate the hierarchy using `agent.parent_agent` or find descendants using `agent.find_agent(name)`.
* **Importance:** This hierarchy defines the scope for [Workflow Agents](#workflow-agents-as-orchestrators) and influences the potential targets for LLM-Driven Delegation. You can navigate the hierarchy using `agent.parent_agent` or find descendants using `agent.find_agent(name)`.

=== "Python"

```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",
Expand All @@ -52,6 +54,7 @@ The foundation for structuring multi-agent systems is the parent-child relations
]
)


# Framework automatically sets:
# assert greeter.parent_agent == coordinator
# assert task_doer.parent_agent == coordinator
Expand Down Expand Up @@ -118,10 +121,12 @@ The foundation for structuring multi-agent systems is the parent-child relations
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")
Expand All @@ -130,6 +135,7 @@ The foundation for structuring multi-agent systems is the parent-child relations
.subAgents(greeter, taskDoer) // Assign sub_agents here
.build();


// Framework automatically sets:
// assert greeter.parentAgent().equals(coordinator);
// assert taskDoer.parentAgent().equals(coordinator);
Expand Down Expand Up @@ -211,33 +217,7 @@ 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
import (
"google.golang.org/adk/agent"
"google.golang.org/adk/agent/llmagent"
"google.golang.org/adk/agent/workflowagents/parallelagent"
)

--8<-- "examples/go/snippets/agents/multi-agent/main.go:parallel-execution"
```


=== "Java"

```java
Expand Down Expand Up @@ -293,52 +273,7 @@ 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<Event> {
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<Event> {
// 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
Expand Down Expand Up @@ -1588,55 +1523,17 @@ By combining ADK's composition primitives, you can implement various established
.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.

Here's how it works:

1. **`SecurityPlugin`**: You add this plugin to your `Runner`. It acts as an interceptor for all tool calls.
2. **`BasePolicyEngine`**: You create a custom class that implements this interface. Its `evaluate()` method contains your logic to decide if a tool call needs confirmation.
3. **`PolicyOutcome.CONFIRM`**: When your `evaluate()` method returns this outcome, the `SecurityPlugin` pauses the tool execution and generates a special `FunctionCall` using `getAskUserConfirmationFunctionCalls`.
4. **Application Handling**: Your application code receives this special function call and presents the confirmation request to the user.
5. **User Confirmation**: Once the user confirms, your application sends a `FunctionResponse` back to the agent, which allows the `SecurityPlugin` to proceed with the original tool execution.

!!! Note "TypeScript Recommended Pattern"
The Policy-based pattern is the recommended approach for implementing Human-in-the-Loop workflows in TypeScript. Support in other ADK languages is planned for future releases.

A conceptual example of using a `CustomPolicyEngine` to require user confirmation before executing any tool is shown below.

=== "TypeScript"

```typescript
const rootAgent = new LlmAgent({
name: 'weather_time_agent',
model: 'gemini-2.5-flash',
description:
'Agent to answer questions about the time and weather in a city.',
instruction:
'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<PolicyCheckResult> {
// Default permissive implementation
return Promise.resolve({
outcome: PolicyOutcome.CONFIRM,
reason: 'Needs confirmation for tool call',
});
}
}
=== "Go"

const runner = new InMemoryRunner({
agent: rootAgent,
appName,
plugins: [new SecurityPlugin({policyEngine: new CustomPolicyEngine()})]
});
```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"
```

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.
Loading
Loading