63 lines · 2.8 KB · TypeScript
RawDownload
// Pure state machine for the per-session runtime event cursor. This is the// single source of truth for ordering decisions on the live event stream:// which seqs to accept, where to reconnect from, and what to persist.//// `receivedSeq` is the highest seq seen on the wire — the dedup gate and the// SSE reconnect cursor. `committedSeq` is the highest seq whose effects have// actually been reduced into session state — the only value that may be// persisted as `Session.lastEventSeq`. They diverge while a text delta sits// in the animation-frame coalescer. export type RuntimeCursor = {  receivedSeq: number | undefined;  committedSeq: number | undefined;}; /** * Gate an incoming payload. Seq-less payloads (status frames) always pass and * never advance the cursor. A seq at or below the highest received one is a * duplicate (server replay overlap, out-of-order packet) and is rejected. */export function acceptRuntimeSeq(  cursor: RuntimeCursor,  seq: number | undefined,): { accept: boolean; cursor: RuntimeCursor } {  if (typeof seq !== "number") return { accept: true, cursor };  if (seq <= (cursor.receivedSeq ?? 0)) return { accept: false, cursor };  return { accept: true, cursor: { ...cursor, receivedSeq: seq } };} /** Mark a seq's effects as reduced into session state. Monotonic. */export function commitRuntimeSeq(cursor: RuntimeCursor, seq: number | undefined): RuntimeCursor {  if (typeof seq !== "number" || seq <= (cursor.committedSeq ?? 0)) return cursor;  return { ...cursor, committedSeq: seq };} /** * Adopt a session-level cursor written outside the live stream. Deliberately * NON-monotonic: Pi's per-runtime seq restarts when a new prompt begins on the * same Pi session (`lastEventSeq: 0` on turn accept) and replay hydration * reseeds it (`replayCursorAfterRuntimeHydration`), so resets must move the * gate backwards. Making this monotonic reintroduces the dropped-second-turn * bug. */export function adoptExternalCursor(sessionLastEventSeq?: number): RuntimeCursor {  return { receivedSeq: sessionLastEventSeq, committedSeq: sessionLastEventSeq };} /** * Where a reconnecting SSE subscription resumes from: the highest RECEIVED * seq, not the committed one. An unflushed coalesced delta is still in memory, * so replaying it would double-apply; anything newer has genuinely not been * seen. */export function reconnectAfter(cursor: RuntimeCursor): number {  return cursor.receivedSeq ?? 0;} // A prompt's optimistic "starting" phase deliberately does not subscribe yet:// the runtime can still be idle from the previous turn, and subscribing too// early can receive a final idle status before `/turn` has restarted Pi.export function shouldSubscribeRuntimeEvents(status: string): boolean {  return status === "running" || status === "stopping";}