You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The gateway has no way to stop an agent turn that is already running, and no per-turn timeout. Once a turn begins it runs to completion on the session's serial queue; every later message from that user queues behind it. A single slow tool call, a doom-looping agent, or a stuck provider request therefore wedges the conversation indefinitely, and neither the end user (over a channel) nor a WS/operator client can interrupt it.
The protocol contract for this already exists in core — EventType.MESSAGE_ABORT is defined and InterruptController is implemented — but the gateway server never wires either of them. The gateway even advertises this absence to clients in its capability handshake.
Current behaviour
The gateway explicitly does not advertise an abort method, with a comment stating so:
There is no /stop-style channel command and no message_abort handler in _handle_client_message.
Desired behaviour
A running turn can be cancelled: (a) by a WS/operator client sending a message_abort frame, and (b) by a chat user via a portable stop command (e.g. /stop).
Each turn runs under a configurable per-turn timeout; on expiry it is cancelled and a typed terminal outcome is returned, not left hanging.
Cancellation cooperatively signals the running agent (via the existing InterruptController) and cancels the asyncio task driving _dispatch_agent_turn.
Any partial output produced before interruption is preserved and delivered, and the terminal state is normalised through the existing run_outcome / AgentRunOutcome machinery rather than surfacing as a coarse error string.
Why not core: the run loop, session queue, and WS frame router that must be interrupted live in the wrapper gateway server; core already supplies the contract (MESSAGE_ABORT) and the primitive (InterruptController).
Why not wrapper CLI/YAML only: this is a runtime protocol capability, not a config surface.
Why not tools: cancellation is a runtime lifecycle concern, not an agent-callable tool.
Why not plugins: it is core gateway behaviour every channel needs, not an optional lifecycle hook.
Secondary touch (optional): core — expose an InterruptController on the run scope the gateway drives, and ensure agent.arun/achat accept a cancellation/timeout signal.
3-way surface (CLI + YAML + Python): partial — a gateway.per_turn_timeout config knob is YAML/CLI-worthy; the abort itself is a runtime protocol method + chat command.
# Before (today): a Telegram user sends a heavy request; the agent gets stuck in a tool# call. The user types "stop" — nothing happens. Every further message queues behind the# wedged turn. Only killing the gateway process clears it.# After (proposed): the user types /stop (or a WS client sends {"type":"abort"}); the# running turn is cancelled, partial output is delivered, and the queue resumes. A# per-turn timeout also auto-cancels a runaway turn without operator intervention.
Severity
Critical — an un-cancellable, un-time-bounded turn on a serial per-session queue is a production liveness hazard for any always-on gateway/bot; there is currently no recourse short of restarting the process.
Validation
src/praisonai-bot/praisonai_bot/gateway/server.py:2741 — abort explicitly not advertised.
src/praisonai-bot/praisonai_bot/gateway/server.py:3033 and :3050 — turn awaited with no timeout inside a serial while True queue.
_handle_client_message handles only hello/join/message/leave; no message_abort branch.
src/praisonai-agents/praisonaiagents/gateway/protocols.py:184 — MESSAGE_ABORT defined but unhandled.
src/praisonai-agents/praisonaiagents/agent/interrupt.py:41 — InterruptController exists, unused by the gateway.
Summary
The gateway has no way to stop an agent turn that is already running, and no per-turn timeout. Once a turn begins it runs to completion on the session's serial queue; every later message from that user queues behind it. A single slow tool call, a doom-looping agent, or a stuck provider request therefore wedges the conversation indefinitely, and neither the end user (over a channel) nor a WS/operator client can interrupt it.
The protocol contract for this already exists in core —
EventType.MESSAGE_ABORTis defined andInterruptControlleris implemented — but the gateway server never wires either of them. The gateway even advertises this absence to clients in its capability handshake.Current behaviour
The gateway explicitly does not advertise an abort method, with a comment stating so:
The core protocol already reserves the event, but nothing handles it:
A core interrupt primitive already exists and is unused by the gateway:
The turn is awaited with no timeout and no cancellation handle:
And it runs inside a strictly serial per-session loop, so a stuck turn starves every queued message:
There is no
/stop-style channel command and nomessage_aborthandler in_handle_client_message.Desired behaviour
message_abortframe, and (b) by a chat user via a portable stop command (e.g./stop).InterruptController) and cancels theasynciotask driving_dispatch_agent_turn.run_outcome/AgentRunOutcomemachinery rather than surfacing as a coarse error string.Layer placement
praisonai→praisonai_bot)MESSAGE_ABORT) and the primitive (InterruptController).InterruptControlleron the run scope the gateway drives, and ensureagent.arun/achataccept a cancellation/timeout signal.gateway.per_turn_timeoutconfig knob is YAML/CLI-worthy; the abort itself is a runtime protocol method + chat command.Proposed approach
message_abort) + portable stop command + per-turnasyncio.wait_for/cancel scope.Resolution sketch
Severity
Critical — an un-cancellable, un-time-bounded turn on a serial per-session queue is a production liveness hazard for any always-on gateway/bot; there is currently no recourse short of restarting the process.
Validation
src/praisonai-bot/praisonai_bot/gateway/server.py:2741— abort explicitly not advertised.src/praisonai-bot/praisonai_bot/gateway/server.py:3033and:3050— turn awaited with no timeout inside a serialwhile Truequeue._handle_client_messagehandles onlyhello/join/message/leave; nomessage_abortbranch.src/praisonai-agents/praisonaiagents/gateway/protocols.py:184—MESSAGE_ABORTdefined but unhandled.src/praisonai-agents/praisonaiagents/agent/interrupt.py:41—InterruptControllerexists, unused by the gateway.