Skip to content

fix(desktop): report agent presence from the relay, not the profile default - #4537

Open
mikececco wants to merge 1 commit into
block:mainfrom
mikececco:fix/agent-roster-presence
Open

fix(desktop): report agent presence from the relay, not the profile default#4537
mikececco wants to merge 1 commit into
block:mainfrom
mikececco:fix/agent-roster-presence

Conversation

@mikececco

Copy link
Copy Markdown

Problem

agents_from_events fills in a default when a kind:10100 agent profile has no
status string:

// desktop/src-tauri/src/nostr_convert.rs
if !obj.get("status").is_some_and(Value::is_string) {
    obj.insert("status".to_string(), json!("offline"));
}

Nothing in-tree ever writes that field — the only in-tree writer of kind:10100
is cmd_set_add_policy, which sets channel_add_policy — so the fallback is
taken for every relay-discovered agent
. The Pulse roster then builds its status
map straight off it:

for (const a of relayAgents) {
  map[a.pubkey] = a.status;   // always "offline" for relay-discovered agents
}

So a running agent is reported offline. The only agents that showed a real state
were locally-managed ones, whose status the view synthesizes from the local
process handle.

Meanwhile the relay already tracks genuine presence — kind:20001 events behind
a 180s Redis TTL, surfaced to the client by usePresenceQuery. The two were
simply never joined.

Change

Join them, with presence taking precedence wherever it has an entry.

Agents absent from the presence lookup keep their incoming status. That is
deliberate: locally-managed agents derive theirs from the live process handle,
which is authoritative for the machine running them and isn't something the
relay should override. It also makes the merge a no-op before the presence query
resolves, so the roster never flickers to offline on load.

The merge itself is a pure function (agents/lib/agentPresenceStatus.ts) rather
than inline logic, so it is unit-testable and reusable by the other roster
surfaces (useMentions, useNewMessageRecipients, useTrayMenu) in follow-ups.

Scope

Deliberately narrow: this changes only status truthfulness, not rendering.
I've kept away from the roster/fleet UI in #3996 and #4169 since several PRs are
already in flight there — this composes with whichever lands rather than
competing with it. The most substantive comment on #3996 asks for exactly this
("derive online/offline from presence/heartbeat facts, not a static profile
field"), and as far as I can tell none of the open PRs do it.

Tests

Six cases in agentPresenceStatus.test.mjs:

  • live presence overrides the kind:10100 offline fallback (the bug)
  • away is preserved, not flattened to online/offline
  • agents with no presence entry keep their own status
  • presence for an unrelated pubkey doesn't leak in
  • an unloaded (undefined) lookup is a no-op
  • presence can also correct a stale "online" handle to offline

Green locally:

  • just desktop-check — pass
  • just desktop-test — 3934 pass, 0 fail

UI note

No visual/layout change — the same status indicator now reflects real presence
instead of a constant. Happy to attach a before/after of the Pulse agents tab if
that's wanted for review.

Refs #3996, #4169

…efault

`agents_from_events` fills in `status: "offline"` whenever a kind:10100 agent
profile does not carry a status string. Nothing in-tree ever writes that field
— the only in-tree writer of kind:10100 sets `channel_add_policy` — so the
fallback is taken for every relay-discovered agent, and the Pulse roster
reported agents as offline whether or not they were running.

Meanwhile the relay already tracks real presence: kind:20001 events backed by
a Redis TTL, exposed to the client through `usePresenceQuery`. The two were
never joined; the roster built its status map straight off the profile field.

Join them, preferring presence where it has an entry. Agents absent from the
lookup keep their incoming status, so locally-managed agents continue to use
the live process handle — authoritative for the machine running them, and not
something the relay can contradict.

The merge is a pure function in `agents/lib/agentPresenceStatus.ts` with unit
tests covering the offline-fallback override, away, missing entries, unrelated
pubkeys, an unloaded lookup, and presence correcting a stale "online" handle.

Refs block#3996, block#4169

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Mike Cecconello <mikececco2000@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant