Fix agentd top: filtering, alignment, real-time updates, drill-down

t-457·WorkTask·
·
·
Created1 month ago·Updated1 month ago

Description

Edit

Fix agentd top TUI dashboard - multiple issues with current implementation.

Current Issues

1. Shows all agents, not just running

getRunningAgents returns completed/failed agents too. Should default to running only, with --all flag to show everything.

2. Columns don't align

Uses B.padRight (B.Pad 2) which adds 2 spaces after variable-length content. Columns don't line up.

run-abc123  Running  5 iterations  -  1.23¢
run-xyz  Completed  42 iterations  -  15.67¢

Should use B.hLimit for fixed-width columns:

run-abc123              Running     5 iters     -         1.23¢
run-xyz                 Completed   42 iters    -         15.67¢

3. No real-time updates

The TUI loads agents once at startup and never refreshes. Should poll every few seconds or use file watching.

4. Can't drill into agent logs

Pressing Enter on a selected agent should switch to log-tailing view (like agentd watch). Currently does nothing.

Fixes Required

Filter running agents by default

getRunningAgents workspace showAll = do
  ...
  let filtered = if showAll 
        then results 
        else filter (\a -> aiStatus a == "Running") results
  pure filtered

Add --all flag to topParser.

Fixed-width columns

renderAgent selected agent =
  style <|
    B.hBox
      [ B.hLimit 24 <| B.padRight B.Max (B.txt <| aiRunId agent),
        B.hLimit 10 <| B.padRight B.Max (B.txt <| aiStatus agent),
        B.hLimit 14 <| B.padRight B.Max (B.txt <| aiDuration agent),
        B.hLimit 10 <| B.padRight B.Max (B.txt <| fromMaybe "-" (aiTokens agent)),
        B.hLimit 10 <| B.padRight B.Max (B.txt <| fromMaybe "-" (aiCost agent)),
        B.txt <| fromMaybe "-" (aiCurrentActivity agent)
      ]

Same for header row.

Real-time updates

Use Brick's BChan for custom events with a background thread:

runTop workspace = do
  chan <- BChan.newBChan 10
  
  -- Background thread polls every 2 seconds
  _ <- forkIO <| forever <| do
    threadDelay 2000000
    agents <- getRunningAgents workspace False
    BChan.writeBChan chan (AgentsUpdated agents)
  
  let app = B.App
        { ...
          B.appHandleEvent = handleTopEvent workspace chan,
          ...
        }
  
  let buildVty = Vty.mkVty Vty.defaultConfig
  initialVty <- buildVty
  _ <- B.customMain initialVty buildVty (Just chan) app initialState
  pure ()

Enter to drill into logs

handleTopEvent workspace event = do
  case event of
    B.VtyEvent (VtyEvents.EvKey VtyEvents.KEnter []) -> do
      state <- B.get
      case BList.listSelectedElement (tsAgents state) of
        Nothing -> pure ()
        Just (_, agent) -> do
          -- Switch to watch mode for this agent
          B.suspendAndResume <| do
            runWatch (Text.unpack <| aiRunId agent) False
            pure state
    ...

Or switch to a split view with list on top, logs on bottom.

Success Criteria

  • [ ] Default view shows only running agents
  • [ ] --all flag shows completed/failed too
  • [ ] Columns align properly with fixed widths
  • [ ] Dashboard updates every 2-3 seconds
  • [ ] Enter key drills into selected agent's logs
  • [ ] 'q' or Escape returns to list (if in drill-down mode)
  • [ ] Shows "No running agents" when list is empty

Timeline (2)

🔄[human]Open → InProgress1 month ago
🔄[human]InProgress → Done1 month ago