|
|
@@ -1,7 +1,7 @@
|
|
|
/** Shared live/prepared observations for Session page and lifecycle consumers. */
|
|
|
|
|
|
import type { Context } from '@deepseek-ai/cordis'
|
|
|
-import { SessionLogOffset } from '@deepseek-ai/dsh-session'
|
|
|
+import { SessionLogOffset, SessionSeq } from '@deepseek-ai/dsh-session'
|
|
|
import type { Session, SessionEvent, SessionHeader, SessionId , SessionLogOffset as SessionLogOffsetType , SessionSeqCursor } from '@deepseek-ai/dsh-session'
|
|
|
import type SessionPersistence from '@deepseek-ai/dsh-session-persistence'
|
|
|
import type {
|
|
|
@@ -21,7 +21,11 @@ export interface SessionObservation extends Disposable {
|
|
|
readonly header: SessionHeader
|
|
|
/** Exact fork-inherited event count paired with {@link header}. */
|
|
|
readonly inheritedEventCount: SessionLogOffsetType
|
|
|
- /** Immutable contiguous events at {@link cursor}. */
|
|
|
+ /**
|
|
|
+ * Immutable contiguous events at {@link cursor}. A live observation
|
|
|
+ * materializes this array on first read, so a consumer that reads only the
|
|
|
+ * header, cursor, or projections never copies the log.
|
|
|
+ */
|
|
|
readonly events: readonly SessionEvent[]
|
|
|
/** Last observed event seq, or -1 for an empty log. */
|
|
|
readonly cursor: SessionSeqCursor
|
|
|
@@ -271,7 +275,10 @@ export class SessionObservationReader {
|
|
|
session: Session,
|
|
|
projectionMode: NonNullable<SessionObservationOptions['projectionMode']>,
|
|
|
): SessionObservation {
|
|
|
- const events = session.snapshotEvents()
|
|
|
+ // The cut is the log length now. The log only appends, so the prefix
|
|
|
+ // below `seq` is the same array whenever a consumer first reads `events`.
|
|
|
+ const seq = session.seq
|
|
|
+ let materialized: readonly SessionEvent[] | undefined
|
|
|
const projections = projectionMode === 'none'
|
|
|
? undefined
|
|
|
: this.ctx.get('sessionProjections')?.snapshot(session)
|
|
|
@@ -281,8 +288,11 @@ export class SessionObservationReader {
|
|
|
source: 'live',
|
|
|
header: session.header,
|
|
|
inheritedEventCount: session.inheritedEventCount,
|
|
|
- events,
|
|
|
- cursor: events.at(-1)?.seq ?? -1,
|
|
|
+ get events() {
|
|
|
+ materialized ??= session.snapshotEvents(SessionLogOffset(0), seq)
|
|
|
+ return materialized
|
|
|
+ },
|
|
|
+ cursor: seq === 0 ? -1 : SessionSeq(seq - 1),
|
|
|
...projections === undefined ? {} : { projections },
|
|
|
retain: () => {
|
|
|
if (disposed) throw new Error(`session observation "${session.id}" is disposed`)
|