finish tool with the values, or when a
closing tool’s result matches a FinishRule. Weak models sometimes skip that.
Quickstart
agent.py
finish with {"requested_service": "haircut"}. When it only says “Noted, thank you”, the finish check steps in. The sections below explain both cases.
Why use unmute for this
A weak model often says “Noted, thank you” and never finishes. The library asks the model one narrow question after such a reply, so the step does not wait forever.The finish check
Weak models often say “Noted, thank you” and stop, without callingfinish.
The step then waits for a save that never comes.
After a step’s reply that spoke and called nothing, once the caller has said
something new in the step, the runtime asks the model one narrow question:
finish with the values, or not_yet. The request offers only those two tools,
and a tool call is required.
- A
finishis sent as that reply’s own call. The step ends as if the model had called it. not_yetchanges nothing. The step goes on.- The check runs at most once per caller turn, and waits at most 8 seconds.
- A step with tools of its own is checked only after one of them succeeded, because its values come from that result.
ModelCallLLMService, an OpenAI-compatible service or a GoogleLLMService. For any other LLM, the spec’s AgentSpec(summarizer=...) answers the check. With no summarizer, there is no check.
Why it works this way. The check offers only finish and not_yet, so a weak model cannot wander off. It runs once per caller turn and has a time limit, so it never holds up the call.
Best practice.
- On Pipecat with a custom LLM, give the spec a
summarizer, or the check does not run.
The held finish
A finish is refused when the caller has not heard a tool’s result yet. The model reads “tell them what it means first”. That finish is held. When the next reply says the result and calls nothing, the runtime sends the held finish for it. Why it works this way. The caller hears a result before the step ends on it.Going back to an earlier step
While a step runs, the caller may change an earlier answer. The model then callsgo_back_to_step with the names in steps. A name the run cannot go back to is
refused as {"refused": ...}. The text lists the steps it can go back to:
none, no step ran before this one. A call with an empty list is refused with name at least one earlier step.
When the reply is empty
A model sometimes returns nothing: no words and no tool call. On LiveKit, a step then asks again, up toEMPTY_REPLY_ATTEMPTS times, which is 3. Each retry adds a different note to the step’s prompt.
- The note says the previous response was empty and asks for the step’s next valid response. It tells the model to use what the caller already said and never to ask again for it.
- Each retry reads a different note, because the Responses API reuses an earlier answer when the request has not changed.
- When the empty reply followed a step tool’s result, the retry offers only
finish, and the note says to use the tool result already in context. - When all tries are empty, a step its group can do without fails and the group carries on. Any other step stays open and says a short apology:
gave_up_line, orgave_up_after_tool_lineafter a tool result.
CallTasks, in the call’s language. Each adapter builds its own CallTasks from the spec, as agent.tasks on LiveKit and flows.tasks on Pipecat. So set agent.tasks.gave_up_line after you build the agent.
Troubleshooting
The step says it could not complete and the caller must try again
Every retry after an empty reply came back empty, and the step said itsgave_up_line.
Fix: set gave_up_line and gave_up_after_tool_line to lines in the call’s language. Then check the step’s instructions, so the model knows what to reply.
The caller changed an answer, and the step cannot go back
The model asked for a name the run cannot go back to. The refusal lists the steps it can. Fix: put the earlier step in the same group, and read the refusal text for the names it allows. In the salon tutorial: Book step by step. Every argument: Tasks reference.Where to go next
Held saves
What happens to a save made before the caller spoke.
Task groups
Run several tasks in order.