adk-go
Reflects `google.golang.org/adk/v2 v2.1.0`, the version the `adk_go` template pins. If a symbol here is missing, check your `go.mod` before assuming the page…
Requires `google.golang.org/adk/v2 >= v2.0.0`, which is where the `workflow` package and `agent/workflowagent` first ship.
$ npx -y skills add google/agents-cli --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
Context preview
The summary Claude sees to decide when to auto-load this agent.
Requires `google.golang.org/adk/v2 >= v2.0.0`, which is where the `workflow` package and `agent/workflowagent` first ship.
> Requires `google.golang.org/adk/v2 >= v2.0.0`, which is where the `workflow` package and > `agent/workflowagent` first ship.
The graph runtime in **`google.golang.org/adk/v2/workflow`**, for the cases the linear `sequentialagent` / `parallelagent` / `loopagent` composition in `adk-go.md` cannot express: conditional routing, fan-out with a fan-in barrier, per-node retries or timeouts, or a workflow that pauses for human input and resumes later. For a plain chain of agents, those workflow *agents* are simpler.
Read `adk-go.md` first for the base API.
**Official docs:** [Workflows overview](https://adk.dev/workflows/index.md) · [pkg.go.dev/workflow](https://pkg.go.dev/google.golang.org/adk/v2/workflow) · [runnable examples](https://github.com/google/adk-go/tree/main/examples/workflow)
A `Workflow` is a graph-based agent: nodes do work, edges define flow, `workflow.Start` is the entry point.
import (
"strings"
"google.golang.org/adk/v2/agent"
"google.golang.org/adk/v2/agent/workflowagent"
"google.golang.org/adk/v2/workflow"
)
cfg := workflow.NodeConfig{RetryConfig: workflow.DefaultRetryConfig()}
upper := workflow.NewFunctionNode("upper",
func(_ agent.Context, in string) (string, error) {
return strings.ToUpper(in), nil
}, cfg)
suffix := workflow.NewFunctionNode("suffix",
func(_ agent.Context, in string) (string, error) {
return in + " IS AWESOME!", nil
}, cfg)
rootAgent, err := workflowagent.New(workflowagent.Config{
Name: "simple_sequence_workflow",
Description: "Uppercases a string and appends a suffix",
Edges: workflow.Chain(workflow.Start, upper, suffix),
})The first node receives the user's message as its input. `workflowagent.New` returns a plain `agent.Agent`.
Every constructor takes a `NodeConfig` (retries, timeout — see *Retries, timeouts, errors*) and returns a value you drop into an `Edge`.
upper := workflow.NewFunctionNode("upper",
func(_ agent.Context, in string) (string, error) {
return strings.ToUpper(in), nil
}, workflow.NodeConfig{})The return value becomes `Event.Output` and arrives as the successor's typed input.
Use it when the node must produce something *besides* its return value: user-visible progress, a state delta, a routing tag, or a HITL prompt.
progress := workflow.NewEmittingFunctionNode("progress",
func(ctx agent.Context, in string, emit func(*session.Event) error) (any, error) {
ev := session.NewEvent(ctx, ctx.InvocationID())
// Content renders in the UI; Output is what the next node receives.
ev.Content = genai.NewContentFromText("working…", genai.RoleModel)
if err := emit(ev); err != nil {
return nil, err
}
// Returning a non-nil value emits a terminal event carrying it as Output.
// Returning nil instead suppresses that terminal event entirely — which is
// what you want when an event you already emitted carries the output.
return in, nil
}, workflow.NodeConfig{})**What a function node's return value becomes:** a `*session.Event` is yielded as-is (this is how you set `Event.Routes`), a `*genai.Content` becomes `event.Content`, and anything else becomes `event.Output`.
drafter, err := workflow.NewAgentNode(draftAgent, workflow.NodeConfig{})
// NewAgentNodeTyped[In, Out](draftAgent, cfg) instead reflects In/Out into JSON
// schemas, so the agent's input and reply are validated against your structs.An `LlmAgent` with unset `Mode` defaults to single-turn here. Register the wrapped agent in `workflowagent.Config.SubAgents` so event authors resolve.
lookup, err := workflow.NewToolNode(weatherTool, workflow.NodeConfig{})
// NewNamedToolNode("weather_step", weatherTool, cfg) to override the node name,
// which otherwise comes from the tool.sub, err := workflow.NewWorkflowNode("subflow", workflow.Chain(workflow.Start, upper, suffix))`NewJoinNode`, `NewDynamicNode` and `NewParallelWorker` are the concurrency kinds — see *Parallelism and fan-in*.
An edge with no `Route` always fires. A routed edge fires only when the source node tagged its event with a matching value:
edges := []workflow.Edge{
{From: workflow.Start, To: triage},
{From: triage, To: answer, Route: workflow.StringRoute("question")},
{From: triage, To: escalate, Route: workflow.IntRoute(2)},
{From: triage, To: archive, Route: workflow.BoolRoute(false)},
{From: triage, To: urgent, Route: workflow.MultiRoute[string]{"p0", "p1"}},
{From: triage, To: fallback, Route: workflow.Default},
}Every route is compared as a string against the entries in `Event.Routes`, so `IntRoute(2)` matches the entry `"2"` and `BoolRoute(false)` matches `"false"`. Any type with a `Matches(*session.Event) bool` method works as a route.
**A node signals its branch by setting `Event.Routes []string`** on an event it emits:
func classifyAndRoute(ctx agent.Context, msg string, emit func(*session.Event) error) (any, error) {
ev := session.NewEvent(ctx, ctx.InvocationID())
ev.Routes = []string{classify(msg)} // e.g. "question"
ev.Output = msg // feeds the successor's typed input
if err := emit(ev); err != nil {
return nil, err
}
return nil, nil // nil output suppresses the default terminal event
}
triage := workflow.NewEmittingFunctionNode("triage", classifyAndRoute, workflow.NodeConfig{})`EdgeBuilder` is the readable way to express fan-out and fan-in:
eb := workflow.NewEdgeBuilder()
eb.Add(workflow.Start, triage)
eb.AddRoute(triage, answer, workflow.StringRoute("question"))
eb.AddRoutes(triage, map[string]workflow.Node{ // shorthand for several StringRoutes
"statement": comment,
"exclamation": react,The CLI and skills that turn any coding assistant into an expert at creating, evaluating, and deploying AI agents on Google Cloud.
Repo: google/agents-cli
Reflects `google.golang.org/adk/v2 v2.1.0`, the version the `adk_go` template pins. If a symbol here is missing, check your `go.mod` before assuming the page…
Requires `google-adk >= 2.0.0`. This page documents the Python graph API; ADK Go has its own — see `references/adk-go-workflows.md`. Requires **Python >=…
* **`Agent`**: The core intelligent unit. Can be `LlmAgent` (LLM-driven) or `BaseAgent` (custom/workflow). * **`Tool`**: Callable function providing external…
Recipes live in [google/adk-samples](https://github.com/google/adk-samples). **`core/python/`** is the curated tier — canonical ADK patterns maintained by the…
**Assumes `/google-agents-cli-scaffold` scaffolding.** If your project isn't scaffolded yet, see `/google-agents-cli-scaffold` first.
Invoke your agent as a BigQuery Remote Function for batch inference over table rows. This requires a custom `POST /` endpoint since BQ cannot use URL paths.