mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-02-05 16:33:08 +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:
@@ -24,7 +24,7 @@ interface ActivityItem {
|
||||
|
||||
// Celebration trigger for overlay
|
||||
interface CelebrationTrigger {
|
||||
agentName: AgentMascot
|
||||
agentName: AgentMascot | 'Unknown'
|
||||
featureName: string
|
||||
featureId: number
|
||||
}
|
||||
@@ -190,9 +190,18 @@ export function useProjectWebSocket(projectName: string | null) {
|
||||
if (message.state === 'success' || message.state === 'error') {
|
||||
// Remove agent from active list on completion (success or failure)
|
||||
// But keep the logs in agentLogs map for debugging
|
||||
newAgents = prev.activeAgents.filter(
|
||||
a => a.agentIndex !== message.agentIndex
|
||||
)
|
||||
if (message.agentIndex === -1) {
|
||||
// Synthetic completion: remove by featureId
|
||||
// This handles agents that weren't tracked but still completed
|
||||
newAgents = prev.activeAgents.filter(
|
||||
a => a.featureId !== message.featureId
|
||||
)
|
||||
} else {
|
||||
// Normal completion: remove by agentIndex
|
||||
newAgents = prev.activeAgents.filter(
|
||||
a => a.agentIndex !== message.agentIndex
|
||||
)
|
||||
}
|
||||
} else if (existingAgentIdx >= 0) {
|
||||
// Update existing agent
|
||||
newAgents = [...prev.activeAgents]
|
||||
@@ -411,6 +420,27 @@ export function useProjectWebSocket(projectName: string | null) {
|
||||
}
|
||||
}, [projectName, connect, sendPing])
|
||||
|
||||
// Defense-in-depth: cleanup stale agents for users who leave UI open for hours
|
||||
// This catches edge cases where completion messages are missed
|
||||
useEffect(() => {
|
||||
const STALE_THRESHOLD_MS = 30 * 60 * 1000 // 30 minutes
|
||||
|
||||
const cleanup = setInterval(() => {
|
||||
setState(prev => {
|
||||
const now = Date.now()
|
||||
const fresh = prev.activeAgents.filter(a =>
|
||||
now - new Date(a.timestamp).getTime() < STALE_THRESHOLD_MS
|
||||
)
|
||||
if (fresh.length !== prev.activeAgents.length) {
|
||||
return { ...prev, activeAgents: fresh }
|
||||
}
|
||||
return prev
|
||||
})
|
||||
}, 60000) // Check every minute
|
||||
|
||||
return () => clearInterval(cleanup)
|
||||
}, [])
|
||||
|
||||
// Clear logs function
|
||||
const clearLogs = useCallback(() => {
|
||||
setState(prev => ({ ...prev, logs: [] }))
|
||||
|
||||
Reference in New Issue
Block a user