Skip to main content
Back to how-to guides Use this pattern when another agent or a person finishes part of a conversation and the original agent must pick up the work.

Concept

Four things can finish work for an agent. Each one returns control in a different way. A handoff with EXPECT_RETURN: false does not return. The parent finishes and the target owns the conversation. Hand off to a terminal agent covers that pattern. To choose between a handoff and a delegate, see Use a handoff instead of a delegate and Use a delegate instead of a handoff. To start a returnable handoff, see Hand off to a returnable agent. Two settings decide what the parent does after a child returns:

Minimal working example

A supervisor sends an unverified customer to a verification agent. The child returns. The supervisor replays the original question and routes it to the order agent.
Walk through a conversation:
  1. The customer says “Where is my order?”. verified_customer_id is not set, so the supervisor hands off to the verification agent.
  2. The child asks for the customer ID and completes. The platform copies customer_id from the child into verified_customer_id on the supervisor.
  3. The supervisor replays “Where is my order?”. Now verified_customer_id is set and the intent is order_status, so the supervisor hands off to the order agent.

How it works

How control returns

A child agent returns in one of two ways:
  • The child reaches COMPLETE. Its thread ends.
  • The child’s model hands the conversation back before it completes. Its thread pauses and stays resumable.
In both cases the parent becomes the active agent. The platform adds the child’s customer-visible replies to the parent conversation history.

State and memory after the return

The map block decides which child values reach the parent. Keep these rules in mind:
  • A mapped child key must hold a value. A GATHER field or a SET assignment in the child gives it one. A key with no value is skipped without an error.
  • An empty returned value does not overwrite a parent value that is already set.
  • set assigns parent values after the map runs.
  • A map target that is a reserved or system variable is rejected. When any map, set, or clear target is not writable, the platform applies none of the return effects. This includes RESPOND.
  • Memory with the execution_tree scope returns automatically.
  • Other child values stay with the child unless you map them.

What the parent does next

Without ON_RETURN, the parent resumes. If the child returned a customer message, the parent routes that message as if the action were resume_intent. With resume_intent, the platform picks the message to replay with resume_with: If you omit resume_with and the child passed a message back, the platform replays the passed message. The platform does not forward a message that answers a sensitive question, such as a PIN. The platform replays once for each return. A reasoning parent allows one replay level. A parent that returns from a flow child can pass a replay up through four nested returns. When the limit is reached, the trace shows resume_intent_depth_limit. With continue, the parent continues its own flow or turn without a replay.

Delegate results

A delegate runs in a separate scope inside one turn. It cannot wait for customer input. If the child needs input, the delegate fails. Give the child everything it needs through INPUT. The RETURNS block copies named child values into parent variables. If you declare RETURNS and the child returns none of those values, the delegate fails. The platform blocks unsafe key names and scrubs secrets from returned values. A delegate stops waiting when TIMEOUT expires. Without TIMEOUT, the platform uses the runtime default. The default is 30 seconds unless your operator changes it. A failure follows ON_FAILURE:

A one-way child that hands back

In 1.9.0, a child that the parent left with EXPECT_RETURN: false can still hand the conversation back to its direct parent. The child needs its own HANDOFF entry that targets that parent. This works only while the first handoff call is still in progress. The platform blocks routes to any other earlier agent as cycles.

When a human agent finishes

Where the person works decides how the session resumes. post_agent is end unless you set return in the routing block or in the project default for agent transfer. With post_agent: return, the agent that escalated resumes. A customer message such as thanks, bye, or done within 5 minutes of the transfer end completes the session. Any other message goes to the agent. With a SmartAssist survey, the platform keeps the session open until the customer answers the survey or the answer window ends. The person’s wrap-up form arrives after the disconnect and finishes the transfer record. The resume decision is already made at that point. While the person is working, customer messages go to the person. The agent does not answer them.

Conditions for on_human_complete

When on_human_complete has entries, the platform pauses the session at escalation. The customer receives the waiting message for every message until the task resolves. The pause record expires after 7 days. The resolve call carries a decision value. The platform checks the entries in order and returns the action of the first match. These are the only supported conditions: An entry with any other condition never matches. If no entry matches, the action is continue.

Timeouts and abandoned handoffs

Common variations

Continue with the parent’s own flow

Use continue when the parent keeps working and only needs the returned values. This example copies the income and records a note.

Delegate a check and map the result

The order desk asks the refund checker for a decision. The checker never talks to the customer. Project-local assumption: the project defines the check_refund_policy tool.
Write ON_FAILURE in a DELEGATE entry. A DELEGATE entry that uses ON_FAIL compiles without an error, and the platform ignores the line.

Resume the agent after the person finishes

Set post_agent: return so the agent that escalated resumes when the person disconnects.

End the session when the person finishes

Set post_agent: end, or leave it out, when the person closes the conversation.

Pause for a reviewer decision

Use on_human_complete when a reviewer answers through the inbox or the resolve API. The decision string drives the returned action.
Reviewers answer with a POST to the project session path /sessions/<session ID>/escalation/resolve. The caller needs the session:execute permission. The body holds resolution with decision, respondedBy, and optional notes and fields. The response returns data.action. Your integration reads the action and acts on it. Conditions such as human.resolved == true never match. The resolve call returns continue for them.

Hand a one-way child back to the parent

A child that the parent left for good can hand the conversation back to the parent while the first handoff call is still in progress.

Verification

  1. Validate the project. Fix every warning about unset variables or unknown conditions.
  2. Run a conversation that triggers the handoff. Confirm that the child owns the next turns.
  3. Complete the child task. Open the session trace and find return_to_parent or thread_return.
  4. Check the parent variables. Each mapped variable holds the child value. A mapped variable with no value means the child did not hold the key.
  5. For resume_intent, find the resume_intent event. Check resumeMessage and resumeMessageSource. Confirm that the parent routed to the expected agent.
  6. Find the handoff_completed event. Check outcome and durationMs. This event records the handoff attempt. It does not record the return.
  7. For a delegate, find delegate_complete. Check success. Find delegate_return_mapping to see which keys were set or blocked.
  8. Force a delegate failure in a test project. Confirm that ON_FAILURE runs and the customer sees the message.
  9. For a desk escalation, end the conversation at the desk. With post_agent: return, send a message and check that the agent answers. With end, check that the session reports the conversation as complete.
  10. For on_human_complete, call the resolve endpoint once for each decision. Check data.action. Find the escalation_resolved event.

Production readiness checklist

  • Every map key exists in the child as a GATHER field or a SET target.
  • Every map target has a MEMORY declaration in the parent and is not a reserved name.
  • Each resume_intent parent has a route that can handle the replayed message.
  • Each child has a COMPLETE rule or a way to hand back. A child without one keeps the conversation.
  • Each DELEGATE has a TIMEOUT and an ON_FAILURE.
  • You set post_agent on every desk route. You do not rely on the default end.
  • Every on_human_complete condition uses decision. Your integration reads data.action.
  • You set a service level for the escalation inbox. Someone watches tasks that are due.
  • You tested the success path, a returned message, a delegate timeout, a delegate failure, and each post_agent value.
  • Monitoring watches handoff_completed, delegate_complete, memory_error, and escalation_resolved events.

Common mistakes

Troubleshooting