Skip to content

refactor: drop relay base-URL defaults; inherit from relaycast SDK 4.2.0#1199

Merged
willwashburn merged 2 commits into
mainfrom
refactor/centralize-relaycast-base-url
Jun 24, 2026
Merged

refactor: drop relay base-URL defaults; inherit from relaycast SDK 4.2.0#1199
willwashburn merged 2 commits into
mainfrom
refactor/centralize-relaycast-base-url

Conversation

@willwashburn

@willwashburn willwashburn commented Jun 24, 2026

Copy link
Copy Markdown
Member

What

agent-relay and agent-relay-broker no longer hardcode an engine base URL. They pass RELAYCAST_BASE_URL / RELAY_BASE_URL through for self-hosting and otherwise inherit the default from the relaycast SDK (cast.agentrelay.com). Builds against published relaycast 4.2.0.

Scope: broker + CLI only. The standalone Python (communicate) and Swift hosted SDKs are handled separately by #1187 (wrap relaycast-sdk) and #1188 (wrap relaycast's Swift SDK) — the better pattern, since wrapping the relaycast SDK makes those clients inherit the cast default instead of requiring callers to pass one. This PR no longer touches sdk-py/sdk-swift.

Changes

broker (agent-relay-broker)

  • Resolve the engine base from env (RELAYCAST_BASE_URLRELAY_BASE_URL) into Option<String> (None when unset) and thread it so every relaycast SDK call inherits the SDK default when None.
  • Build the fleet node-control WS URL via relaycast::node_control_ws_url(...) (removed relay's derive_ws_base_url_from_http).
  • Inject RELAY_BASE_URL into spawned agents / generated MCP config only when an override is configured.
  • Removed relay's DEFAULT_RELAYCAST_BASE_URL const; bumped relaycast = "=4.2.0".

cli

  • normalizeBaseUrl no longer injects a literal (the SDK owns the default); stale gateway comment fixed; test fixtures neutralized.

Verification

  • cargo build + cargo test -p agent-relay-broker against published relaycast 4.2.0: 774 lib tests pass, 0 failures.
  • CLI agent-relay-mcp.startup.test.ts: 19 pass.
  • No base-URL literal / gateway / api.relaycast.dev in broker or CLI source.

🤖 Generated with Claude Code

The hosted engine base URL default now lives solely in the relaycast SDK.
relay holds no base-URL literal: clients pass RELAYCAST_BASE_URL / RELAY_BASE_URL
through for self-hosting and otherwise inherit the SDK default (cast.agentrelay.com).
Removes the strangled gateway.relaycast.dev / api.relaycast.dev domains.

- broker: resolve the engine base from env into Option<String> (None when unset)
  and thread it so SDK calls default via the SDK; build the fleet node-control
  WS URL via relaycast::node_control_ws_url; inject RELAY_BASE_URL into spawned
  agents only when an override is set. Bump relaycast to =4.2.0.
- cli: normalizeBaseUrl no longer injects a literal (the SDK owns the default).
- sdk-py / sdk-swift: de-default base URL — callers supply base_url / baseURL
  (or set RELAY_BASE_URL). (Breaking for these SDKs.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@willwashburn willwashburn requested a review from khaliqgant as a code owner June 24, 2026 19:57
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Base URL handling is changed across broker, runtime, CLI, Python, and Swift code to accept optional or explicit values instead of hardcoded defaults. Tests and documentation were updated to use relay.example.com or localhost values, and the changelog records the compatibility change.

Changes

Hosted base URL unification

Layer / File(s) Summary
Broker Relaycast client wiring
crates/broker/Cargo.toml, crates/broker/src/relaycast/*, crates/broker/src/cli_mcp_args.rs
Relaycast clients, workspace sessions, and MCP token wiring now accept optional base URLs, and the broker dependency is bumped to relaycast 4.2.0.
Runtime base URL propagation
crates/broker/src/runtime/*, crates/broker/src/spawner.rs, crates/broker/src/wrap.rs
RelaySession now stores configured_base, relay env parsing and URL derivation use optional values, child-agent env injection is conditional, and runtime tests drop the WS derivation helper.
CLI normalization and release notes
CHANGELOG.md, packages/cli/src/cli/agent-relay-mcp.ts, packages/cli/src/cli/agent-relay-mcp.startup.test.ts, tests/integration/sdk/v8-api-smoke.mjs
normalizeBaseUrl returns undefined when omitted, startup tests and smoke instructions use relay.example.com or localhost values, and the changelog records the base URL behavior changes.
Python communicate base URL contract
packages/sdk-py/src/agent_relay/communicate/*, packages/sdk-py/tests/communicate/test_types.py
The communicate config and transport remove the default relay base URL constant, require an explicit or env-provided base URL, and update the unset test case.
Swift explicit baseURL requirement
packages/sdk-swift/Sources/AgentRelaySDK/AgentRelayClient.swift, packages/sdk-swift/Tests/AgentRelaySDKTests/AgentRelaySDKTests.swift, packages/sdk-swift/README.md
The Swift AgentRelay initializers now require a non-optional baseURL, the fallback helper is removed, and the README and tests use explicit relay.example.com URLs.

Sequence Diagram(s)

sequenceDiagram
  participant connect_relay
  participant AuthClient
  participant MultiWorkspaceSession
  participant run_init
  participant node_control_ws_url
  participant run_wrap
  participant spawn_env_vars

  connect_relay->>AuthClient: new(configured_base)
  connect_relay->>MultiWorkspaceSession: new(configured_base, configured_ws)
  run_init->>node_control_ws_url: node_control_ws_url(configured_base.as_deref())
  run_wrap->>spawn_env_vars: child_base_url.as_deref()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • AgentWorkforce/relay#1064: Introduced the gateway-default base URL behavior that this PR removes from broker and CLI paths.
  • AgentWorkforce/relay#1195: Changed the broker runtime base URL derivation area that this PR continues by switching to optional configured values.
  • AgentWorkforce/relay#1147: Added the Swift AgentRelayClient base URL defaulting that this PR replaces with an explicit baseURL.

Suggested reviewers

  • khaliqgant

Poem

🐰 I hopped through relays, light and spry,
no gateway default hid in the sky.
Base URLs now come when spoken,
and unset paths stay quietly open.
Ears up—self-hosted trails reply!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 67.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main refactor: removing relay base-URL defaults and deferring to relaycast SDK 4.2.0.
Description check ✅ Passed The description is mostly complete and covers the summary, changes, verification, and scope limits, even though it doesn't use the exact template headings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/centralize-relaycast-base-url

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed due to a network error.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
CHANGELOG.md (1)

10-18: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate duplicate section headers under [Unreleased].

This adds a second ### Changed (Line 10) and ### Removed (Line 14) while the same headers already exist later in the section (Lines 45 and 64). Keep a Changelog expects one heading per change type per release; merge these into the existing groups.

As per coding guidelines: "Curate [Unreleased] in CHANGELOG.md... following Keep a Changelog format and Semantic Versioning."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 10 - 18, The [Unreleased] section in CHANGELOG.md
has duplicate change-type headings, so merge the newly added `### Changed` and
`### Removed` entries into the existing `### Changed` and `### Removed` groups
instead of creating second headers. Keep the content under the existing headings
and remove the duplicate section titles so the changelog follows Keep a
Changelog structure.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Around line 14-18: The changelog has conflicting base-URL guidance between the
new Removed entry and the existing [Unreleased] note. Update the relevant
CHANGELOG sections so the entries for codex-relay-skill, gemini-relay-extension,
and the SDKs all describe the same current behavior, using the correct default
base URL and migration guidance consistently. Reconcile the text in the Removed
section with the earlier base-URL note so there is only one accurate story about
gateway.relaycast.dev, api.relaycast.dev, and cast.agentrelay.com.

In `@crates/broker/src/runtime/session.rs`:
- Around line 129-133: The base URL selection in session handling is picking
RELAYCAST_BASE_URL before applying trim/filter, so an empty canonical value can
block a valid RELAY_BASE_URL fallback. Update the logic in session.rs around
configured_base so each env var is trimmed and checked for emptiness before
falling back to the next one, using the existing configured_base expression to
preserve the intended override order.

---

Nitpick comments:
In `@CHANGELOG.md`:
- Around line 10-18: The [Unreleased] section in CHANGELOG.md has duplicate
change-type headings, so merge the newly added `### Changed` and `### Removed`
entries into the existing `### Changed` and `### Removed` groups instead of
creating second headers. Keep the content under the existing headings and remove
the duplicate section titles so the changelog follows Keep a Changelog
structure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 855b38bb-4913-4320-b430-5ee91f0d4009

📥 Commits

Reviewing files that changed from the base of the PR and between 8ada1f6 and 73c59a7.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • CHANGELOG.md
  • crates/broker/Cargo.toml
  • crates/broker/src/cli_mcp_args.rs
  • crates/broker/src/relaycast/auth.rs
  • crates/broker/src/relaycast/workspace.rs
  • crates/broker/src/relaycast/ws.rs
  • crates/broker/src/runtime/init.rs
  • crates/broker/src/runtime/mod.rs
  • crates/broker/src/runtime/paths.rs
  • crates/broker/src/runtime/session.rs
  • crates/broker/src/runtime/tests.rs
  • crates/broker/src/spawner.rs
  • crates/broker/src/wrap.rs
  • packages/cli/src/cli/agent-relay-mcp.startup.test.ts
  • packages/cli/src/cli/agent-relay-mcp.ts
  • packages/sdk-py/src/agent_relay/communicate/transport.py
  • packages/sdk-py/src/agent_relay/communicate/types.py
  • packages/sdk-py/tests/communicate/test_types.py
  • packages/sdk-swift/README.md
  • packages/sdk-swift/Sources/AgentRelaySDK/AgentRelayClient.swift
  • packages/sdk-swift/Tests/AgentRelaySDKTests/AgentRelaySDKTests.swift
  • tests/integration/sdk/v8-api-smoke.mjs
💤 Files with no reviewable changes (2)
  • crates/broker/src/runtime/mod.rs
  • crates/broker/src/runtime/paths.rs

Comment thread CHANGELOG.md
Comment on lines +14 to +18
### Removed

- Removed all `gateway.relaycast.dev` / `api.relaycast.dev` references; clients target `cast.agentrelay.com` only.
- **Breaking (SDKs):** relay's Swift `AgentRelay` client and Python `communicate` client no longer default the base URL — callers must pass `baseURL`/`base_url` or set `RELAY_BASE_URL`.

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Changelog contradicts an existing [Unreleased] entry.

Line 16 states all gateway.relaycast.dev / api.relaycast.dev references were removed and clients target cast.agentrelay.com only. However, the existing entry on Line 51 still documents these domains as live defaults:

codex-relay-skill and gemini-relay-extension now default to https://gateway.relaycast.dev... Set RELAY_BASE_URL to keep using https://api.relaycast.dev.

Reconcile these two entries so the changelog presents a single, accurate base-URL story for the release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 14 - 18, The changelog has conflicting base-URL
guidance between the new Removed entry and the existing [Unreleased] note.
Update the relevant CHANGELOG sections so the entries for codex-relay-skill,
gemini-relay-extension, and the SDKs all describe the same current behavior,
using the correct default base URL and migration guidance consistently.
Reconcile the text in the Removed section with the earlier base-URL note so
there is only one accurate story about gateway.relaycast.dev, api.relaycast.dev,
and cast.agentrelay.com.

Comment on lines +129 to +133
let configured_base: Option<String> = std::env::var("RELAYCAST_BASE_URL")
.ok()
.or_else(|| std::env::var("RELAY_BASE_URL").ok())
.unwrap_or_else(|| DEFAULT_RELAYCAST_BASE_URL.to_string());
let ws_base = std::env::var("RELAYCAST_WS_URL")
.unwrap_or_else(|_| derive_ws_base_url_from_http(&http_base));
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty());

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Trim/filter before falling back to RELAY_BASE_URL.

Line 129 chooses RELAYCAST_BASE_URL before trimming, so an empty canonical env var suppresses a valid RELAY_BASE_URL override and can send self-hosted workspace keys to the SDK default host.

Proposed fix
-    let configured_base: Option<String> = std::env::var("RELAYCAST_BASE_URL")
-        .ok()
-        .or_else(|| std::env::var("RELAY_BASE_URL").ok())
-        .map(|s| s.trim().to_string())
-        .filter(|s| !s.is_empty());
+    let configured_base: Option<String> = std::env::var("RELAYCAST_BASE_URL")
+        .ok()
+        .map(|s| s.trim().to_string())
+        .filter(|s| !s.is_empty())
+        .or_else(|| {
+            std::env::var("RELAY_BASE_URL")
+                .ok()
+                .map(|s| s.trim().to_string())
+                .filter(|s| !s.is_empty())
+        });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let configured_base: Option<String> = std::env::var("RELAYCAST_BASE_URL")
.ok()
.or_else(|| std::env::var("RELAY_BASE_URL").ok())
.unwrap_or_else(|| DEFAULT_RELAYCAST_BASE_URL.to_string());
let ws_base = std::env::var("RELAYCAST_WS_URL")
.unwrap_or_else(|_| derive_ws_base_url_from_http(&http_base));
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty());
let configured_base: Option<String> = std::env::var("RELAYCAST_BASE_URL")
.ok()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.or_else(|| {
std::env::var("RELAY_BASE_URL")
.ok()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/broker/src/runtime/session.rs` around lines 129 - 133, The base URL
selection in session handling is picking RELAYCAST_BASE_URL before applying
trim/filter, so an empty canonical value can block a valid RELAY_BASE_URL
fallback. Update the logic in session.rs around configured_base so each env var
is trimmed and checked for emptiness before falling back to the next one, using
the existing configured_base expression to preserve the intended override order.

@willwashburn willwashburn merged commit 76dcdfb into main Jun 24, 2026
2 checks passed
@willwashburn willwashburn deleted the refactor/centralize-relaycast-base-url branch June 24, 2026 20:22
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.

1 participant