Skip to content

hosted agents: add truncated to the stream state frame (MARSOHS-900) - #1194

Merged
SSharma-10 merged 2 commits into
digitalocean:mainfrom
kamleshsahu:ksahu/marsohs-900-stream-state-truncated
Oct 26, 2026
Merged

SSharma-10 merged 2 commits into
digitalocean:mainfrom
kamleshsahu:ksahu/marsohs-900-stream-state-truncated

Conversation

@kamleshsahu

Copy link
Copy Markdown
Contributor

Summary

HostedAgentStreamState dropped the truncated marker on decode, so an SDK caller could not tell a replayed window with a hole in it from a complete one.

The data plane sets truncated on a catching_up frame when the window it served is the session's head rather than the caller's resume point — a stored or supplied cursor could not be reached inside the replay window, so the events between it and head−N exist and are not being sent. It is also set when the cursor was reached but a hole remains behind it. The server has emitted it for a while; only the client half was missing.

Without the field, a renderer shows the replayed events as one continuous transcript. The common case for this is multi-device: one device attaches and leaves, another drives the session past the replay window, the first returns and silently misses the middle.

Changes

  • HostedAgentStreamState gains Truncated bool (json:"truncated,omitempty"), documented with what the marker means and why ignoring it is wrong.
  • A test pinning a catching_up frame with truncated: true, and an assertion on the existing live frame test that a frame without the field decodes to false.

Compatibility

Additive and omitted when false, so frames written before the server set it decode to the zero value. No existing behaviour changes.

Testing

  • go test github.com/digitalocean/godo — pass
  • go vet — clean
  • gofmt — clean

The consuming change is a follow-up in doctl, which will render a line before the replayed events rather than presenting them as continuous.

🤖 Generated with Claude Code

kamleshsahu and others added 2 commits October 26, 2026 16:57
The data plane marks a catching_up window that is the session's head rather
than the caller's resume point: a stored or supplied cursor could not be
reached inside the replay window, so the events between it and head-N are not
sent. The server has emitted `truncated` on that frame for a while; the SDK
dropped it on decode, so a caller could not tell a replayed window with a hole
in it from a complete one.

Add the field to HostedAgentStreamState. It is additive and omitted when
false, so frames written before the server set it decode to the zero value.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@SSharma-10 SSharma-10 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.

LGTM

@SSharma-10
SSharma-10 merged commit f93b47a into digitalocean:main Oct 26, 2026
8 checks passed
kamleshsahu added a commit to kamleshsahu/doctl that referenced this pull request Oct 26, 2026
An attach replays recent history before joining the live tail, bounded by the
server's replay window. When a stored or supplied cursor cannot be reached
inside that window the server serves the session's head instead and marks the
catching_up frame `truncated` — the events between the cursor and head-N exist
and are not sent. drainStream decoded the frame, acted only on `superseded`
and dropped the rest, so the replayed events printed as one continuous
transcript and a hole in the middle was indistinguishable from a session that
had simply been quiet.

Render a muted line above the replayed window naming `logs` as the command
that has the whole transcript. Not a warning: the stream is healthy and
correctly bounded; the only thing wrong would be reading the pane as
continuous. The common case is multi-device — one device attaches and leaves,
another drives the session past the window, the first returns.

Bumps godo to pick up HostedAgentStreamState.Truncated (digitalocean/godo#1194,
merged). v1.233.0 was cut before that merge, so the pin is a pseudo-version of
godo main; swap it for the next release before merge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kamleshsahu added a commit to kamleshsahu/doctl that referenced this pull request Oct 26, 2026
An attach replays recent history before joining the live tail, bounded by the
server's replay window. When a stored or supplied cursor cannot be reached
inside that window the server serves the session's head instead and marks the
catching_up frame `truncated` — the events between the cursor and head-N exist
and are not sent. drainStream decoded the frame, acted only on `superseded`
and dropped the rest, so the replayed events printed as one continuous
transcript and a hole in the middle was indistinguishable from a session that
had simply been quiet.

Render a muted line above the replayed window naming `logs` as the command
that has the whole transcript. Not a warning: the stream is healthy and
correctly bounded; the only thing wrong would be reading the pane as
continuous. The common case is multi-device — one device attaches and leaves,
another drives the session past the window, the first returns.

TEMPORARY: go.mod replaces godo with the fork commit carrying the new field
(digitalocean/godo#1194). Swap it for the released version before merge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kamleshsahu added a commit to kamleshsahu/doctl that referenced this pull request Oct 26, 2026
The previous commit built against a replace pointing at a fork branch, which
was how this could compile before HostedAgentStreamState.Truncated existed
upstream. digitalocean/godo#1194 is merged, so drop the replace and depend on
godo directly.

v1.233.0 was cut before that merge, so this pins a pseudo-version of godo main
rather than a release. Swap it for the next tag before merging.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kamleshsahu added a commit to kamleshsahu/doctl that referenced this pull request Nov 10, 2026
main is already on godo v1.236.0, which carries
HostedAgentStreamState.Truncated (digitalocean/godo#1194, first released in
v1.234.0). Take main's go.mod, go.sum and vendor/ wholesale, which drops this
branch's temporary godo pseudo-version pin; the change is now only the
renderer and its tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
kamleshsahu added a commit to kamleshsahu/doctl that referenced this pull request Nov 10, 2026
An attach replays recent history before joining the live tail, bounded by the
server's replay window. When a stored or supplied cursor cannot be reached
inside that window the server serves the session's head instead and marks the
catching_up frame `truncated` — the events between the cursor and head-N exist
and are not sent. drainStream decoded the frame, acted only on `superseded`
and dropped the rest, so the replayed events printed as one continuous
transcript and a hole in the middle was indistinguishable from a session that
had simply been quiet.

Render a muted line above the replayed window naming `logs` as the command
that has the whole transcript. Not a warning: the stream is healthy and
correctly bounded; the only thing wrong would be reading the pane as
continuous. The common case is multi-device — one device attaches and leaves,
another drives the session past the window, the first returns.

HostedAgentStreamState.Truncated shipped in godo v1.234.0
(digitalocean/godo#1194) and main is already on v1.236.0, so no dependency
change is needed here.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
RohithSangati pushed a commit to digitalocean/doctl that referenced this pull request Nov 10, 2026
…#2077)

An attach replays recent history before joining the live tail, bounded by the
server's replay window. When a stored or supplied cursor cannot be reached
inside that window the server serves the session's head instead and marks the
catching_up frame `truncated` — the events between the cursor and head-N exist
and are not sent. drainStream decoded the frame, acted only on `superseded`
and dropped the rest, so the replayed events printed as one continuous
transcript and a hole in the middle was indistinguishable from a session that
had simply been quiet.

Render a muted line above the replayed window naming `logs` as the command
that has the whole transcript. Not a warning: the stream is healthy and
correctly bounded; the only thing wrong would be reading the pane as
continuous. The common case is multi-device — one device attaches and leaves,
another drives the session past the window, the first returns.

HostedAgentStreamState.Truncated shipped in godo v1.234.0
(digitalocean/godo#1194) and main is already on v1.236.0, so no dependency
change is needed here.

Co-authored-by: Claude Sonnet 5.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.

2 participants

⌂ 换网址