Skip to content

fix(swarm): carry a provider's proxy decision into its lanes - #150

Merged
rn7s2 merged 1 commit into
mainfrom
fix/lane-provider-proxy
Oct 17, 2026
Merged

rn7s2 merged 1 commit into
mainfrom
fix/lane-provider-proxy

Conversation

@rn7s2

@rn7s2 rn7s2 commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

The bug

Every lane of a swarm failed its first model request on a machine that exports http_proxy, with:

:error-message "HTTP 400: "  :input 0

Zero tokens spent, no body, nothing in the lane's log but the provider and the error. It reads like a bad model or a bad key, not a proxy problem.

Root cause

A lane boots evo-agent serve --no-userspace, so the coordinator hands it its providers through the baseline: provider-registration-form (swarm/init.lisp) rebuilds one register-provider per coordinator registration. That form carried :base-url and the credential's variable — and dropped :proxy.

So a provider the coordinator was told to reach directly (:proxy nil, the fix in d2884e2 "feat(provider): let a provider decide its own proxy") was reached through the environment's proxy in the lane, and a lane inherits the coordinator process's environment.

provider-config in the lane then resolves no :proxy, with-proxy falls back to the environment, and dexador — handed a proxy for a plain-HTTP endpoint — writes an origin-form request line (POST /v1/messages) where a proxy requires the absolute form. The proxy answers 400 with an empty body.

How it was found

By querying a live lane through POST /ops instead of reading the code. The lane's own registration, read in the lane:

(:base-url "<the provider's endpoint>" :api-key-env "EVO_SWARM_<PROVIDER>_API_KEY")

and the coordinator's for the same provider:

(:base-url "<the provider's endpoint>" :api-key-env "EVO_SWARM_<PROVIDER>_API_KEY" :proxy nil)

The lane's was missing the third element, and with-proxy in that lane was resolving the environment's proxy. That difference is the whole bug.

The fix

provider-registration-form carries :proxy when the registration has one. An absent key stays absent, so a provider that never chose still lets the lane's environment decide, exactly as it does in the coordinator.

Verification

  • The form for a provider registered :proxy nil now reads :proxy nil; one with a proxy URL keeps it; one that never chose has no :proxy at all.
  • make test — 2087 core + 373 swarm, 0 failed.
  • The three cases are regression checks in test-baseline (swarm/tests/unit.lisp).

Co-authored-by: EvoAgent evo@ruiqilei.com

A lane boots `evo-agent serve --no-userspace`, so the coordinator hands it
its providers through the baseline: provider-registration-form rebuilds a
`register-provider` per coordinator registration. That form carried
:base-url and the credential's variable and dropped :proxy — so a provider
the coordinator was told to reach directly (`:proxy nil`) was reached
through whatever proxy the environment names in the lane, and a lane
inherits the coordinator process's environment.

The result was that every lane of a swarm on a machine exporting
http_proxy failed its first request with "HTTP 400: " and zero tokens
spent, while the coordinator — which reads its own registration, :proxy
included — worked. It looked like a model or credential problem, not a
proxy one, and the lane's journal showed only the provider and the error.

Found by querying a live lane through POST /ops rather than reading the
code: the lane's registration was

  (:base-url "http://192.168.1.5:3425" :api-key-env "EVO_SWARM_MAGPIE_API_KEY")

where the coordinator's had a third element, :proxy nil. provider-config
in that lane therefore resolved no :proxy, with-proxy fell back to the
environment's proxy, and dexador wrote an origin-form request line where a
proxy requires the absolute form (see with-proxy) — a 400 with no body.

provider-registration-form now carries :proxy when the registration has
one, an absent key staying absent so a provider that never chose still
lets the lane's environment decide, exactly as it does in the
coordinator.

Verified: the form for a provider registered with :proxy nil now reads
`:proxy nil`, one with a proxy URL keeps it, and one that never chose has
no :proxy at all; make test is 2087 core + 373 swarm, 0 failed. The three
cases are regression checks in test-baseline.

Co-authored-by: EvoAgent <evo@ruiqilei.com>
@rn7s2
rn7s2 merged commit 449363e into main Oct 17, 2026
3 checks passed
@rn7s2
rn7s2 deleted the fix/lane-provider-proxy branch October 17, 2026 17:09
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