fix(desktop): send complete respond_to wire patch on every allowlist transition - #4270
fix(desktop): send complete respond_to wire patch on every allowlist transition#4270iroiro147 wants to merge 1 commit into
Conversation
…transition
The agent instance edit dialog gated the allowlist payload on
`submitMode === "allowlist" && listChanged`, silently dropping the payload
in two reachable shapes:
1. Mode flip to allowlist with a list that happens to match the persisted
record (e.g. anyone → allowlist where the list was populated in an
earlier session): the mode flips but the harness never receives the
full `{mode, allowlist}` tuple atomically, so the agent stays
unreachable to the intended members.
2. Mode flip to allowlist with a fresh list was covered only because the
two gates happened to coincide.
The reporter (block#2501) observed the visible symptom as "UI edits don't
stick" — the UI wrote `definition_respond_to` (the snapshot projection)
but the harness reads from the record-level `respond_to` payload that the
dialog failed to send.
Extract a pure `computeRespondToWirePatch` helper in
`personaRuntimeModel.ts` that owns the contract end-to-end: send the
allowlist payload whenever the submitted mode is `allowlist` AND (mode
changed OR list changed); send the mode only when it changed. This is the
single canonical wire-shape producer; the dialog now spreads it into the
submit input. Six new pure-module tests pin each transition shape; the
behaviour is end-to-end exercised by `update_managed_agent`'s merge of
undefined mode/allowlist as "leave unchanged".
Fixes block#2501
Signed-off-by: Sarthak Singh <sarthak.singh@juspay.in>
|
Read the diff — 1. The "Rust path enforces the allowlist-non-empty invariant" note holds for this path, but not for the #4115 cascade path. Your reviewer note is accurate for But #4115 (your persona → instance cascade) reaches the record through a different Rust function, record.respond_to = match persona.respond_to.as_deref() {
Some(wire) => RespondTo::parse_wire(wire)?,
None => RespondTo::default(),
};
record.respond_to_allowlist = persona.respond_to_allowlist.clone();So a definition sitting in 2. Does this close MaxWynnDev's repro, or only the v0.4.23 transition-3 flow? Your reproduction (v0.4.23, transition 3) is exactly what the helper fixes. But the other #2501 repro (MaxWynnDev, v0.5.2) is "the list never persists at all, even on first save" — and on first save this dialog already sent the allowlist under the old gate ( Happy to build #4270 + #4115 together and run the end-to-end matrix (fresh allowlist; |
Summary
Fixes #2501.
The Desktop agent-instance edit dialog silently dropped the allowlist payload on two reachable mode transitions, so the
buzz-acpharness kept starting withrespond_to=owner-onlyregardless of what the UI showed. This made it impossible to share a custom agent with other community members through the UI — only a hand edit ofmanaged-agents.jsonworked.Root cause
The dialog gated the allowlist payload on
submitMode === "allowlist" && listChanged, conflating "mode changed" with "payload changed":{mode, allowlist}tuple atomically, so the record stays in a state the harness reads asowner-only.definition_respond_to(the definition snapshot projection) but the harness reads from the record-levelrespond_to+respond_to_allowlistthe dialog never sent. (update_managed_agentmergesundefinedallowlist as "leave unchanged", so the two states stayed out of sync permanently.)Fix
Extract a pure
computeRespondToWirePatchhelper inpersonaRuntimeModel.tsthat owns the full contract:respondToon the wire only when the mode changed.respondToAllowliston the wire wheneversubmitMode === "allowlist"AND (modeChangedORlistChanged) — so a mode flip to allowlist always carries the complete{mode, allowlist}tuple the harness needs, even when the list itself happens to match.The dialog now spreads the helper's return into the submit input — there is one canonical wire-shape producer instead of inline conditional logic.
Reproduction (from the issue)
Under Buzz Desktop v0.4.23 (macOS, Apple Silicon), custom agent, runtime
claude:respond_to=owner-only.Manual
managed-agents.jsonedit ofrespond_to+respond_to_allowlistfixes the agent permanently — the file is the source of truth; the dialog simply wasn't writing it on transition 3.Testing
desktop/src/features/agents/ui/agentInstanceEditRespondToWire.test.mjs— 6 tests covering the full transition matrix:pnpm exec tsc --noEmit: clean.RespondToModetype end-to-end so the wire shape is type-checked againstUpdateManagedAgentInput.Notes for reviewers
editValidity_allowlistWithEmptyList_blocksSavegate already prevents the crash-loop shape at the dialog.Signed-off-by: Sarthak Singh sarthak.singh@juspay.in