Skip to content

fix(opencode-agents): own the HTTP client - #194

Merged
apucacao merged 2 commits into
mainfrom
cursor/opencode-handler-owns-http-d425
Oct 21, 2026
Merged

apucacao merged 2 commits into
mainfrom
cursor/opencode-handler-owns-http-d425

Conversation

@apucacao

@apucacao apucacao commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR: I keep catching my agent trying to shove handler concerns into Vega.

Decision

A caller passes base_url for a running opencode serve. The handler owns every HTTP call. create_opencode_handler does not accept an httpx client or transport.

Boundary

The caller may start opencode serve, write its runtime config, prepare the workspace and skills, and pass base_url. The handler owns the OpenCode protocol. That covers the HTTP client, GET /event and its SSE reads, POST /session, POST /session/{id}/message with the evaluated model, abort, event reduction, filtering to this session's id, racing a failed message POST, and opening a separate session for each judge. A caller that passes only base_url gets all of it.

Vega is audited against this boundary in observability #2547 and the two PRs on top of it. turnkey.py has no httpx, no transport, no placeholder host, no OpenCode routes, no event handling, and no skip_judges workaround. test_turnkey.py keeps a loopback fake of opencode serve that answers /event, /session, and /message. It plays the server, not the client.

Why

Vega was opening its own httpx.AsyncClient and a custom transport so it could start opencode serve on the first request. That made Vega a special caller. A customer starts the server and passes base_url. Vega should do the same, and it should not manage httpx.

What this PR does not do

  • It does not add a connect callback or any other hook for starting the server.
  • It does not start opencode serve.
  • It does not change session lifecycle, judge sessions, or template rendering.
  • It does not change Vega. Observability #2547 does that.

How did you test this change?

uv run ruff check, uv run ruff format --check, uv run mypy packages/opencode-agents/src, and uv run pytest packages/opencode-agents/tests (45 passed). The tests talk to a loopback server through base_url and the handler's own client.

Open in Web Open in Cursor 

Callers pass base_url for a running opencode serve. The handler opens
its own client, so a caller cannot pass an httpx client or transport.

Co-authored-by: alexis <alexis@launchdarkly.com>
@apucacao
apucacao marked this pull request as ready for review October 20, 2026 21:17
@apucacao
apucacao requested a review from jeffdupont October 20, 2026 21:17
@jeffdupont

Copy link
Copy Markdown
Contributor

The cancelled-read ordering test lost its assert and now passes with the await line_task fix removed. The loopback fake can't see that ordering, so the check needs to live client-side, e.g. patch _next_line to record when it finishes and assert that happens before the response closes. Also, serve_forever(poll_interval=0.01) takes the suite from 20s to about 1s.

The loopback fake cannot see that ordering. Record when _next_line
finishes and require that before GET /event closes. Poll the loopback
server every 0.01s.

Co-authored-by: alexis <alexis@launchdarkly.com>
@apucacao

Copy link
Copy Markdown
Contributor Author

The cancelled-read check is on the client now. A patched _next_line records when it finishes, and the test requires that before GET /event closes. The loopback fake no longer tries to see that order.

I took await line_task out and that assert failed, then put the await back. The loopback server uses serve_forever(poll_interval=0.01).

d9bf7f92337fa397b52ee0640bd718f12640de9a — CI is green, including Bugbot.

@apucacao
apucacao requested review from jeffdupont and removed request for jeffdupont October 21, 2026 17:47

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

Thanks, the cancelled-read test now fails with the fix removed, and the suite is back to about 1s. LGTM.

@apucacao
apucacao merged commit ed2d419 into main Oct 21, 2026
7 checks passed
@apucacao
apucacao deleted the cursor/opencode-handler-owns-http-d425 branch October 21, 2026 17:56
@github-actions github-actions Bot mentioned this pull request Oct 21, 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