Skip to main content
Back to how-to guides Use this pattern when the same request must reach a different agent by channel, language, user role, or session state.

Concept

A HANDOFF route can test any value in the session data. Write the test as an expression in WHEN. The platform evaluates it without the model, and it refuses the route when the expression is false. Context routing differs from intent routing in one way. The classifier does not run when the supervisor has no intent.category condition and no INTENTS: section. The supervisor model then chooses among the routes, and the platform enforces each route’s WHEN when the model calls it. Two tools control which routes the model can reach.

Values you can test

The platform provides channel, language, locale, time zone, and identity. It provides no role. Your channel, SDK, or a lookup must supply the role. Treat caller data from a browser as unverified. Pair a role test with session.identityTier == 2. Use session.channel for the channel. The paths channel.name and system.channel belong to other features. They do not resolve in a HANDOFF WHEN, and channel.name compiles without a warning. The path session.interaction.current.channel does not exist. Voice has several channel types: voice, voice_twilio, voice_livekit, voice_realtime, voice_pipeline, voice_vxml, korevg, audiocodes, and genesys_audio_connector. A test for "voice" matches only the first one. Use IN [...] to match the family.

Order and ties

The position of an entry sets its priority. The first entry has the highest priority. The PRIORITY: field is read and then ignored. Several deterministic routes can be true at once, for example a Spanish speaker on a voice channel. The model then chooses, and the position shows as [Priority N] in each route description. To make the result certain, write exclusive conditions or put the combined route first. See Combine conditions.

Minimal working example

This supervisor routes verified administrators, Spanish speakers, and voice callers. A WHEN: true route handles everyone else. Put the supervisor and all agents in the same project. The target agents are short stand-ins. agents/context-routing-supervisor.agent.abl
agents/admin-support-agent.agent.abl
agents/spanish-service-agent.agent.abl
agents/voice-support-agent.agent.abl
agents/standard-service-agent.agent.abl
Project-local assumptions:
  • session.user_role is caller data that your SDK or channel sends, for example the value admin.
  • customer_id and account_id follow the same rules as in How to route users by detected intent. The platform passes the supervisor’s value when it has one. Otherwise the model fills the field from the conversation.

How it works

  1. The supervisor keeps the conversation until a route fires.
  2. The model calls a route. The platform evaluates that route’s WHEN against the session data.
  3. A true expression admits the route. A false expression refuses it, and the model tries another route.
  4. The target receives the PASS values, the summary, and the history that history allows. The default is full.
  5. With EXPECT_RETURN: false, the target keeps the conversation. With EXPECT_RETURN: true, the supervisor resumes when the target returns.
  6. A missing value makes a test false. session.user_role == "admin" is false when the role is absent.
  7. The WHEN: true route is always available. It receives any request that the other routes do not take.
A route without an intent.category test never reads the category.

Common variations

Combine conditions

Join tests with AND and OR. Put the combined route before the single-test routes. Here, Spanish voice callers reach a dedicated agent.
Do not join a test with a quoted phrase. In session.channel == "voice" AND "the user is a VIP", the compiler warns with CEL_CONDITION_UNRESOLVED_CALL. At runtime the phrase is a string that is always true, so the route fires for every voice caller. Test a field instead, for example session.customer_tier == "vip".

Route on locale

Use the locale when the dialect matters.

Route on state that a child returns

Use EXPECT_RETURN: true when another agent collects the value first. This route asks for a language preference once. It then routes on the answer.
map copies the child’s chosen_language into the supervisor’s preferred_language. Write the child field first. The child must gather or produce chosen_language. Use IS NOT SET on a plain variable such as preferred_language. Do not use it on a dotted path such as session.interaction.current.language. The path holds a null value when the language is unknown, and IS NOT SET is false for null.

Hide a route on other channels

Add ENABLED_WHEN when a channel must never see a route. The model does not see the route while the condition is false.
Write ENABLED_WHEN as an expression over data that exists before the turn. A condition that reads intent or plain language fails to compile with ENABLED_WHEN_SEMANTIC_REFERENCE. A condition that reads a missing value counts as false.

Add ON_FAILURE

ON_FAILURE runs when the handoff fails before the target accepts it.
The values are CONTINUE, ESCALATE, and RESPOND "message". A bare quoted string fails with INVALID_HANDOFF_FAILURE_ACTION.

Verification

  1. Start a voice session and send a message. Open the trace. Find the handoff_condition_check event for the voice route. Confirm result: true and whenOutcome: deterministic_pass.
  2. In the same event, read evaluatedContext. Confirm the value of session.channel that your channel reports.
  3. Send a Spanish message on a web channel. Confirm Spanish_Service_Agent. Check session.interaction.current.language in the event.
  4. Start a session with caller data user_role set to admin and an identity tier of 2. Confirm Admin_Support_Agent. Repeat with tier 0. Confirm the route is refused.
  5. Send a message that matches no condition. Confirm Standard_Service_Agent.
  6. Check that each target receives the pass values and the summary.

Production readiness checklist

  • Every value in a WHEN has a source: the platform, caller data, a lookup, or a child’s return.
  • Role tests also require a verified identity, for example session.identityTier == 2.
  • Channel tests list every channel type in the family, or you confirm the exact value in a trace.
  • Overlapping routes are ordered, or their conditions exclude each other.
  • A WHEN: true route or an answering supervisor covers every other message.
  • Quoted phrases never appear inside an AND or OR test.
  • ON_FAILURE is set on routes where a missing target must produce a reply.
  • Tests cover each channel, each language, each role, and one message with no match.

Common mistakes

Troubleshooting