Skip to content

agents proxy: opencode M6 — reconnect with replay_from, hardening, TestedVersion 1.18.27 - #1952

Open
julia-ye wants to merge 1 commit into
juliaye/opencode-proxy-m5from
juliaye/opencode-proxy-m6
Open

agents proxy: opencode M6 — reconnect with replay_from, hardening, TestedVersion 1.18.27#1952
julia-ye wants to merge 1 commit into
juliaye/opencode-proxy-m5from
juliaye/opencode-proxy-m6

Conversation

@julia-ye

@julia-ye julia-ye commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #1951 (M5). PR 6 of 6 — the final milestone of the opencode facade ladder (plan doc in the hosted-agents subtree).

What

SSE reconnect with a replay_from cursor. The event loop now survives transient harness-stream drops inside one client SSE response: it reconnects with the last event id seen as the resume cursor — recorded unconditionally, never compared, because event ids are random UUIDv4s and a max-id ratchet skips events (the codex facade's shipped drainStream bug; the test harness mints random ids precisely to catch this). Backoff mirrors the codex facade / doctl agents attach schedule (5 attempts, 1s→30s, budget reset after a 30s-healthy connection), with terminal-error classification (401/403/404/409 — including the single-consumer conflict with a concurrent doctl agents attach).

Loud failure on give-up. If reconnecting is exhausted or pointless while a turn is in flight, the client is told: pending permission dialogs dismissed, dangling tool parts and the assistant message closed, session.error, idle — never a silent spinner. A stream end with no turn in flight still just ends the SSE response (the TUI re-attaches itself), exactly as before.

TestedVersion → 1.18.27 (re-captured during M5: attach burst identical to 1.18.25, plus the permission surface), and start-proxy --help now documents the opencode bridge, the opencode attach … --continue connect line, and the tested version (pinned by a help test so it can't rot).

Plan items that turned out to be already done

Checked rather than re-implemented: GetSession validation before bind, SIGINT/SIGTERM handling, and context-rooted shutdown all landed with M1; the unhandled-route/unhandled-event log has been empty since M4's stubs (/diff, /todo) and event no-ops — the live M5 runs logged nothing. The stub inventory is complete at 1.18.27.

Testing

  • New reconnect_test.go: mid-turn drop resumes with the cursor (each delta arrives exactly once — dedup is the replay_from contract, not id comparison), no-turns stream end still closes the response, a terminal error fails the tracked turn loudly (dialog dismissed, assistant finalized, session.error + idle), and open-retries are bounded. Tests warm the history cache first so the harness's error/drop injection deterministically hits the live stream, not the facade's background replay_only warm.
  • Also fixed en route: the client's reply string is now recorded before ResolveHITL (rolled back on error) — the harness can deliver run.human_input_received the instant the resolve lands, racing a write placed after it, which could make permission.replied echo the wrong string for an always reply.
  • Full agentproxy tree race-clean; codex untouched; live turn (including a permission approval) verified against the dev stack on this build.

🤖 Generated with Claude Code

… 1.18.27

The event loop now survives transient harness-stream drops inside one client
SSE response: reconnect with a replay_from cursor (last event id SEEN,
recorded unconditionally and never compared — event ids are random UUIDv4s,
so a max-id ratchet would skip events), backoff with a healthy-duration
budget reset, and terminal-error classification. When the loop gives up with
a turn in flight it fails loudly — pending permission dialogs dismissed,
dangling tools and the assistant message closed, session.error, idle —
instead of leaving the TUI spinning. A stream end with no turn in flight
still ends the SSE response, as before.

Of the plan's remaining M6 items, GetSession-before-bind, signal handling,
and context-rooted shutdown already landed in M1, and the unhandled-route/
event log has been empty since M4 — the stub inventory is complete.
TestedVersion bumps to 1.18.27 (re-captured: attach burst identical) and the
start-proxy help now documents the opencode bridge and its tested version.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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