Three UX fixes for the agentd top TUI dashboard (Omni/Agentd.hs):
Currently only KUp/KDown arrow keys move the cursor (lines ~3270-3273). Add j/k as aliases:
B.VtyEvent (VtyEvents.EvKey (VtyEvents.KChar 'j') []) ->
B.modify <| \s -> s {tsAgents = BList.listMoveDown (tsAgents s)}
B.VtyEvent (VtyEvents.EvKey (VtyEvents.KChar 'k') []) -> ...
BUT: 'k' is already bound to 'kill agent'. Need to resolve conflict. Options:
Preferred: move kill to 'K' (uppercase), free up 'k' for up navigation.
showTopAgentWatch (line ~3102) uses Async.race watchAction (void IO.getLine) — pressing Enter exits, ^C kills the whole process.
Fix: catch SIGINT/UserInterrupt in the watch action so ^C exits the watch but returns control to brick TUI. Something like:
showTopAgentWatch :: AgentInfo -> IO ()
showTopAgentWatch agent = do
let runId = aiRunId agent
watchAction = case aiKind agent of
TopOneshot -> runOneshotWatch [Text.unpack runId] False
TopPersistent -> runPersistentWatch [runId] False
TextIO.putStrLn <| "Watching " <> runId <> " (^C or Enter to return to dashboard)..."
result <- try @AsyncException (Async.race watchAction (void IO.getLine))
case result of
Left UserInterrupt -> pure () -- ^C caught, return to dashboard
Left e -> throwIO e
Right _ -> pure ()
The key is suspendAndResume in brick already handles screen state — we just need to not propagate the interrupt up.
The summary system uses a fingerprint (aiActivityFingerprint) to decide if a cached summary is stale. The fingerprint is built from status + last 8 thinking labels + last 8 tool labels (buildActivityFingerprint).
Problem: the cache is ONLY invalidated when the fingerprint changes. If the agent is doing repetitive work (same tool labels repeatedly), the fingerprint never changes so summary never refreshes. Even if time passes.
Fix options:
(fingerprint, summary, cachedAt) — invalidate if > 30 seconds old AND agent is activeTopState: force re-summary every 30s regardless of fingerprint for active agentstsSummaryLastRefresh :: Map.Map Text UTCTime and skip re-summarization if refreshed within 30s, but ALWAYS re-summarize after 30s even if fingerprint unchangedRecommend: add timestamp to cache tuple and check age. In activitySummaryIsCurrent, return False if cached > 30s ago and agent is active.
Omni/Agentd.hs (live branch) — all three issues are in this fileNo activity yet.