You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 873973e
Browse filesBrowse the repository at this point in the historyBrowse files
@@ -46,7 +48,8 @@ The inner workflow receives the predecessor's output as its START input and its
46
48
47
49
Schedule nodes at runtime using `ctx.run_node()`.
48
50
49
-
See the dedicated [Dynamic Node Scheduling Reference](file:///Users/deanchen/Desktop/adk-workflow/.agents/skills/adk-workflow/references/dynamic-nodes.md) for detailed rules, examples, and best practices.
51
+
See the dedicated [Dynamic Node Scheduling Reference](dynamic-nodes.md) for
52
+
detailed rules, examples, and best practices.
50
53
51
54
## Retry Configuration
52
55
@@ -80,12 +83,13 @@ delay = min(delay, max_delay)
80
83
delay = delay * (1 + random(0, jitter))
81
84
```
82
85
83
-
### Accessing retry count
86
+
### Accessing the attempt count
84
87
85
88
```python
86
89
defmy_node(ctx: Context, node_input: str) -> str:
87
-
if ctx.retry_count >0:
88
-
print(f"Retry attempt {ctx.retry_count}")
90
+
# attempt_count is 1 on the first try, ≥2 on retries
91
+
if ctx.attempt_count >1:
92
+
print(f"Retry attempt {ctx.attempt_count}")
89
93
return"result"
90
94
```
91
95
@@ -167,6 +171,7 @@ class CollectorNode(BaseNode):
167
171
```
168
172
169
173
Nodes with `wait_for_output=True` default:
174
+
170
175
-`JoinNode`: `True` (waits for all predecessors)
171
176
-`LlmAgentWrapper` (task mode): `True` (set in `model_post_init`)
Copy file name to clipboardExpand all lines: .agents/skills/adk-agent-builder/references/getting-started.md
+5-3Lines changed: 5 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,12 +4,14 @@ Step-by-step guide covering environment setup, basic LLM agents, and workflow ag
4
4
5
5
## 📋 New Agent Checklist
6
6
Use this checklist when creating a new agent to ensure it follows convention:
7
+
7
8
-[ ]**Directory**: Is there a directory for the agent?
8
9
-[ ]**__init__.py**: Does it contain `from . import agent`?
9
10
-[ ]**agent.py**: Does it define `root_agent` or `app`?
10
11
-[ ]**.env**: Is there a `.env` file with the appropriate API keys? (Do not commit to git)
11
12
12
13
## 💡 Quick Reference (CLI Commands)
14
+
13
15
-**Create**: `adk create <agent_name>` (Scaffolds a new agent project)
14
16
-**Web UI**: `adk web <path_to_agent_dir>` (Starts dev server at localhost:8000)
15
17
-**Run CLI**: `adk run <path_to_agent_dir>` (Interactive or query mode)
@@ -44,7 +46,7 @@ Obtain an API key from [Google AI Studio](https://aistudio.google.com/app/apikey
44
46
Create a `.env` file in the agent directory:
45
47
46
48
```
47
-
GOOGLE_GENAI_USE_VERTEXAI=FALSE
49
+
GOOGLE_GENAI_USE_ENTERPRISE=FALSE
48
50
GOOGLE_API_KEY=YOUR_API_KEY
49
51
```
50
52
@@ -53,7 +55,7 @@ GOOGLE_API_KEY=YOUR_API_KEY
53
55
For production use with Google Cloud:
54
56
55
57
```
56
-
GOOGLE_GENAI_USE_VERTEXAI=TRUE
58
+
GOOGLE_GENAI_USE_ENTERPRISE=TRUE
57
59
GOOGLE_CLOUD_PROJECT=your-project-id
58
60
GOOGLE_CLOUD_LOCATION=us-central1
59
61
```
@@ -65,7 +67,7 @@ Run `gcloud auth application-default login` to authenticate.
Copy file name to clipboardExpand all lines: .agents/skills/adk-agent-builder/references/llm-agent-nodes.md
+29-21Lines changed: 29 additions & 21 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,12 +4,14 @@ Embed LLM-powered agents as nodes in workflow graphs.
4
4
5
5
## 📋 Agent Verification Checklist (LLM Nodes)
6
6
Use this checklist to verify your LLM agent configuration:
7
+
7
8
-[ ]**Output Type**: If no `output_schema` is set, downstream now receives `str` (auto-extracted from `types.Content`). You can safely type-hint `node_input: str`.
8
9
-[ ]**State Serialization**: If this agent feeds into a `JoinNode`, did you set `output_schema` to avoid non-serializable `types.Content` errors?
9
10
-[ ]**Instructions**: Are `{var}` templates used in instructions resolving ONLY from `ctx.state`? (Not `node_input`)
10
11
-[ ]**Config**: Are instructions, tools, and response schema set on the `LlmAgent` directly, and NOT in `generate_content_config`?
11
12
12
13
## 💡 Quick Reference
14
+
13
15
-**Chat Mode**: Default. Multi-turn, keeps session history.
14
16
-**Single-Turn Mode**: Isolated. Set `mode="single_turn"` or rely on auto-wrapping defaults.
15
17
-**Task Mode**: Multi-turn within a task. Set `mode="task"`.
@@ -70,25 +72,25 @@ agent = Workflow(
70
72
)
71
73
```
72
74
73
-
## LLM Agent Output Types (Critical)
75
+
## LLM Agent Output Types
74
76
75
-
**LlmAgentWrapper auto-extracts text and outputs `str` when no `output_schema` is set.** Previously, it outputted `types.Content` causing type errors. Now, if you type-hint `node_input: str`, it will work correctly for standard text output.
77
+
When an `LlmAgent` runs as a workflow node, `process_llm_agent_output` (in
78
+
`_llm_agent_wrapper.py`) sets `event.output` to:
76
79
77
-
**Solutions (pick one):**
80
+
- The **concatenated text** of the model's response (a `str`) — when
81
+
`output_schema` is not set.
82
+
- The **validated dict** (`model_dump()` of the Pydantic model) — when
83
+
`output_schema=MyModel` is set.
78
84
79
-
1.**Use `Any` and extract text** (recommended for function nodes after LLM agents):
85
+
A downstream function node typed `node_input: str` therefore works in the
86
+
default case, and `node_input: dict` works when `output_schema` is set.
80
87
81
-
```python
82
-
from typing import Any
83
-
from google.genai import types
84
-
85
-
defprocess_llm_output(node_input: Any) -> str:
86
-
ifisinstance(node_input, types.Content):
87
-
return''.join(p.text for p in (node_input.parts or []) if p.text)
88
-
returnstr(node_input) if node_input isnotNoneelse''
89
-
```
90
-
91
-
2.**Use `output_schema`** on the LLM agent to get a parsed `dict` instead:
88
+
**Observability caveat:** the value above is set on the event internally and
89
+
forwarded to the next node, but `event.output` is **`None`** when you observe it
90
+
from `runner.run_async(...)` for the LLM agent's own event — the framework
91
+
clears it before the event reaches user code. Don't write tests that assert on
92
+
`event.output` for an LLM agent's event; assert on the downstream node's output,
93
+
on `session.state[output_key]`, or on `event.content.parts[*].text` instead.
No `output_schema`| `str` (concatenated model text)
119
+
With `output_schema` | `dict` (parsed from Pydantic model)
118
120
119
-
**State serialization warning:** When LLM agents feed into a `JoinNode`, the JoinNode stores intermediate results in session state. Without `output_schema`, this stores `types.Content` objects which are **not JSON-serializable** and will cause `TypeError` with SQLite/database session services. Always use `output_schema` on LLM agents that feed into a JoinNode.
121
+
**Prefer `output_schema` when downstream nodes need structured access.** Strings
122
+
are fine for pass-through text, but a typed dict is easier to consume and is
123
+
required when the predecessor feeds a `JoinNode` whose results land in a
124
+
persistent session service (raw text is fine; objects that aren't
Use this checklist when implementing parallel patterns:
7
+
7
8
-[ ]**JoinNode Serialization**: If LLM agents feed into a `JoinNode`, did you set `output_schema` on them to prevent JSON serialization errors?
8
9
-[ ]**ParallelWorker Usage**: Did you avoid using `parallel_worker=True` on fan-out nodes? (It expects a list input)
9
10
-[ ]**Multi-Trigger vs Join**: Do you understand that Multi-Trigger fires downstream once per branch, while JoinNode waits and fires once with merged dict?
**Serialization warning:** JoinNode stores partial inputs in session state while waiting. If predecessors are LLM agents without `output_schema`, the stored values are `types.Content` objects which are **not JSON-serializable**. This causes `TypeError` with SQLite/database session services. Fix: use `output_schema` on LLM agents feeding into a JoinNode.
93
96
94
-
## ParallelWorker: Process Lists in Parallel
97
+
## Parallel workers: process lists in parallel
95
98
96
-
Apply the same node to each item in a list concurrently:
99
+
Apply the same node to each item in a list concurrently by setting the
100
+
`parallel_worker=True` flag. The framework wraps the node internally — there is
101
+
no public `ParallelWorker` class to import.
97
102
98
103
```python
104
+
from google.adk.workflow import node, Workflow
105
+
106
+
@node(parallel_worker=True)
99
107
defprocess_item(node_input: int) -> int:
100
108
return node_input *2
101
109
102
-
parallel = ParallelWorker(node(process_item))
103
-
104
110
defproduce_list(node_input: str) -> list:
105
111
return [1, 2, 3, 4, 5]
106
112
107
113
agent = Workflow(
108
114
name="parallel_processing",
109
115
edges=[
110
116
('START', produce_list),
111
-
(produce_list, parallel),
117
+
(produce_list, process_item),
112
118
],
113
119
)
114
120
# Output: [2, 4, 6, 8, 10]
115
121
```
116
122
117
-
### ParallelWorker Details
123
+
### Behavior
118
124
119
125
- Input: a **list** (or single item, which gets wrapped in a list)
120
126
- Output: a **list** of results in the same order as inputs
121
127
- Empty list input produces empty list output
122
128
- Each item is processed by a dynamically created worker node
123
-
- Workers are named `{parent_name}__{index}` (e.g., `process_item__0`)
124
129
- Default `rerun_on_resume=True`
125
130
126
-
### ParallelWorker with @node Decorator
127
-
128
-
```python
129
-
@node(parallel_worker=True)
130
-
defprocess_item(node_input: int) -> int:
131
-
return node_input *2
132
-
133
-
# Equivalent to: ParallelWorker(FunctionNode(process_item_fn))
134
-
```
135
-
136
-
### ParallelWorker with Agents
131
+
### Parallel workers with Agents
137
132
138
-
Set `parallel_worker=True` directly on an Agent:
133
+
Set `parallel_worker=True` directly on an Agent — no extra wrapping needed:
139
134
140
135
```python
141
136
from google.adk import Agent
@@ -155,12 +150,6 @@ agent = Workflow(
155
150
)
156
151
```
157
152
158
-
Or wrap manually:
159
-
160
-
```python
161
-
parallel_analyzer = ParallelWorker(analyzer)
162
-
```
163
-
164
153
**Do NOT use `parallel_worker=True` on fan-out nodes.** Fan-out edges `(a, (b, c, d))` already run nodes in parallel. Adding `parallel_worker=True` makes the node expect a list input and iterate over it — if it receives a single value or None, it produces no output and the JoinNode gets nothing.
0 commit comments