cleanup(session): isolate trajectory inspection
This commit is contained in:
@@ -57,16 +57,6 @@ export interface SurfaceFoldResult {
|
||||
replacements: SurfaceFoldReplacement[]
|
||||
}
|
||||
|
||||
/** One append-only surface generation separated from its successor by a replacement. */
|
||||
export interface SurfaceFoldContext {
|
||||
/** Zero-based generation within this session log. */
|
||||
generation: number
|
||||
/** Surface sequences present when this generation froze, or at the current tail. */
|
||||
nodes: number[]
|
||||
/** Replacement operation that created this generation; absent for the initial context. */
|
||||
origin?: SurfaceFoldReplacement
|
||||
}
|
||||
|
||||
/** Readonly live projection of the message-producing session events. */
|
||||
export interface SessionSurface {
|
||||
/** Current surface event sequences in model-visible order. */
|
||||
@@ -270,11 +260,14 @@ function planSurfaceEvent(
|
||||
}
|
||||
}
|
||||
|
||||
/** Commit one validated transition and return replacement metadata when one occurred. */
|
||||
function applySurfacePlan(
|
||||
/** Apply one event and return replacement metadata only when one occurred. */
|
||||
function applySurfaceEvent(
|
||||
state: SurfaceFoldState,
|
||||
plan: SurfacePlan | undefined,
|
||||
event: SessionEvent,
|
||||
expectedSeq: number,
|
||||
events: readonly SessionEvent[],
|
||||
): SurfaceFoldReplacement | undefined {
|
||||
const plan = planSurfaceEvent(state, event, expectedSeq, events)
|
||||
if (plan?.kind === 'append') {
|
||||
state.nodes.push(plan.seq)
|
||||
} else if (plan?.kind === 'replace') {
|
||||
@@ -290,16 +283,6 @@ function applySurfacePlan(
|
||||
}
|
||||
}
|
||||
|
||||
/** Apply one event and return replacement metadata only when one occurred. */
|
||||
function applySurfaceEvent(
|
||||
state: SurfaceFoldState,
|
||||
event: SessionEvent,
|
||||
expectedSeq: number,
|
||||
events: readonly SessionEvent[],
|
||||
): SurfaceFoldReplacement | undefined {
|
||||
return applySurfacePlan(state, planSurfaceEvent(state, event, expectedSeq, events))
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay a complete session log through the canonical surface fold.
|
||||
* @param events - session events in contiguous seq order.
|
||||
@@ -316,34 +299,9 @@ export function foldSurface(events: readonly SessionEvent[]): SurfaceFoldResult
|
||||
return { nodes: [...state.nodes], replacements }
|
||||
}
|
||||
|
||||
/** Reconstruct every surface generation only for consumers that request history. */
|
||||
function foldSurfaceContexts(events: readonly SessionEvent[]): SurfaceFoldContext[] {
|
||||
const state = createFoldState()
|
||||
const contexts: SurfaceFoldContext[] = []
|
||||
let origin: SurfaceFoldReplacement | undefined
|
||||
for (const [index, event] of events.entries()) {
|
||||
const plan = planSurfaceEvent(state, event, index, events)
|
||||
const priorNodes = plan?.kind === 'replace' ? [...state.nodes] : undefined
|
||||
const replacement = applySurfacePlan(state, plan)
|
||||
if (replacement === undefined || priorNodes === undefined) continue
|
||||
contexts.push({
|
||||
generation: state.replaceGeneration - 1,
|
||||
nodes: priorNodes,
|
||||
...(origin === undefined ? {} : { origin }),
|
||||
})
|
||||
origin = replacement
|
||||
}
|
||||
contexts.push({
|
||||
generation: state.replaceGeneration,
|
||||
nodes: [...state.nodes],
|
||||
...(origin === undefined ? {} : { origin }),
|
||||
})
|
||||
return contexts
|
||||
}
|
||||
|
||||
/** Incremental ordered surface view and append-boundary validator. */
|
||||
export class SurfaceManager implements SessionSurface {
|
||||
/** Shared transition state for the live surface. */
|
||||
/** Shared transition state; replacement history is not retained. */
|
||||
private _state = createFoldState()
|
||||
/** Last processed seq; -1 folds a seeded log on first access. */
|
||||
private _lastProcessedSeq = -1
|
||||
@@ -371,18 +329,11 @@ export class SurfaceManager implements SessionSurface {
|
||||
return this._state.nodes
|
||||
}
|
||||
|
||||
/** Surface generations reconstructed on demand without burdening ordinary live sessions. */
|
||||
get contexts(): readonly SurfaceFoldContext[] {
|
||||
if (this._lastProcessedSeq < this.log.length - 1) this._processDelta()
|
||||
return foldSurfaceContexts(this.log)
|
||||
}
|
||||
|
||||
/** Fold events appended since the previous access. */
|
||||
private _processDelta(): void {
|
||||
for (let i = this._lastProcessedSeq + 1; i < this.log.length; i++) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- bounded by the loop condition
|
||||
const event = this.log[i]!
|
||||
applySurfaceEvent(this._state, event, i, this.log)
|
||||
applySurfaceEvent(this._state, this.log[i]!, i, this.log)
|
||||
this._lastProcessedSeq = i
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
isSurfaceEvent,
|
||||
} from '@deepseek-ai/dsh-session'
|
||||
import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import { SurfaceManager } from '../src/surface.ts'
|
||||
|
||||
/** Build a minimal session with turn boundaries and a single user message. */
|
||||
function surfaceSession(): Session {
|
||||
@@ -190,19 +189,6 @@ describe('SurfaceManager', () => {
|
||||
{ seq: 2, start: 0, end: 0, shadowedSeqs: [0] },
|
||||
{ seq: 3, start: 2, end: 1, shadowedSeqs: [2, 1] },
|
||||
])
|
||||
expect(new SurfaceManager(s.events).contexts).toEqual([
|
||||
{ generation: 0, nodes: [0, 1] },
|
||||
{
|
||||
generation: 1,
|
||||
nodes: [2, 1],
|
||||
origin: { seq: 2, start: 0, end: 0, shadowedSeqs: [0] },
|
||||
},
|
||||
{
|
||||
generation: 2,
|
||||
nodes: [3],
|
||||
origin: { seq: 3, start: 2, end: 1, shadowedSeqs: [2, 1] },
|
||||
},
|
||||
])
|
||||
folded.nodes[0] = 99
|
||||
folded.replacements[0]!.shadowedSeqs.push(99)
|
||||
expect(s.surface.nodes).toEqual([3])
|
||||
@@ -218,7 +204,6 @@ describe('SurfaceManager', () => {
|
||||
expect(s.surface.nodes).toEqual([1])
|
||||
const manager = s.surface as unknown as { _state: object }
|
||||
expect(Object.hasOwn(manager._state, 'replacements')).toBe(false)
|
||||
expect(Object.hasOwn(manager, '_contexts')).toBe(false)
|
||||
expect(foldSurface(s.events).replacements).toEqual([
|
||||
{ seq: 1, start: 0, end: 0, shadowedSeqs: [0] },
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user