hosted agents: read session events from the data-plane /events endpoint (stack on OHS_endpoints) - #1072
Merged
Merged
Conversation
Live session streaming moved off the control plane's
`/v2/agents/sessions/{id}/stream` onto the data plane's
`/v2/agents/sessions/{id}/events`, so point StreamSession there.
The two surfaces are not interchangeable, so the move is a split rather than
a rename:
- Live reads go to `/events`. Delivery is forward-only from the moment of
attach, and the resume cursor rides in the standard `Last-Event-ID`
header instead of a query parameter.
- `ReplayOnly` reads stay on `/stream?replay_only=true`. The control plane
owns the stored event history; the data-plane endpoint holds none, so
sending a replay-only read there would hang on a stream that never
yields the history it was asked for.
The live stream also carries `stream.state` transport control frames
reporting connection health (live / catching_up / degraded / superseded).
They arrive in the same canonical envelope as an event, so they decode
through the same parser; name the kind and its payload so callers can
identify and skip them rather than rendering them as session activity.
Co-Authored-By: Claude Opus 5 <[email protected]>
…dpoint
The previous commit moved live streaming onto the data plane but left
replay-only reads (`doctl agents logs`) on the control plane's
`/stream?replay_only=true`, because the data-plane endpoint held no history
of its own -- it delivered forward-only from the moment of attach.
The data plane now stores and serves that history, so both reads move onto
`/v2/agents/sessions/{id}/events` and the split disappears:
- Live is unchanged: forward-only from attach, connection held open,
ReplayFrom sent as Last-Event-ID.
- ReplayOnly adds `?replay_only=true`. The server writes the session's
stored history and then ends the stream, so the read terminates on its
own rather than blocking on a connection that never closes.
ReplayFrom keeps riding the `replay_from` query parameter on a replay-only
read rather than moving to Last-Event-ID with the live lane. The two are not
the same cursor: on a live attach it is a resume hint the server is free to
widen for context, while on a history read it is an explicit pagination
point, and collapsing them would let a history query silently return events
the caller already has.
`stream.state` frames now appear on both reads. A replay-only read reports
`catching_up` and then simply ends -- it never reaches `live`, since there is
no live tail to join.
Co-Authored-By: Claude Opus 5 <[email protected]>
Co-authored-by: Cursor <[email protected]>
The base branch added backward history paging (Before/Limit, HasMore) on the control-plane .../stream path while this branch moved both session reads to the data-plane .../events path. Keep both: the paging query parameters now ride the replay-only mode of the events endpoint, which is the only mode that can start in the past. Co-authored-by: Cursor <[email protected]>
The base branch added include_raw (native protocol frames), provider OAuth, and checkpoint/fork/rollback while this branch serves both session reads from the data-plane .../events path. Keep both: include_raw rides as a query parameter on /events for live and replay-only, and live ReplayFrom still uses Last-Event-ID. Co-authored-by: Cursor <[email protected]>
SSharma-10
added a commit
to digitalocean/doctl
that referenced
this pull request
Aug 18, 2026
…ck on feat/agents-subcommands) (#1899) * agents: pin godo to the data-plane /events build Points godo at digitalocean/godo#1072, which re-applies the two commits reverted from `OHS_endpoints`, so `StreamSession` reads both live and replay-only streams from the data plane's `/v2/agents/sessions/{id}/events` again. Vendor-only in effect: the sole diff under vendor/ is the 89 lines that the earlier pin to the released v1.202.0-beta.1 had dropped from hosted_agents.go. The next commit moves doctl's own code back onto it. Co-authored-by: Cursor <[email protected]> * agents: read live and replay streams from the data-plane /events endpoint With godo back on `/events`, undo the three local accommodations that were made while the endpoint was unavailable. `commands/agents.go` drops its local copies of the `stream.state` kind and payload and uses godo's `HostedAgentEventKindStreamState` / `HostedAgentStreamState` again, so the wire contract lives in one place rather than being restated here. The reconnect test reads the resume cursor from the `Last-Event-ID` header instead of a `replay_from` query parameter, matching where the live lane actually carries it. `replay_from` stays the cursor for replay-only reads, which are a different lane. The agentproxy harness serves `/events` and opens every stream with a `stream.state` frame, so the codex facade tests exercise a stream shaped like the real one. The control plane's `/stream` is deliberately left unregistered: no agentproxy caller makes a replay-only read, so a request landing there is a bug worth failing on rather than quietly serving. Co-authored-by: Cursor <[email protected]> * agents: default the agents surface to the hosted-agents host Hosted agents are fronted by their own host, which serves both the session control plane and the data-plane event stream, so reaching them meant exporting DIGITALOCEAN_API_URL by hand -- and that redirects every other doctl command along with it. Give the `doctl agents` services their own client pinned to that host, and apply caller-supplied client options ahead of the --api-url override so an endpoint the user named explicitly still wins. That is what keeps a non-production environment reachable (the preview host, for instance) and leaves the rest of doctl on api.digitalocean.com. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]> Co-authored-by: SSharma-10 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-applies the two commits reverted from
OHS_endpointsbyeae8993andab376b8(see #1021), unchanged, on a branch of their own.The point of the separate branch is to let the matching doctl work (digitalocean/doctl, stacked on
feat/agents-subcommands) pin a godo revision that actually has/events, sodoctlbuilds can be tested against the OHP data plane without moving either shared PR branch.What the commits do
StreamSessionmoves off the control plane's/v2/agents/sessions/{id}/streamonto the data plane's/v2/agents/sessions/{id}/events, for both reads:ReplayFromis sent as the standardLast-Event-IDheader.?replay_only=true: the server writes the session's stored history and then ends the stream, so the read terminates on its own.ReplayFromstays on thereplay_fromquery parameter, since it is an explicit pagination cursor here rather than a resume hint the server may widen.Both reads carry
stream.statetransport control frames reporting connection health (live/catching_up/degraded/superseded). They arrive in the same canonical envelope as an event, soHostedAgentEventKindStreamStateandHostedAgentStreamStatename the kind and its payload, letting callers identify and skip them instead of rendering them as session activity.Testing
go build ./...,go vet ./...andgo test ./...all pass, including the fourStreamSessiontests covering the live path, replay-only, replay-only history-then-EOF, andstream.statedecoding.