mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-01-30 06:12:06 +00:00
fix: ensure agents are removed from Mission Control UI on completion
Previously, agents that completed their work would remain visible in the Mission Control UI until a manual page refresh. This occurred because the AgentTracker._handle_agent_complete method silently dropped completion messages when an agent wasn't tracked (e.g., due to missed start messages from WebSocket connection issues). Backend changes: - Modified _handle_agent_complete in server/websocket.py to always emit completion messages, even for untracked agents - Synthetic completions use agentIndex=-1 and agentName='Unknown' as sentinel values to indicate untracked agents Frontend changes: - Updated useWebSocket.ts to handle synthetic completions by removing agents by featureId when agentIndex is -1 - Added 30-minute stale agent cleanup as defense-in-depth for users who leave the UI open for extended periods - Updated TypeScript types to allow 'Unknown' as valid agent name Component updates: - AgentAvatar.tsx: Added UNKNOWN_COLORS and UnknownSVG fallback for rendering unknown agents with a neutral gray question mark icon - CelebrationOverlay.tsx, DependencyGraph.tsx: Updated interfaces to accept 'Unknown' agent names Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -238,31 +238,41 @@ class AgentTracker:
|
||||
}
|
||||
|
||||
async def _handle_agent_complete(self, feature_id: int, is_success: bool) -> dict | None:
|
||||
"""Handle agent completion message from orchestrator."""
|
||||
"""Handle agent completion - ALWAYS emits a message, even if agent wasn't tracked."""
|
||||
async with self._lock:
|
||||
if feature_id not in self.active_agents:
|
||||
return None
|
||||
|
||||
agent = self.active_agents[feature_id]
|
||||
state = 'success' if is_success else 'error'
|
||||
agent_type = agent.get('agent_type', 'coding')
|
||||
|
||||
result = {
|
||||
'type': 'agent_update',
|
||||
'agentIndex': agent['agent_index'],
|
||||
'agentName': agent['name'],
|
||||
'agentType': agent_type,
|
||||
'featureId': feature_id,
|
||||
'featureName': agent['feature_name'],
|
||||
'state': state,
|
||||
'thought': 'Completed successfully!' if is_success else 'Failed to complete',
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
}
|
||||
|
||||
# Remove from active agents
|
||||
del self.active_agents[feature_id]
|
||||
|
||||
return result
|
||||
if feature_id in self.active_agents:
|
||||
# Normal case: agent was tracked
|
||||
agent = self.active_agents[feature_id]
|
||||
result = {
|
||||
'type': 'agent_update',
|
||||
'agentIndex': agent['agent_index'],
|
||||
'agentName': agent['name'],
|
||||
'agentType': agent.get('agent_type', 'coding'),
|
||||
'featureId': feature_id,
|
||||
'featureName': agent['feature_name'],
|
||||
'state': state,
|
||||
'thought': 'Completed successfully!' if is_success else 'Failed to complete',
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
}
|
||||
del self.active_agents[feature_id]
|
||||
return result
|
||||
else:
|
||||
# Synthetic completion for untracked agent
|
||||
# This ensures UI always receives completion messages
|
||||
return {
|
||||
'type': 'agent_update',
|
||||
'agentIndex': -1, # Sentinel for untracked
|
||||
'agentName': 'Unknown',
|
||||
'agentType': 'coding',
|
||||
'featureId': feature_id,
|
||||
'featureName': f'Feature #{feature_id}',
|
||||
'state': state,
|
||||
'thought': 'Completed successfully!' if is_success else 'Failed to complete',
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'synthetic': True,
|
||||
}
|
||||
|
||||
|
||||
class OrchestratorTracker:
|
||||
|
||||
Reference in New Issue
Block a user