Skip to content

fix(desktop): connect managed agents with the configured relay URL, not the canonical identity URL - #4859

Open
anilkishan wants to merge 2 commits into
block:mainfrom
anilkishan:fix/agent-relay-connection-url
Open

fix(desktop): connect managed agents with the configured relay URL, not the canonical identity URL#4859
anilkishan wants to merge 2 commits into
block:mainfrom
anilkishan:fix/agent-relay-connection-url

Conversation

@anilkishan

Copy link
Copy Markdown

Summary

Desktop-managed agents can silently connect to a different relay community than the owner's desktop, discover 0 channels, and sit idle forever — never replying to mentions.

Root cause: two normalizers deliberately disagree about host equivalence, and the spawn path mixes them up.

  • buzz_core::relay::normalize_relay_url (the identity normalizer) folds all loopback spellings to 127.0.0.1 to build the stable (pubkey, relay_url) runtime key. Its doc comment explicitly says connection code should retain the configured URL.
  • buzz_core::tenant::normalize_host (the tenancy normalizer) does not collapse localhost vs 127.0.0.1 — distinct spellings are distinct communities, and the relay fails closed on unmapped hosts.

spawn_agent_child violates the first normalizer's contract: it sets the child's BUZZ_RELAY_URL from the canonical runtime_key.relay_url instead of the configured URL. So an agent configured against ws://localhost:3000 is spawned against ws://127.0.0.1:3000, binds to the wrong (often empty) community, and goes deaf.

The fix keeps the two roles separate, per normalize_relay_url's documented intent:

  • Connection: spawn_agent_child now uses the configured relay URL (trimmed) for the child's BUZZ_RELAY_URL. All three call sites (start_managed_agent_process, start_pair, launch restore) already have the configured URL in scope and now pass it through.
  • Identity & drift: the runtime key and the spawn-config snapshot still use the canonical key.relay_url. The restart-drift check recomputes the prospective snapshot with key.relay_url, so the spawn-time stamp must agree — otherwise agents restart-loop whenever the configured spelling differs from the canonical one.

No identity migration: existing (pubkey, relay_url) runtime keys are unchanged.

Related issue

Fixes #2444, #3283, #3505, #4147.

Closest existing PR: #4345 addresses the same symptom by changing normalize_relay_url to fold loopback to localhost instead of 127.0.0.1. That helps the common dev seed, but (a) it only covers loopback spellings while tenancy is host-derived for all hosts, and (b) changing the identity normalizer rewrites existing runtime keys on upgrade. This PR instead fixes the layer that violates the documented contract and covers non-loopback spelling differences too. Happy to coordinate with the author if maintainers prefer that direction.

Testing

  • New unit test agent_connection_preserves_loopback_authority covering the connection-URL helper.
  • just desktop-tauri-test (full cargo test --workspace in desktop/src-tauri, 2,200+ tests) passes.
  • just desktop-tauri-clippy and cargo fmt --check clean.
  • This exact fix has been running in production on a self-hosted macOS deployment (relay with host-derived multi-community rows) from v0.4.26 through v0.5.4: agents connect to the correct community, no restart loops, and the restart-drift badge behaves.

…ot the canonical identity URL

Managed agents were spawned with BUZZ_RELAY_URL set to the canonical
(pubkey, relay_url) identity URL from normalize_relay_url, which folds
loopback spellings to 127.0.0.1. Relay tenancy is host-derived and does
NOT fold spellings, so an agent configured against ws://localhost:PORT
connected to the ws://127.0.0.1:PORT community instead — discovering 0
channels and sitting idle (block#2444, block#3283, block#3505, block#4147).

Pass the configured relay URL through to the child connection at all
three spawn call sites, keeping the canonical key URL for runtime
identity and for the spawn-config snapshot (the restart-drift check
recomputes with key.relay_url, so the stamp must agree or agents
restart-loop when the spellings differ).

Signed-off-by: anilkishan <10408515+anilkishan@users.noreply.github.com>
@anilkishan
anilkishan requested a review from a team as a code owner August 5, 2026 08:00

@Chessing234 Chessing234 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

connecting with the configured relay url while identity/snapshot stay on canonical key.relay_url matches the tenancy vs identity split. any leftover call site that still builds the connect URL from the identity spelling?

Review follow-up on the same tenancy-vs-identity split: the relay-access
probe built its HTTP base from the canonical key spelling (probing a
different or unmapped community than the one being configured), and the
post-probe start passed the canonical spelling as the child's connection
URL. Both now use the requested URL; start_pair re-derives the same
canonical key, so identity is unchanged.

Signed-off-by: anilkishan <10408515+anilkishan@users.noreply.github.com>
@anilkishan

Copy link
Copy Markdown
Author

Good question — swept the desktop crate for key.relay_url / runtime_key.relay_url flowing into connection paths. Three leftovers turned up:

  1. Relay-access probeprobe_agent_relay_access (runtime_commands.rs) built its HTTP api_base from key.relay_url, so the probe could query a different (or unmapped) community than the one being configured. Fixed in 5e028af: probe with requested_relay_url (already in scope).

  2. Post-probe start — the success arm passed key.relay_url into start_pair, so the child spawned right after a successful probe still connected with the canonical spelling. Fixed in 5e028af: pass the requested spelling through; start_pair re-derives the same canonical key, so identity is unchanged.

  3. Restart orchestrationset_global_agent_config and install_acp_runtime restarts rebuild start URLs from live runtime keys (.map(|key| key.relay_url)). By that point the configured spelling is gone — the runtime map only holds the canonical key. The proper fix is to persist the connection URL alongside the canonical key in the pair runtime/receipt and restart with it. That grows the diff (receipt schema + both restart paths), so I'd propose it as a follow-up unless you'd rather have it here. These two paths are no worse after this PR than before it: they restart with the canonical spelling, which is what every spawn did previously.

Identity and bookkeeping uses of key.relay_url (stop/teardown, receipts, status rows, the drift-check snapshot) are left canonical deliberately — that side of the split is working as intended.

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.

[Bug] Desktop 0.4.23 spawns managed agents on ws://127.0.0.1:3000 while the community uses ws://localhost:3000 - agents silently stop responding

2 participants