Skip to content

fix(desktop): preserve agent model/provider when persona snapshot fields are blank#1583

Merged
wpfleger96 merged 3 commits into
mainfrom
wpfleger/persona-blank-fallback
Jul 7, 2026
Merged

fix(desktop): preserve agent model/provider when persona snapshot fields are blank#1583
wpfleger96 merged 3 commits into
mainfrom
wpfleger/persona-blank-fallback

Conversation

@wpfleger96

@wpfleger96 wpfleger96 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Bug

For agents linked to a persona via "Inherit runtime from persona", the desktop backend re-snapshots the persona onto the agent record at every start and every app-launch restore. The existing code used `persona_snapshot` which unconditionally assigned `snapshot.model` and `snapshot.provider` to the agent record. When the persona has no configured `model`/`provider` (both fields are `Option` and default to `None`), the blank values clobbered whatever model and provider the user had set on the agent. The readiness gate then immediately flagged the agent as needing configuration — a loop that restarted on every app open.

Fix

New helper `persona_field_with_record_fallback` in `persona_events.rs` is the single source of truth for the precedence rule: persona field wins when non-blank (trimmed), otherwise falls back to the record's own field (also blank-normalized). Both-blank stays `None` so a genuinely unconfigured agent still reads as needing setup.

Five call sites updated across three paths:

  • Snapshot path (`persona_snapshot_with_agent_config_fallback`): refactored to delegate env-merge/`system_prompt`/`source_version` to `persona_snapshot` and apply the shared helper for `model`/`provider`. Three call sites — agent start (`start_local_agent_with_preflight`), restore backfill (`backfill_persona_snapshots`), and app-launch restore (`restore_managed_agents_on_launch`).
  • Deploy path (`build_deploy_payload`): was using `persona.model.or(record.model)` with no blank normalization and dropped `record.provider` entirely when the persona had a blank provider. Provider-backend agents with a blank persona provider now correctly deploy with the record's configured provider.
  • Display path (`resolve_effective_prompt_model_provider`): was returning live persona fields with no record fallback, so the config/display surface could show an agent as needing configuration while the spawn path ran it with the record's values. Now matches spawn behavior.

`env_vars` finding

The `persona_snapshot` env-var layering was already correct: persona env is cloned first, then agent overrides are inserted on top — agent keys always win on collision. A persona with an empty env map does not wipe the agent's env vars. No clobber exists in the env path; layering is untouched.

…lds are blank

When a persona has no configured model/provider, the existing re-snapshot
logic unconditionally wrote the blank values onto the agent record at every
spawn and app-launch restore. This clobbered any values the user had set on
the agent, and the readiness gate would immediately flag the agent as needing
configuration — a loop users could not escape.

Fix: add `persona_snapshot_with_agent_config_fallback` which applies the same
persona-wins precedence for non-blank values but preserves the agent record's
existing model/provider when the persona leaves them blank. Swap all three
call sites (agent start, restore backfill, restore re-snapshot). Both-blank
stays None so a genuinely unconfigured agent still reads as needing setup.

@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.

Approve — clean, minimal, correct. (Review by Brain, posted via Wes's account.)

  • persona_snapshot_with_agent_config_fallback does exactly what the title says: persona wins when non-blank, agent record preserved when persona is blank, both-blank stays None, source_version always refreshed. Whitespace-only correctly treated as blank.
  • All three re-snapshot call sites (start preflight, backfill, launch restore) converted; the create-time path correctly keeps plain persona_snapshot — its blank-persona fallback already happens via snapshot_model.or_else(input.model), so no double-fallback.
  • The env-var finding in the description checks out in the code: agent overrides merge after persona env, so no clobber existed there.
  • 5 unit tests cover every branch incl. whitespace and env layering.
  • check-file-sizes.mjs bump is +4 lines on an already-overridden file with justification, consistent with that file's convention.

… deploy/display paths

Introduce `persona_field_with_record_fallback` in `persona_events.rs` as the
single source of truth for the precedence rule: persona field wins when
non-blank (trimmed), otherwise falls back to the record's own field (also
blank-normalized). Three paths previously duplicated or lacked this rule:

- `persona_snapshot_with_agent_config_fallback`: refactored to call
  `persona_snapshot` for env/system_prompt/source_version, then patch
  model/provider via the shared helper — future PersonaSnapshot field
  additions stay consistent automatically.
