All skills
google avatar

/adk-agent-builder

@29933ce
by googlegoogle/adk-python22k stars
4,084

Builds ADK (Agent Development Kit) Python agents: LLM agents with tools, graph workflows of function and agent nodes, conditional routing, fan-out and join, schema-validated delegation between agents, human-in-the-loop pauses, and pytest coverage for all of it. Use when asked to create an agent or a workflow, add a tool to one, branch or loop between nodes, run steps in parallel, pause for user approval, or test an agent. Don't use for explaining how ADK works internally or designing its core components (use `adk-architecture`), for an agent that already runs but misbehaves (use `adk-debug`), for authoring a sample under `contributing/` (use `adk-sample-creator`), or for naming, typing, and formatting conventions (use `adk-style`).

Use this Skill: https://skilld.dev/gh/google/adk-python/adk-agent-builder

This session only. Nothing lands on disk.

referencesrouting-and-conditions.md

≈1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Routing and Conditional Branching

A node emits Event(route=...); the edges leaving that node decide which successors fire.

Dict routing — the default form

Map route values to targets in one edge tuple:

from google.adk import Event, Workflow


def classify(node_input: str):
  route = 'error' if 'error' in node_input else 'success'
  return Event(output=node_input, route=route)


agent = Workflow(
    name='router',
    edges=[
        ('START', classify),
        (classify, {'success': handle_success, 'error': handle_error}),
    ],
)

The three-tuple form (classify, handle_success, 'success') does the same thing one target at a time. Reach for it only when a single edge must match several routes (see below), since the dict form maps one route to one target.

Sequence shorthand

A tuple of more than two elements becomes a chain:

edges = [('START', step_a, step_b, step_c)]
# equivalent to [('START', step_a), (step_a, step_b), (step_b, step_c)]

Chains and dict routing compose:

edges = [
    ('START', process_input, classify),
    (classify, {'approved': send, 'rejected': discard}),
]

Route values

A route is a str, bool, or int, or a list of those.

(decision, {'approve': path_a, 'reject': path_b})   # strings
(decision, {True: yes_path, False: no_path})        # booleans
(decision, {0: path_0, 1: path_1})                  # integers

Default route

'__DEFAULT__' (exported as DEFAULT_ROUTE) fires when no other route on that node matches:

edges = [
    ('START', classify),
    (classify, {
        'success': handler_a,
        'error': handler_b,
        '__DEFAULT__': fallback_handler,
    }),
]

The default fans out like any other route, so '__DEFAULT__': (a, b) triggers both. '__DEFAULT__' may not appear inside a list of routes on one edge — give it its own edge.

One edge, several routes

Passing a list matches any value in it:

edges = [
    ('START', classifier),
    (classifier, {'route_z': handler_b}),
    (classifier, handler_a, ['route_x', 'route_y']),
]

Several routes from one node

A node can emit a list of routes to fire multiple branches at once:

def fan_out_router(node_input: str):
  return Event(output=node_input, route=['path_a', 'path_b'])


agent = Workflow(
    name='multi_route',
    edges=[
        ('START', fan_out_router),
        (fan_out_router, {'path_a': branch_a, 'path_b': branch_b}),
    ],
)

Self-loop

def guess_number(target_number: int):
  guess = random.randint(0, 10)
  yield Event(message=f'Guessing {guess}...')
  if guess == target_number:
    yield Event(message='Correct!')
  else:
    yield Event(route='guessed_wrong')


agent = Workflow(
    name='root_agent',
    edges=[
        ('START', validate_input, guess_number),
        (guess_number, {'guessed_wrong': guess_number}),
    ],
)

Revision loop

edges = [
    ('START', process_input, draft_email, human_review),
    (human_review, {
        'revise': draft_email,
        'approved': send,
        'rejected': discard,
    }),
]

Constraints the graph validator enforces

  • A cycle needs at least one routed edge. An entirely unconditional cycle is rejected at construction time, because nothing could ever break out of it.
  • Edges leaving START may not carry a route. START never runs, so it never emits one.
  • No two edges may share a source and a target, even with different routes. To reach one destination from both a named route and __DEFAULT__, point the default at a thin wrapper function.

Unrouted edges always fire

An edge with no route fires on every output event from its source, whatever route that event carries. So if a node routes at all, give every one of its outgoing edges a route — otherwise the unrouted one fires alongside the branch you selected.

edges = [
    ('START', node_a),  # unconditional
    (node_a, node_b),   # fires on every node_a output
]

Source: SKILL.md on GitHub

No alerts7d3 checks · Risk SAFE
  • Gen Agent Trust Hub7d

    This skill provides comprehensive documentation and reference material for building agents using the Google Agent Development Kit (ADK). It covers workflow orchestration, tool usage, and includes guidance on security best practices like input validation and secure credential management. No security issues were detected.

  • Socket7d

    No alerts

  • Snyk7d

    Risk: LOW · No issues

Signed by skilld at 29933ce. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 2 months ago

README badge

README badge for google/adk-python/adk-agent-builder