agentd: add updated_at timestamp to status JSON

t-764·WorkTask·
·
·
Created1 week ago·Updated1 week ago·pipeline runs →

Description

Edit

Goal

Enable pull-based notification workflow: on heartbeat, Ava runs agentd status --json | jq filtered/sorted by a timestamp that reflects the last time an agent's state changed, so we can detect 'new idle' vs 'already relayed idle' without a push notification subsystem.

Context

Ben's design (see recent Telegram thread with Ava): the agentd notification channel should be pull-based, not push-based. The heartbeat pattern will be something like:

agentd status --json | jq '.[] | select(.status == "idle") | select(.updated_at > $LAST_CHECK)' 

No need for mail/webhook subsystem.

What's missing

AgentInfo (intent/Omni/Agentd/Daemon.hs:224) currently has aiStartedAt and aiCompletedAt but no general 'last state change' timestamp. A long-running persistent agent that transitions running→idle→running→idle only updates started_at once and completed_at never (it doesn't complete), so there's no way to tell *when* it became idle.

Acceptance criteria

1. Add aiUpdatedAt :: Maybe Time.UTCTime field to AgentInfo in intent/Omni/Agentd/Daemon.hs (near aiStartedAt). 2. Add updated_at TEXT column to the agents table schema (intent/Omni/Agentd/Daemon.hs initDb ~line 346). Include a schema migration: ALTER TABLE agents ADD COLUMN updated_at TEXT guarded so re-running is safe. 3. Emit "updated_at" .= aiUpdatedAt info in the ToJSON instance (~line 285). 4. Update every UPDATE agents SET ... statement (lines 418, 425, 432, 440, 447, 454, 461, 468) to also set updated_at = ? with the current time. Easiest approach: add a helper touchUpdated :: SQL.Connection -> Text -> IO () and call it at every status/summary transition, OR add updated_at = ? to each existing UPDATE (and pass now as an extra parameter). 5. SELECT queries that build AgentInfo must populate aiUpdatedAt from the column. 6. Verify: spawn a persistent agent, let it go idle, confirm agentd status --json shows an updated_at that changes on each turn_end.

Out of scope

  • No new CLI flag on agentd status — we're using jq for filtering.
  • No changes to webhook/notification code (that's being deprecated).
  • No schema cleanup of started_at/completed_at (keep them).

Testing

  • Unit test (if there's a JSON encoding test) that updated_at serializes.
  • Manual: agentd run -n test-idle 'say hi then wait' → wait for idle → agentd status --json | jq '.[] | select(.run_id == "test-idle") | .updated_at' should be populated and more recent than started_at.

Git Commits

f4a2c7f5agentd: add updated_at to agent status model and DB updates
Coder Agent10 days ago1 files

Timeline (5)

🔄[human]Open → InProgress1 week ago
🔄[human]InProgress → Open1 week ago
💬[human]1 week ago

Implemented updated_at tracking for agent status in Omni/Agentd/Daemon.hs. Added aiUpdatedAt to AgentInfo and emitted updated_at in JSON. Added agents.updated_at schema column + ALTER migration. Updated AgentInfo SELECT/FromRow to load updated_at. Added touchUpdated helper and wired all agent-row mutations to refresh updated_at (status/summary/title/pid), with inline updated_at on started/completed transitions and persistent stop SQL. Also set updated_at on agent inserts. Added unit assertion that AgentInfo JSON includes updated_at key. Verified with typecheck.sh Omni/Agentd/Daemon.hs, bild Omni/Agentd/Daemon.hs, and bild --test Omni/Agentd/Daemon.hs.

🔄[human]Open → Review1 week ago