- `build_deploy_payload`: was using `persona.model.or(record.model)` with no
  blank normalization and dropped `record.provider` entirely when the persona
  had a blank provider. Provider-backend agents with a blank persona provider
  now correctly deploy with the record's configured provider.
- `resolve_effective_prompt_model_provider`: was returning live persona fields
  with no record fallback, so the config/display surface could show an agent
  as unconfigured while the spawn path ran it with the record's values. Now
  matches spawn behavior by applying the same precedence rule.

Also: extend `backfill_persona_snapshots` doc comment to note already-snapshotted
records (persona_source_version set) self-heal on next manual start; add inline
fallback-arg comments at all three call sites; update file-size overrides.
…t fallback

The two fields (model, provider) are independent in the fallback rule — a
persona that sets only model wins on model while the agent's provider is
preserved, and vice versa. This is the practically common case (model-only
personas). Add two tests pinning both directions of the asymmetric cross-field
case so regression in either field's independence is immediately visible.
@wpfleger96 wpfleger96 merged commit a3ee2c5 into main Jul 7, 2026
21 checks passed
@wpfleger96 wpfleger96 deleted the wpfleger/persona-blank-fallback branch July 7, 2026 16:49
tellaho added a commit that referenced this pull request Jul 7, 2026
…ivity

* origin/main:
  fix(desktop): hydrate reactions for Inbox context messages (#1596)
  fix: cleanup old screenshots that my agents committed (#1598)
  chore(release): release Buzz Desktop version 0.3.46 (#1585)
  fix(desktop): preserve agent model/provider when persona snapshot fields are blank (#1583)
  feat(acp,desktop): identify and reap stale agent harness processes (#1582)
  feat(desktop): active-draft badge, send-from-drafts confirm dialog, thread-deleted state (#1581)
  fix(desktop): treat baked build env vars as satisfying required agent config (#1580)
  feat(desktop): add "Copy image" to image right-click context menu (#1579)
  fix(nest): use buzz-dev symlink name for dev builds (#1587)
  fix(composer): address image-editor follow-up nits on #1491 (#1565)
  fix(desktop): render black static boot screen (#1570)
  feat(agents): group activity tool bursts (#1571)
  feat(desktop): aggregated overview rail, commit detail page, and full breadcrumbs (#1573)
  fix(desktop): fetch profiles for reaction actors and thread-reply authors (#1550)
  refactor(desktop): unify EditAgentDialog styling with PersonaDialog (#1540)
  feat(desktop): add 10-minute message grouping window (#1578)
  feat(desktop): unify sidebar section actions into a per-section ⋮ menu (#1577)
  feat(desktop): emoji avatar picker for agents + reliable picker scroll (#1576)

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
tlongwell-block pushed a commit that referenced this pull request Jul 7, 2026
* origin/main:
  docs(readme): add Getting started section routing install paths (#1606)
  fix(desktop): restrict shared-agent sync to dev data dirs (#1597)
  feat(desktop): restart-required badge from spawn-time config hash (#1602)
  feat(desktop): boot-time reconcile of managed agents to relay events (#1601)
  feat(desktop): canonical <PubKey> component — hover to view/copy full keys, owner "you" labels (#1589)
  fix(desktop): hydrate reactions for Inbox context messages (#1596)
  fix: cleanup old screenshots that my agents committed (#1598)
  chore(release): release Buzz Desktop version 0.3.46 (#1585)
  fix(desktop): preserve agent model/provider when persona snapshot fields are blank (#1583)
  feat(acp,desktop): identify and reap stale agent harness processes (#1582)
  feat(desktop): active-draft badge, send-from-drafts confirm dialog, thread-deleted state (#1581)
  fix(desktop): treat baked build env vars as satisfying required agent config (#1580)
  feat(desktop): add "Copy image" to image right-click context menu (#1579)
  fix(nest): use buzz-dev symlink name for dev builds (#1587)
  fix(composer): address image-editor follow-up nits on #1491 (#1565)
  fix(desktop): render black static boot screen (#1570)
  feat(agents): group activity tool bursts (#1571)
  feat(desktop): aggregated overview rail, commit detail page, and full breadcrumbs (#1573)
  fix(desktop): fetch profiles for reaction actors and thread-reply authors (#1550)
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