diff --git a/frontend/src/features/agents/hooks/useAgentDrillDown.js b/frontend/src/features/agents/hooks/useAgentDrillDown.js index 46474d0..a3dca03 100644 --- a/frontend/src/features/agents/hooks/useAgentDrillDown.js +++ b/frontend/src/features/agents/hooks/useAgentDrillDown.js @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback, useRef } from 'react'; import { getAgents, getSessionMessages, @@ -145,51 +145,14 @@ setTriggers(tList); } catch(e) {} - const sid = found.session?.sync_workspace_id || found.session_id; - const nodeId = found.mesh_node_id || "hub"; - - if (sid) { - try { - const cFilesListing = await getAgentCortexFiles(agentId, nodeId, sid); - const files = cFilesListing.files || []; - setCortexFiles(files); - - const fileExists = (name) => files.some(f => f.name === name || f.path === `.cortex/${name}`); - - if (fileExists("feedback.md")) { - try { - const feedback = await getAgentCortexFile(agentId, nodeId, sid, "feedback.md"); - setFeedbackContent(feedback?.content || ""); - } catch (e) {} - } - - if (fileExists("rubric.md")) { - try { - const rubric = await getAgentCortexFile(agentId, nodeId, sid, "rubric.md"); - setRubricContent(rubric?.content || ""); - } catch (e) {} - } - - try { - const coworker = await getAgentCortexFile(agentId, nodeId, sid, ".coworker.md"); - setCoworkerContent(coworker?.content || ""); - } catch (e) {} - - if (fileExists("history.log")) { - try { - const logs = await getAgentCortexFile(agentId, nodeId, sid, "history.log"); - if (logs?.content) { - try { - const parsed = JSON.parse(logs.content); - setHistoryLog(Array.isArray(parsed) ? parsed : []); - } catch (e) { - setHistoryLog(logs.content.split('\n').filter(l => l.trim()).map(line => ({ message: line }))); - } - } - } catch (e) {} - } - } catch (e) {} + // Cortex files (feedback, rubric, history) are fetched separately + // only when agent transitions to idle, to avoid blocking gRPC during active runs. + const isActive = found.status === 'active' || found.status === 'starting'; + const wasActive = prevStatusRef.current === 'active' || prevStatusRef.current === 'starting'; + if (!isActive && (wasActive || prevStatusRef.current === null)) { + fetchCortexFiles(found); } + prevStatusRef.current = found.status; } catch (err) { setError(err.message); } finally { @@ -229,6 +192,56 @@ loadConf(); }, []); + // Separate cortex file fetch so blocking gRPC calls don't run every 2.5s + const fetchCortexFiles = useCallback(async (found) => { + const sid = found.session?.sync_workspace_id || found.session_id; + const nodeId = found.mesh_node_id || "hub"; + if (!sid) return; + try { + const cFilesListing = await getAgentCortexFiles(agentId, nodeId, sid); + const files = cFilesListing.files || []; + setCortexFiles(files); + + const fileExists = (name) => files.some(f => f.name === name || f.path === `.cortex/${name}`); + + if (fileExists("feedback.md")) { + try { + const feedback = await getAgentCortexFile(agentId, nodeId, sid, "feedback.md"); + setFeedbackContent(feedback?.content || ""); + } catch (e) {} + } + + if (fileExists("rubric.md")) { + try { + const rubric = await getAgentCortexFile(agentId, nodeId, sid, "rubric.md"); + setRubricContent(rubric?.content || ""); + } catch (e) {} + } + + try { + const coworker = await getAgentCortexFile(agentId, nodeId, sid, ".coworker.md"); + setCoworkerContent(coworker?.content || ""); + } catch (e) {} + + if (fileExists("history.log")) { + try { + const logs = await getAgentCortexFile(agentId, nodeId, sid, "history.log"); + if (logs?.content) { + try { + const parsed = JSON.parse(logs.content); + setHistoryLog(Array.isArray(parsed) ? parsed : []); + } catch (e) { + setHistoryLog(logs.content.split('\n').filter(l => l.trim()).map(line => ({ message: line }))); + } + } + } catch (e) {} + } + } catch (e) {} + }, [agentId]); + + // Track previous status to detect transitions to idle + const prevStatusRef = useRef(null); + useEffect(() => { fetchData(); const interval = setInterval(fetchData, 2500);