Skip to content

fix(channels): add default_agent to SidecarChannelConfig — restore inbound routing pin (closes #5294)#5295

Merged
houko merged 1 commit into
librefang:mainfrom
DaBlitzStein:fix/sidecar-channels-default-agent-5294
May 20, 2026
Merged

fix(channels): add default_agent to SidecarChannelConfig — restore inbound routing pin (closes #5294)#5295
houko merged 1 commit into
librefang:mainfrom
DaBlitzStein:fix/sidecar-channels-default-agent-5294

Conversation

@DaBlitzStein

Copy link
Copy Markdown
Contributor

Closes #5294.

Problem

Sidecar adapter migration (#5241) dropped the per-channel default_agent field that in-process configs (TelegramConfig, DiscordConfig, …) used to seed AgentRouter.channel_defaults at boot. The router-population loop in channel_bridge.rs (around line 3295) pushes sidecar adapters into the adapters vec with None for the default-agent slot, so the per-channel router.set_channel_default_with_name call never fires for sidecar channels.

Result: inbound messages on a sidecar channel with no explicit binding fall through to the non-deterministic 'first available agent' branch in resolve_or_fallback. Spawning a new agent (without restricting its channels allowlist) silently redirects inbound traffic to it.

Reproduction

  1. Configure Telegram via [[sidecar_channels]]. Existing agent (e.g. fandangorodelo) with channels = ["telegram"] in its manifest, receiving Telegram traffic correctly.
  2. Create a second agent (any purpose, e.g. Profesor) without restricting its channels list (defaults to channels = []).
  3. Send a Telegram message → ends up routed to Profesor instead of fandangorodelo, because the router has no channel_defaults["telegram"] and falls through to first-available.

Fix

Add default_agent: Option<String> to SidecarChannelConfig (mirrors the equivalent field on in-process channel configs) and propagate it through the adapter-push so the existing population loop seeds the router.

[[sidecar_channels]]
name = "telegram"
command = "python3"
args = ["-m", "librefang.sidecar.adapters.telegram"]
channel_type = "telegram"
default_agent = "fandangorodelo"   # NEW

No behavioural change when the field is absent — deployments that currently rely on the "first available" fallback continue working.

Test plan

  • cargo check -p librefang-types -p librefang-channels — clean
  • cargo clippy -p librefang-types -p librefang-channels --all-targets -- -D warnings — clean
  • cargo test -p librefang-channels --lib sidecar_default_agent_roundtrip_5294 — passes (new test covering absent + explicit-value round-trip).
  • Manual repro on live deploy (rodela-ai fork): without fix, traffic routed to wrong agent; with fix + default_agent = "fandangorodelo" in config, traffic routes correctly even when other agents exist.

Notes

This only addresses the missing-router-default half of #5294. The two related concerns (channels = [] accept-all semantics, and the 'first available' fallback being a silent footgun) are separate and need their own discussion — see the issue body. Happy to follow up on either if maintainers want to flip those defaults too.

…bound routing pin (closes librefang#5294)

Sidecar adapter migration (librefang#5241) dropped the per-channel default_agent
field that in-process configs (TelegramConfig, DiscordConfig, etc.) used
to seed AgentRouter.channel_defaults at boot. The router-population
loop in channel_bridge.rs pushed sidecar adapters into the adapters vec
with None for the default-agent slot, so the per-channel
set_channel_default_with_name call never fired for sidecar channels.

Result: inbound messages on a sidecar channel with no explicit binding
fell through to the non-deterministic 'first available agent' branch
in resolve_or_fallback. Spawning a new agent (without restricting its
channels allowlist) silently redirected inbound traffic to it.

Fix: add default_agent: Option<String> to SidecarChannelConfig and
propagate it through the adapter-push so the existing population loop
seeds the router. No behavioural change when the field is absent.

Test: sidecar_default_agent_roundtrip_5294.
@github-actions github-actions Bot added size/S 10-49 lines changed area/channels Messaging channel adapters labels May 19, 2026

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

Verified:

  • default_agent field has #[serde(default)] (librefang-types/src/config/types.rs ~2180), so existing [[sidecar_channels]] blocks without it still parse as None — back-compat preserved.
  • Wire-through reaches the router: sidecar_config.default_agent.clone() lands in the registration tuple alongside the in-process adapter path (channel_bridge.rs ~3282-3285), and the router loop at 3295-3329 feeds it to set_channel_default_with_name() — same code path that already works for in-process adapters.
  • Regression test sidecar_default_agent_roundtrip_5294 (in channels/src/sidecar.rs) covers serde present + absent. End-to-end routing is exercised by the existing bridge_integration_test.rs tests.

Stale golden schema is pre-existing (config_schema_golden test is already #[ignore]) and orthogonal.

@houko
houko merged commit 2f7158a into librefang:main May 20, 2026
21 of 30 checks passed
@github-actions github-actions Bot added the ready-for-review PR is ready for maintainer review label May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/channels Messaging channel adapters ready-for-review PR is ready for maintainer review size/S 10-49 lines changed

Projects

None yet

2 participants