Skip to content

fix(desktop): sync agent relay profile when persona avatar changes#1512

Merged
klopez4212 merged 6 commits into
mainfrom
fix/persona-avatar-sync-to-agent-profile
Jul 6, 2026
Merged

fix(desktop): sync agent relay profile when persona avatar changes#1512
klopez4212 merged 6 commits into
mainfrom
fix/persona-avatar-sync-to-agent-profile

Conversation

@klopez4212

@klopez4212 klopez4212 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Problem

When editing a persona's avatar in the "Edit agent" dialog, the avatar change was saved to the persona record but the linked agent's relay profile (kind:0 event) was never re-synced. The agent card in the UI continued showing the old avatar because:

  1. Backend: update_persona saved the persona locally but never triggered sync_managed_agent_profile for linked agents, and never updated the agent record's avatar_url field.
  2. Frontend: The agent card prioritized the relay profile avatar (profileQuery.data?.avatarUrl) over the persona avatar (persona.avatarUrl), so the stale relay data won.

Fix

Backend (desktop/src-tauri/src/commands/personas/mod.rs)

  • After saving the persona, if the avatar changed, update all linked agent records' avatar_url field (with fallback to command-default icon when cleared, matching update_managed_agent)
  • Collect relay profile sync params and await re-publish of their kind:0 profiles (sequential, best-effort, outside the lock)
  • Uses the same pattern as update_managed_agent (sync params collected under lock, async publish outside)

Frontend (desktop/src/features/agents/ui/UnifiedAgentsSection.tsx)

  • Flip avatar priority: firstAvatarUrl(persona.avatarUrl, profileQuery.data?.avatarUrl)
  • The persona avatar (local source of truth) now takes precedence over the relay profile avatar (which may be stale)

Frontend (desktop/src/features/agents/hooks.ts)

  • Invalidate all user-profile and users-batch queries on persona update so the relay profile cache catches up after the backend sync

Testing

  • cargo check passes for the Tauri crate
  • Biome lint/format passes
  • All pre-push hooks pass (rust tests, desktop tests, mobile tests, desktop-tauri tests)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7089313851

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src-tauri/src/commands/personas/mod.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 91b3fdbb66

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src/features/agents/hooks.ts Outdated
klopez4212 added a commit that referenced this pull request Jul 5, 2026
The useUpdatePersonaMutation already invalidated user-profile queries after
a persona avatar change, but channel timelines and member lists use
useUsersBatchQuery with a 60s staleTime. Without invalidating users-batch,
those surfaces show the stale avatar until the batch query naturally
refetches.

Addresses the outstanding Codex review comment on PR #1512.

Signed-off-by: Kenny Lopez <kenny@block.xyz>
@klopez4212
klopez4212 requested a review from wesbillman July 5, 2026 06:48

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the full diff against the sibling paths it mirrors. The core fix is correct and well-structured:

  • Backend faithfully follows the update_managed_agent two-phase pattern (agent_models.rs:800-984): sync params collected under managed_agents_store_lock inside spawn_blocking, publish after the lock drops — no .await under the guard. ✅
  • Persisting record.avatar_url before publishing keeps startup reconciliation (reconcile_agent_profile) in agreement with the published kind:0, so nothing fights back on next launch. ✅
  • The frontend priority flip (persona wins over relay profile) matches the codebase's documented philosophy — resolve_legacy_avatar in commands/agents.rs already states the persona avatar is authoritative because the relay is an unreliable source for persona-backed agents. ✅
  • The user-profile/users-batch predicate invalidation matches the existing pattern in features/profile/hooks.ts. ✅

A few notes, in descending order of importance:

1. Clearing the persona avatar leaves a restart-dependent state (worth fixing in this PR)

When the user clears the avatar, trim_optional yields None, so this path sets record.avatar_url = None and publishes a kind:0 with no picture. But avatar_url: None is exactly the legacy pre-PR-921 sentinel: on next startup, reconcile_agent_profile treats the record as un-migrated, backfills the command-default icon, and re-publishes. Net behavior: clear → blank avatar until restart → command icon after restart.

The sibling paths all resolve a fallback instead of persisting None:

  • update_managed_agent (agent_models.rs ~938): record.avatar_url.clone().or_else(|| managed_agent_avatar_url(&effective_command))
  • resolve_created_avatar_url (commands/agents.rs ~185): same chain.

Suggest mirroring that here — when the persona avatar is cleared, fall back to managed_agent_avatar_url(&effective_command) for the linked agent records and the published profile, so clear-avatar is deterministic instead of restart-dependent.

2. Awaited sync with no HTTP timeout (fine as a follow-up)

