Summary
Allow users to cancel an in-progress agent response from the Chat UI. Currently, clicking "Stop" aborts the SSE stream (via AbortController), but the agent thread continues running in the background — wasting compute and potentially executing unwanted tool calls.
Motivation
When the agent is taking a long time (e.g., multi-step plan with tool calls), the user has no way to actually stop it. The frontend can close the stream, but the backend thread keeps going. This wastes resources and can lead to confusing state where a "cancelled" message still gets saved.
Design
Agent Framework (src/gaia/agents/base/agent.py)
-
Add _cancelled flag to the Agent base class:
def __init__(self):
self._cancelled = threading.Event()
def cancel(self):
"""Request cooperative cancellation of the current query."""
self._cancelled.set()
def _check_cancelled(self):
"""Check if cancellation was requested. Call at safe points."""
if self._cancelled.is_set():
raise AgentCancelled("Execution cancelled by user")
-
Add cancellation checkpoints in process_query():
- Before each step iteration
- Before
_execute_tool()
- Before LLM calls
- After tool completion
-
AgentCancelled exception — New exception type in errors.py that the streaming loop catches gracefully.
Server (src/gaia/chat/ui/server.py)
-
Store active agent reference per session:
_active_agents: Dict[str, ChatAgent] = {}
-
POST /api/chat/cancel endpoint:
@app.post("/api/chat/cancel")
async def cancel_chat(request: CancelRequest):
agent = _active_agents.get(request.session_id)
if agent:
agent.cancel()
return {"cancelled": True}
-
Cleanup — Remove agent from _active_agents when streaming completes.
Frontend
api.ts — cancelChat(sessionId) function
- ChatView — "Stop" button calls
cancelChat() in addition to AbortController.abort()
Acceptance Criteria
Files to Modify
src/gaia/agents/base/agent.py — _cancelled flag, cancel(), checkpoints
src/gaia/agents/base/errors.py — AgentCancelled exception
src/gaia/chat/ui/server.py — Active agent tracking, /api/chat/cancel
src/gaia/apps/chat/webui/src/services/api.ts — cancelChat()
src/gaia/apps/chat/webui/src/components/ChatView.tsx — Wire stop button
Summary
Allow users to cancel an in-progress agent response from the Chat UI. Currently, clicking "Stop" aborts the SSE stream (via
AbortController), but the agent thread continues running in the background — wasting compute and potentially executing unwanted tool calls.Motivation
When the agent is taking a long time (e.g., multi-step plan with tool calls), the user has no way to actually stop it. The frontend can close the stream, but the backend thread keeps going. This wastes resources and can lead to confusing state where a "cancelled" message still gets saved.
Design
Agent Framework (
src/gaia/agents/base/agent.py)Add
_cancelledflag to the Agent base class:Add cancellation checkpoints in
process_query():_execute_tool()AgentCancelledexception — New exception type inerrors.pythat the streaming loop catches gracefully.Server (
src/gaia/chat/ui/server.py)Store active agent reference per session:
POST /api/chat/cancelendpoint:Cleanup — Remove agent from
_active_agentswhen streaming completes.Frontend
api.ts—cancelChat(sessionId)functioncancelChat()in addition toAbortController.abort()Acceptance Criteria
gaia chat) handles Ctrl+C gracefully via the same mechanismFiles to Modify
src/gaia/agents/base/agent.py—_cancelledflag,cancel(), checkpointssrc/gaia/agents/base/errors.py—AgentCancelledexceptionsrc/gaia/chat/ui/server.py— Active agent tracking,/api/chat/cancelsrc/gaia/apps/chat/webui/src/services/api.ts—cancelChat()src/gaia/apps/chat/webui/src/components/ChatView.tsx— Wire stop button