Skip to content

fix(desktop): connect managed agents to the configured relay, not the normalized loopback identity - #4664

Closed
spkaplan wants to merge 1 commit into
block:mainfrom
spkaplan:pr-loopback-fix
Closed

fix(desktop): connect managed agents to the configured relay, not the normalized loopback identity#4664
spkaplan wants to merge 1 commit into
block:mainfrom
spkaplan:pr-loopback-fix

Conversation

@spkaplan

@spkaplan spkaplan commented Aug 4, 2026

Copy link
Copy Markdown

Summary

Two coupled defects in Desktop-managed agents on loopback-addressed local communities:

  1. Agents came up online but discovered 0 channels and sat idle whenever the workspace relay was addressed as localhost (the desktop default and the seeded local-dev community). They only worked when the community was addressed as 127.0.0.1.
  2. A permanent, un-clearable "Restart required" badge once (1) is fixed — no restart could settle it.

Root cause (shared). The relay is multi-tenant, keyed by the literal request Host, so localhost:3000 and 127.0.0.1:3000 are distinct communities with isolated channels/members. buzz_core::relay::normalize_relay_url intentionally folds all loopback spellings to 127.0.0.1 for the runtime identity key only — its own doc says:

Connection code may retain the configured URL; this canonical form is for identity, receipts, status and deduplication.

But the spawn path reused that normalized ManagedAgentRuntimeKey::relay_url as the child's actual BUZZ_RELAY_URL, so an agent for a community joined on localhost:3000 connected to the empty 127.0.0.1:3000 tenant: subscribe resolved 0 channels and the agent never woke.

Fix

In desktop/src-tauri/src/managed_agents/ (runtime.rs, runtime_commands.rs, restore.rs):

  • Connection: connect the child on the configured relay URL at the spawn sites, keeping the normalized ManagedAgentRuntimeKey solely as the dedup identity (receipts, pid files, logs). Honors normalize_relay_url's documented contract; no identity/dedup/receipts change.
  • Restart badge (corollary): needs_restart compares a SpawnConfigSnapshot stamped at spawn against one recomputed live (prospective_spawn_config_snapshot), and the recompute reads the relay from the normalized runtime-map key. Once the connection fix flips the spawn's effective_relay_url to the configured spelling, stamping the snapshot with it (localhost) while the recompute uses the normalized key (127.0.0.1) makes them mismatch forever. Stamp SpawnConfigInputs.relay_url with the normalized runtime_key.relay_url so both sides compare the same spelling.

Validation

Reproduced and verified end-to-end on a local self-hosted stack (relay on localhost:3000):

  • Before: agent log relay=ws://127.0.0.1:3000 -> "discovered 0 channel(s)" -> "no channel subscriptions resolved -- agent will sit idle".
  • After: same agent relay=ws://localhost:3000 -> "discovered 1 channel(s)" -> "subscribed to channel <spike>", and two managed agents (a Codex harness and a cursor-agent harness) each replied to an owner @mention in-channel. Restart badge clears on restart and stays clear.
  • Rebased onto current main; all pre-push hooks pass (branch-skew, desktop-check incl. file-size ratchet, rust-tests, desktop-test, mobile-test, desktop-tauri-checks = clippy + Tauri crate tests).

Test plan

  • Create a Desktop-managed agent in a community addressed as localhost:<port>, attach it to a channel, @mention it as owner — it should discover the channel and reply.
  • Confirm receipts / pid files / logs still key on the normalized (127.0.0.1) identity (no dedup regression across loopback spellings).
  • Edit the agent's config (e.g. instructions/model), confirm the "Restart required" badge appears, restart, confirm it clears and stays clear.

@spkaplan
spkaplan requested a review from a team as a code owner August 4, 2026 04:16

@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: c071752d1c

ℹ️ 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".

// joined on `localhost`, leaving it "online" but discovering 0 channels.
// `normalize_relay_url`'s own contract says connection code must retain the
// configured URL; this honors that.
let effective_relay_url = relay_url.to_string();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep restart hashes on a consistent relay URL

For relay URLs whose configured form differs from the normalized runtime key (the fixed localhost case, [::1], default ports, etc.), this raw assignment also changes the value stamped into process.spawn_config_hash; later build_managed_agent_summary recomputes the hash with key.relay_url (the normalized value), so a freshly started agent is reported as needs_restart immediately even though no config changed. Split the connection URL from the hash input, or make the summary recompute with the same configured URL.

Useful? React with 👍 / 👎.

…start badge

Buzz's relay is multi-tenant, keyed by the literal request Host, so
localhost:3000 and 127.0.0.1:3000 are distinct communities with isolated
channels/members. buzz-core::relay::normalize_relay_url folds all loopback
spellings to 127.0.0.1 for runtime identity/dedup ONLY (its doc says connection
code may retain the configured URL). But spawn_agent_child used that normalized
URL as the child's actual BUZZ_RELAY_URL, so UI-managed agents connected to the
empty 127.0.0.1 tenant — "online" but discovering 0 channels — while the human
and their channels lived on localhost. Connect the child on the CONFIGURED relay
at all spawn sites; keep the normalized form only as the dedup identity / key /
receipts / logs.

Corollary badge fix: needs_restart compares a SpawnConfigSnapshot stamped at
spawn against one recomputed live, and the recompute reads the relay from the
normalized runtime-map key. Stamping the snapshot with the now-configured
effective_relay_url (localhost) while the recompute used the normalized key
(127.0.0.1) made them mismatch forever — a permanent, un-clearable
"Restart required" badge. Stamp SpawnConfigInputs.relay_url with the normalized
runtime_key.relay_url so both sides compare the same spelling.

cargo check --no-default-features clean; desktop file-size ratchet respected.

Signed-off-by: Sam Kaplan <samuel.kaplan@salesforce.com>
@salman1993

Copy link
Copy Markdown

🤖 Thank you for working on this. We reviewed the overlapping proposals and are consolidating the configured-vs-canonical relay URL fix in #4859 so review and implementation can happen in one place. We’re marking this PR as superseded and asking a maintainer or the author to close it. Please review #4859 and contribute any feedback, tests, or implementation details you think should be carried into the consolidated fix.

@anilkishan

Copy link
Copy Markdown

salman asked us to consolidate on #4859. The restart-badge point - snapshot stays on the canonical spelling, connection does not - is in the follow-up. Thank you for pinning that so the badge cannot stick forever once the child dials localhost.

@salman1993 salman1993 closed this Aug 13, 2026
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.

3 participants