Capture and Route: IT Helpdesk Triage

Real-world use case: IT helpdesk ticket capture and routing system. Captures incoming messages into state, classifies urgency, and routes to appropriate support tiers.

In other frameworks: LangGraph requires custom state capture via TypedDict updates and conditional_edges for routing. adk-fluent uses S.capture() for state injection and Route() for declarative branching.

Pipeline topology: S.capture(“ticket”) >> triage [save_as: priority] >> Route(“priority”) ├─ “p1” -> incident_commander ├─ “p2” -> senior_support └─ else -> support_bot

Tip

What you’ll learn How to compose agents into a sequential pipeline.

Source: 50_capture_and_route.py

from adk_fluent import Agent, S
from adk_fluent._routing import Route
from adk_fluent.testing import check_contracts

MODEL = "gemini-2.5-flash"

# IT Helpdesk: capture ticket → classify priority → route to team
helpdesk = (
    S.capture("ticket")
    >> Agent("triage")
    .model(MODEL)
    .instruct(
        "You are an IT helpdesk triage agent.\n"
        "Read the support ticket and classify it.\n"
        "Ticket: {ticket}\n"
        "Output the priority level: p1, p2, or p3."
    )
    .writes("priority")
    >> Route("priority")
    .eq(
        "p1",
        Agent("incident_commander")
        .model(MODEL)
        .instruct(
            "CRITICAL INCIDENT.\nOriginal ticket: {ticket}\nCoordinate immediate response. Page on-call engineer."
        ),
    )
    .eq(
        "p2",
        Agent("senior_support")
        .model(MODEL)
        .instruct("Priority ticket.\nTicket: {ticket}\nInvestigate and provide a resolution plan within 4 hours."),
    )
    .otherwise(
        Agent("support_bot")
        .model(MODEL)
        .instruct("Routine support request.\nTicket: {ticket}\nProvide self-service instructions or FAQ links.")
    )
)

# Verify data contracts before deployment
issues = check_contracts(helpdesk.to_ir())
contract_errors = [i for i in issues if isinstance(i, dict) and i.get("level") == "error"]

built = helpdesk.build()
# In native ADK, capturing the user's message into state for downstream
# agents requires writing a custom BaseAgent subclass:
#
# class CaptureUserMessage(BaseAgent):
#     async def _run_async_impl(self, ctx):
#         for event in reversed(ctx.session.events):
#             if event.author == "user":
#                 ctx.session.state["ticket"] = event.content.parts[0].text
#                 break
#
# Then manually wiring it as the first step in a SequentialAgent.
# Route-based dispatch requires another custom agent with if/elif logic.
        graph TD
    n1[["capture_ticket_then_triage_routed (sequence)"]]
    n2>"capture_ticket capture(ticket)"]
    n3["triage"]
    n4{"route_priority (route)"}
    n5["incident_commander"]
    n6["senior_support"]
    n7["support_bot"]
    n4 --> n5
    n4 --> n6
    n4 -.-> n7
    n2 --> n3
    n3 --> n4
    n3 -. "priority" .-> n4
    n2 -. "ticket" .-> n3
    n2 -. "ticket" .-> n5
    n2 -. "ticket" .-> n6
    n2 -. "ticket" .-> n7
    

Equivalence

# Contract checking passes — all {ticket}, {priority} resolve
assert len(contract_errors) == 0

# Pipeline builds with capture agent first
from adk_fluent._primitives import CaptureAgent

assert isinstance(built.sub_agents[0], CaptureAgent)
assert built.sub_agents[0].name == "capture_ticket"

# Triage agent is second
assert built.sub_agents[1].name == "triage"

# Full pipeline builds
assert built is not None
assert len(built.sub_agents) >= 3