pub enum HarnessOperatorAgentEventV1 {
AgentChunk {
sequence: u64,
session: HarnessRuntimeSessionAddressV1,
chunk: HarnessAgentStreamChunkV1,
published_at_ms: u64,
},
Lagged {
sequence: u64,
session: HarnessRuntimeSessionAddressV1,
dropped: u64,
},
ReplayBoundary {
session: HarnessRuntimeSessionAddressV1,
replayed: u32,
dropped_before_replay: u64,
},
Ping {
sequence: u64,
},
}Expand description
Long-lived, server-push counterpart to a SubscribeAgentStream
connection – see HarnessOperatorEventV1’s own doc comment for the
shared framing this also uses. Deliberately its own type, not a variant
of HarnessOperatorEventV1 and not a variant of
HarnessOperatorTerminalEventV1 either, for two separate reasons this
stream’s overflow story below has to hold at once:
- Like
HarnessOperatorTerminalEventV1,HarnessOperatorEventV1’sLagged/SnapshotBaselinepair is wrong here: there is no task/run/node to resync, only content that is already self-contained. - Unlike
HarnessOperatorTerminalEventV1, a dropped chunk here cannot be waved off with a diagnostic counter either. A terminal frame is always a full screen, soTerminalFrame’s owncoalesced_since_lastcan silently supersede a stale frame with a fresher one and lose nothing real. An agent-stream chunk has no such property: aText/Thinkingdelta or anInteractionPromptis a fact about one instant, not a snapshot of the whole session, so a chunk this stream drops is gone – there is no later chunk that already contains it, and dropping anInteractionPromptin particular would strand the operator unable to ever answer a correlation id they never saw.
So overflow here gets its own honest shape: Lagged reports a real,
unrecoverable loss for one subscribed session – no snapshot follows it,
because none could repair what was lost – and the client’s only correct
response is to surface that loss to the operator, not to wait for a
recovery frame that is never coming.
ReplayBoundary is a separate, narrower concession to the same
“instants are gone once missed” rule: a subscriber routinely registers
seconds after a session’s first turn already started (an operator can
only address a session that has been spawned), and every Text/
Thinking/Blocked chunk published into that gap used to be gone for
good. The harness now keeps a small bounded ring of the most recent ones
per session and replays it once at subscribe time, immediately marked by
this event so it is never mistaken for live content – see this field’s
own doc comment on AgentChunk::published_at_ms for how a replayed
chunk keeps proving it is history, not now.
Variants§
AgentChunk
Fields
session: HarnessRuntimeSessionAddressV1chunk: HarnessAgentStreamChunkV1published_at_ms: u64The harness’s own wall-clock reading of the moment this chunk
was first published to AgentStreamSubscriberRegistry
(hatchery-harness-service::agent_stream), carried unchanged
through every delivery path – live, state seed, and the bounded
replay ReplayBoundary marks the end of. A replayed chunk keeps
the timestamp it was born with here; nothing ever restamps it to
the moment it happened to be replayed.
Lagged
This subscriber’s outbound queue overflowed for the named session and
dropped chunks were lost for it specifically – other subscribers,
and this subscriber’s other subscribed sessions, are unaffected. See
this type’s own doc comment for why there is no recovery frame to
follow it.
ReplayBoundary
Sent at most once per SubscribeAgentStream subscription per
session, right after that session’s replayed instant chunks
(Text/Thinking/Blocked pulled from the harness’s own bounded
replay ring – see hatchery-harness-service::agent_stream’s own
doc comment) and before any live chunk for that session: the marker
that lets the operator tell “recent history it missed” apart from
“happening right now”. Sent for every session the harness has
recorded ANYTHING for at all (state, replay, or both), even if the
ring itself turned out empty for it (replayed: 0) – but never for
a session the harness has not seen even once, since there is nothing
to mark a boundary against there and the first thing that subscriber
sees for it will just be live content, unambiguously so.
dropped_before_replay is the ring’s own running eviction count –
nonzero here means the replay itself is truncated, and it names that
gap rather than silently handing back a partial history as if it
were the whole one.
Ping
Same keep-alive rationale as HarnessOperatorTerminalEventV1::Ping:
this is a physically separate connection with its own dead-peer-
detection problem, independent of the terminal and task/run/node
subscriptions’ own.