Skip to content

feat(provider): let a provider decide its own proxy - #149

Merged
rn7s2 merged 1 commit into
mainfrom
provider-proxy-override
Oct 16, 2026
Merged

rn7s2 merged 1 commit into
mainfrom
provider-proxy-override

Conversation

@rn7s2

@rn7s2 rn7s2 commented Oct 16, 2026

Copy link
Copy Markdown
Owner

A plain-HTTP provider could not be reached on any machine that exports
http_proxy, and the failure said nothing about why: every request came back
HTTP 400: with no body and no tokens spent (input 0).

Why

evo deliberately resolves a proxy per request (env-proxy, honouring the
lowercase http_proxy that dexador's own *default-proxy* misses) and hands
it to dexador as :proxy. dexador then connects to the proxy but writes an
origin-form request line:

POST /v1/messages HTTP/1.1
Host: 192.168.1.5:3425

where an HTTP proxy requires the absolute form
(POST http://192.168.1.5:3425/v1/messages HTTP/1.1). xray answers that with
HTTP/1.1 400 Bad Request and Content-Length: 0 — the empty body the agent
reported. An HTTPS provider is unaffected, since HTTPS tunnels with CONNECT.

What

:proxy on register-provider now decides in place of the environment:

  • a proxy URL string forces that one;
  • nil reaches this provider directly, whatever http_proxy/https_proxy
    say — the case of a plain-HTTP endpoint behind a machine-wide proxy;
  • absent keeps the environment's answer, exactly as before.

with-proxy takes the override as an optional third element and makes it the
proxy dexador uses, so it is not undone by a proxy baked into dexador at build
time. perform-request carries it (a defgeneric lambda list may not give a
&key default, so the method does), and call-provider passes the provider's
registered value. provider-config publishes :proxy only when it was
registered: an absent key and a nil one mean different things.

Verification

  • make test unit suite: 2087 passed, 0 failed, including new checks that
    an override beats the environment, and that absent is not nil in the
    resolved config.
  • Same endpoint, same process, two provider keys — one registered :proxy nil,
    one not, with http_proxy set:
:magpie-direct -> stop-reason=:STOP  error=NIL       content=("Hi!")
:magpie-env    -> stop-reason=:ERROR error="HTTP 400: "
  • The built binary, init.lisp registering the same provider, prompt
    Reply with exactly: proxy override works:
with :proxy nil   -> proxy override works
without           -> ✗ provider error: HTTP 400:

A plain-HTTP endpoint was unreachable on any machine that exports
http_proxy. evo honours the environment's proxy, and dexador — handed
:proxy — connects to it but writes an origin-form request line
("POST /v1/messages"), where a proxy requires the absolute form. xray
answers that with 400 and no body, so every request to such a provider
came back "HTTP 400: " with no tokens spent, while the same request
through curl succeeded; an HTTPS endpoint was unaffected, since HTTPS
tunnels with CONNECT.

:proxy on register-provider now decides in place of the environment:

- a proxy URL string forces that one;
- nil reaches this provider directly, whatever http_proxy/https_proxy
  say — the plain-HTTP endpoint behind a machine-wide proxy;
- absent keeps the environment's answer, as before.

with-proxy takes the override as an optional third element and makes it
the proxy dexador uses, so an override is not undone by the proxy baked
into dexador at build time; perform-request carries it (the defgeneric
may not give a &key default, so the method does); call-provider sends
the provider's registered value. provider-config publishes :proxy only
when it was registered, an absent key and a nil one meaning different
things.

Co-authored-by: EvoAgent <evo@ruiqilei.com>
@rn7s2
rn7s2 merged commit d2884e2 into main Oct 16, 2026
3 checks passed
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