Turn Completion Notes
Tell chat users why an agent turn stopped early instead of a silent truncation
Turn a coarse last_stop_reason into a concise, user-safe note so a chat user learns why a turn stopped early β instead of getting a silently truncated or empty reply.
Covered reasons mirror Agent.last_stop_reason: completed | max_steps | cancelled | error, plus the three provider-block reasons content_filtered | refused | length_truncated. A deep-research agent hits its step limit; instead of a truncated answer, the reply ends with β³ I stopped after reaching the step limit β reply "continue" to carry on. As of PR #5764, error is reliably set on a terminal LLM failure (server 500, revoked key, exhausted retries) in both the sync and async paths, so the gateway can surface the default β οΈ This turn ended early due to an error β please try again. note instead of a silent empty reply.
from praisonaiagents import Agent
from praisonai.bots import BotSessionManager
agent = Agent(
name="Deep Researcher",
instructions="Do multi-step web research and summarise findings.",
max_steps=20, # long budget β truncation is possible
)
# Opt in on the session manager: tell the user *why* if a turn stops early.
session = BotSessionManager(
platform="telegram",
surface_completion_reason=True,
)
# When the agent hits its step budget, the reply ends with the completion note.
reply = await session.chat(agent, user_id="123", prompt="Research X in depth")Quick Start
- Enable the notes on the gateway
Construct the session manager with
surface_completion_reason=True. Cleancompletedturns still surface nothing.python from praisonai.bots import BotSessionManager session = BotSessionManager( platform="telegram", surface_completion_reason=True, # append the note when a turn stops early ) - Customise a note per turn
Override the default note for a turn by returning an
AgentReplywith aTurnCompletionthat carriesdetail.python from praisonaiagents.bots import AgentReply, TurnCompletion reply = AgentReply( text="Here's what I found so far.", completion=TurnCompletion( reason="max_steps", detail="Long research task β reply 'continue' to keep going.", ), )
How It Works
After each turn the session manager reads the agent’s last_stop_reason, wraps it in a TurnCompletion, and β when enabled β appends the note to the reply.
extract_completion recognises an AgentReply with a completion, a serialised dict, or any object exposing completion / last_stop_reason (including a bare Agent). append_completion_note returns the text unchanged when disabled, when there is no completion, or when the turn completed cleanly.
Reasons and Default Notes
TurnCompletion.note() maps each stop reason to a user-safe message. A clean completion is intentionally silent.
reason | Note surfaced to the user |
|---|---|
completed | (nothing β clean completion is silent) |
max_steps | β³ I stopped after reaching the step limit β reply "continue" to carry on. |
cancelled | π This turn was interrupted before it finished β send it again to retry. |
error | β οΈ This turn ended early due to an error β please try again. |
content_filtered | β³ This turn ended early β please try again. (generic fallback β see note) |
refused | β³ This turn ended early β please try again. (generic fallback β see note) |
length_truncated | β³ This turn ended early β please try again. (generic fallback β see note). Fires only after output_continuation‘s cap is exhausted β see Output Continuation. |
| (unknown/new) | β³ This turn ended early β please try again. |
Configuration Options
| Setting | Type | Default | Description |
|---|---|---|---|
surface_completion_reason | bool | False | On BotSessionManager. Opt in to append the completion note to gateway replies. Clean completed turns still surface nothing. |
TurnCompletion and append_completion_note take these fields:
| Field / Argument | Type | Default | Description | |||
|---|---|---|---|---|---|---|
TurnCompletion.reason | str | "completed" | Stop reason (`completed \ | max_steps \ | cancelled \ | error`; unknown tolerated). |
TurnCompletion.detail | str | "" | Optional user-safe override for the default note. | |||
append_completion_note(..., enabled=) | bool | False | Off by default β returns the text untouched unless enabled. |
Common Patterns
Long research agents with a high max_steps β enable the note so "continue" becomes a discoverable UX:
agent = Agent(name="Researcher", instructions="Deep multi-step research.", max_steps=20)
session = BotSessionManager(platform="telegram", surface_completion_reason=True)
# Hits the budget β reply ends with the "reply continue" note.Cancellation UX β the user hits /stop and sees the cancelled note instead of no reply:
# reason="cancelled" β "π This turn was interrupted before it finished β send it again to retry."Error transparency β the user sees the error note and can retry without opening a ticket:
# reason="error" β "β οΈ This turn ended early due to an error β please try again."Best Practices
Leave off for internal bots
Enable it for public-facing gateways. Internal bots often prefer silence, so keep the default False there.
Use detail to stay on-brand
TurnCompletion.detail overrides the default note per turn β use it to keep messages localised and on-brand.
Happy paths stay quiet
Notes never surface on a clean completion, so enabling this adds no noise to successful turns.
Pair with max_steps
Combine with the step-limit docs so users understand the “reply continue” flow when a turn hits its budget.