Phase 2 awaits one sync_managed_agent_profile per linked agent, sequentially, and AppState.http_client (app_state.rs:89) sets no request timeout — a hung relay stalls the Save mutation indefinitely, multiplied by the number of linked agents. update_managed_agent has the same exposure, so this is consistent rather than a regression; a client-level timeout (or join_all) would fix both paths at once and is better done as its own change.

3. Cosmetic

  • The error log here reuses sync_managed_agent_profile's baked-in "Created the agent, but could not sync its profile metadata" message, which reads oddly on the update path (the rename path shares this wart).
  • The PR body still says "fire-and-forget" for phase 2, but the second commit correctly changed it to awaited — worth a one-line body edit so the description matches the code.

Only #1 changes user-visible behavior; #2 and #3 are follow-up/cosmetic.

klopez4212 added a commit that referenced this pull request Jul 6, 2026
…s cleared

When a persona avatar is cleared, trim_optional yields None. Previously
this None was propagated directly to linked agent records, which
reconcile_agent_profile interprets as "un-migrated legacy record" and
backfills with the command-default icon on next restart — making the
clear-avatar flow non-deterministic (blank until restart, then icon).

Apply the same or_else(managed_agent_avatar_url) fallback already used in
update_managed_agent so the agent record always stores a concrete URL.

Addresses review feedback from wesbillman on PR #1512.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 096a7ac395

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src-tauri/src/commands/personas/mod.rs
@klopez4212

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review @wesbillman!

#1 (clear-avatar fallback): Fixed in 096a7ac — when the persona avatar is cleared, linked agent records now fall back to managed_agent_avatar_url(&effective_command) instead of storing None, mirroring the pattern in update_managed_agent. Deterministic immediately, no restart dependency.

#2 (HTTP timeout): Agreed this is pre-existing and consistent — will address in a follow-up with a client-level timeout or join_all.

#3 (cosmetic): Will fix the error log wording and PR body description in a follow-up.

When editing a persona's avatar, the linked agents' relay profiles were
never re-synced — the kind:0 event still showed the old picture URL.

Backend: After saving the persona, if the avatar changed, update linked
agent records' avatar_url and fire-and-forget re-publish their kind:0
profiles to the relay.

Frontend: Flip avatar priority in the agent card to prefer the persona
avatar (local source of truth) over the relay profile avatar (which may
be stale after an edit). Also invalidate user-profile queries on persona
update so the relay cache catches up.

Fixes: avatar not updating when changing agent profile image
The fire-and-forget spawn allowed the command to return before the relay
profile was updated, causing the frontend cache invalidation to refetch
stale data. Await the sync inline (matching update_managed_agent's pattern)
so the mutation settlement sees the fresh relay profile.
The useUpdatePersonaMutation already invalidated user-profile queries after
a persona avatar change, but channel timelines and member lists use
useUsersBatchQuery with a 60s staleTime. Without invalidating users-batch,
those surfaces show the stale avatar until the batch query naturally
refetches.

Addresses the outstanding Codex review comment on PR #1512.

Signed-off-by: Kenny Lopez <kenny@block.xyz>
…s cleared

When a persona avatar is cleared, trim_optional yields None. Previously
this None was propagated directly to linked agent records, which
reconcile_agent_profile interprets as "un-migrated legacy record" and
backfills with the command-default icon on next restart — making the
clear-avatar flow non-deterministic (blank until restart, then icon).

Apply the same or_else(managed_agent_avatar_url) fallback already used in
update_managed_agent so the agent record always stores a concrete URL.

Addresses review feedback from wesbillman on PR #1512.
@klopez4212
klopez4212 force-pushed the fix/persona-avatar-sync-to-agent-profile branch from 096a7ac to b77e3fe Compare July 6, 2026 14:41

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b77e3fe62e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src/features/agents/hooks.ts
…sona update

When a persona avatar changes, the per-pubkey users-batch-entry cache
entries for linked agents must be evicted before invalidating the
aggregate users-batch queries. Otherwise the batch refetch resolves
from stale 60s-fresh entries, leaving message timelines and member
lists showing the old avatar.

Mirrors the eviction pattern in useUpdateManagedAgentMutation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c588102fd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src/features/agents/hooks.ts
Renovate's lockfile regen for chrono 0.4.45 (#1050) also downgraded
windows-core 0.62.2 -> 0.61.2 (and windows-link/windows-result) for
iana-time-zone, wmi, and generator. wmi 0.18.4 uses windows 0.62.2,
which cannot compile against windows-core 0.61.2, breaking the
Windows Rust job on main. Chrono stays at 0.4.45.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@klopez4212
klopez4212 merged commit ce901f7 into main Jul 6, 2026
29 checks passed
@klopez4212
klopez4212 deleted the fix/persona-avatar-sync-to-agent-profile branch July 6, 2026 15:30
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.

2 participants