mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-12 04:01:20 +00:00
refactor(session): open journal streams from snapshots
This commit is contained in:
@@ -29,7 +29,11 @@ export interface SessionSnapshot {
|
||||
readonly sessionId: SessionId
|
||||
readonly queue: readonly QueuedMessage[]
|
||||
readonly running: boolean
|
||||
readonly subagent: { readonly address: SubagentAddress; readonly parentAvailable: boolean } | null
|
||||
readonly subagent: {
|
||||
readonly address: SubagentAddress
|
||||
/** Absent until the direct-parent catalog resolves. */
|
||||
readonly parentAvailable?: boolean
|
||||
} | null
|
||||
readonly removed: boolean
|
||||
readonly openState: OpenState
|
||||
readonly openError: ClientFailure | null
|
||||
|
||||
@@ -45,7 +45,7 @@ export const PAGE_MESSAGES = 50
|
||||
export interface SessionOptions {
|
||||
/** Catalog-discovered address selecting non-activating subagent transport. */
|
||||
address?: SubagentAddress
|
||||
/** Whether the exact direct parent Agent was live at the latest catalog read. */
|
||||
/** Whether the exact direct parent Agent was live at the latest catalog read; absent before that read. */
|
||||
parentAvailable?: boolean
|
||||
/**
|
||||
* First ACCEPTED prompt on a blank session (fires at most once, on the
|
||||
@@ -86,7 +86,7 @@ export class Session implements SessionFace {
|
||||
private readonly queueMirror = new SessionQueueMirror()
|
||||
private running = false
|
||||
private address: SubagentAddress | undefined
|
||||
private parentAvailable = false
|
||||
private parentAvailable: boolean | undefined
|
||||
/**
|
||||
* Sticky send marker, private input of the composerPhase derivation: set
|
||||
* synchronously before prompt()'s first await, never reset — the blank →
|
||||
@@ -144,7 +144,7 @@ export class Session implements SessionFace {
|
||||
) {
|
||||
this.projections = options.projections ?? new ProjectionValueStore()
|
||||
this.address = options.address
|
||||
this.parentAvailable = options.parentAvailable ?? false
|
||||
this.parentAvailable = options.parentAvailable
|
||||
this.notifier = new Notifier(() => {
|
||||
this.snapshotCache = this.buildSnapshot()
|
||||
})
|
||||
@@ -467,9 +467,9 @@ export class Session implements SessionFace {
|
||||
* Install or clear the catalog-discovered transport address. A changed
|
||||
* address rebuilds an already-open window through its new history route.
|
||||
* @param address - direct parent/child address, or undefined for ordinary transport.
|
||||
* @param parentAvailable - latest exact-parent availability hint.
|
||||
* @param parentAvailable - latest exact-parent availability hint, or undefined before a catalog read.
|
||||
*/
|
||||
configureSubagent(address: SubagentAddress | undefined, parentAvailable = false): void {
|
||||
configureSubagent(address: SubagentAddress | undefined, parentAvailable?: boolean): void {
|
||||
const same = this.address?.parentSessionId === address?.parentSessionId
|
||||
&& this.address?.childSessionId === address?.childSessionId
|
||||
&& this.address?.mode === address?.mode
|
||||
@@ -623,7 +623,10 @@ export class Session implements SessionFace {
|
||||
running: this.running,
|
||||
subagent: this.address === undefined
|
||||
? null
|
||||
: { address: this.address, parentAvailable: this.parentAvailable },
|
||||
: {
|
||||
address: this.address,
|
||||
...(this.parentAvailable === undefined ? {} : { parentAvailable: this.parentAvailable }),
|
||||
},
|
||||
removed: this.removed,
|
||||
openState: this.openState,
|
||||
openError: this.openError,
|
||||
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
SessionEventEntry,
|
||||
SessionPage,
|
||||
SessionPageRequest,
|
||||
SessionProjectionBaseline,
|
||||
} from '../types.ts'
|
||||
|
||||
export {
|
||||
@@ -30,8 +31,13 @@ export type ClientSessionPageRequest = Omit<SessionPageRequest, 'address' | 'thr
|
||||
/** Complete generated `ctx.remote.session` namespace. */
|
||||
export type SessionRemote = ClientRemote['session']
|
||||
|
||||
/** Opening metadata carried only by a follow snapshot, never by loadOlder pages. */
|
||||
interface SessionJournalPage extends SessionPage {
|
||||
readonly projections?: SessionProjectionBaseline
|
||||
}
|
||||
|
||||
/** One complete publication from the Session journal stream. */
|
||||
export type SessionJournalChange = RemoteJournalChange<SessionPage, SessionEventEntry>
|
||||
export type SessionJournalChange = RemoteJournalChange<SessionJournalPage, SessionEventEntry>
|
||||
|
||||
type SessionControlBaselineFrame = Extract<SessionControlFrame, { type: 'baseline' }>
|
||||
type SessionControlDeltaFrame = Exclude<SessionControlFrame, SessionControlBaselineFrame>
|
||||
@@ -93,7 +99,7 @@ export function createSessionControlStream(
|
||||
|
||||
/** Gateway-owned event journal bound to one ordinary or direct-subagent Session address. */
|
||||
export class SessionEventStream extends RemoteJournalStream<
|
||||
SessionPage,
|
||||
SessionJournalPage,
|
||||
SessionEventEntry,
|
||||
number,
|
||||
ClientSessionPageRequest
|
||||
@@ -126,15 +132,23 @@ export class SessionEventStream extends RemoteJournalStream<
|
||||
|
||||
/** @inheritdoc */
|
||||
protected override async * follow(
|
||||
afterSeq: number | undefined,
|
||||
request: ClientSessionPageRequest,
|
||||
signal: AbortSignal,
|
||||
): AsyncIterable<RemoteJournalFrame<SessionEventEntry, number>> {
|
||||
const request = afterSeq === undefined
|
||||
? { address: this.address }
|
||||
: { address: this.address, afterSeq }
|
||||
for await (const frame of this.remote.session.follow(request, signal)) {
|
||||
if (frame.type === 'opened') {
|
||||
yield frame
|
||||
): AsyncIterable<RemoteJournalFrame<SessionEventEntry, number, SessionJournalPage>> {
|
||||
for await (const frame of this.remote.session.follow({
|
||||
address: this.address,
|
||||
...(request.maxMessages === undefined ? {} : { maxMessages: request.maxMessages }),
|
||||
}, signal)) {
|
||||
if (frame.type === 'snapshot') {
|
||||
yield {
|
||||
type: 'opened',
|
||||
cursor: frame.cursor,
|
||||
page: {
|
||||
events: frame.events,
|
||||
hasMore: frame.hasMore,
|
||||
projections: frame.projections,
|
||||
},
|
||||
}
|
||||
continue
|
||||
}
|
||||
const { type: _type, ...entry } = frame
|
||||
@@ -147,7 +161,7 @@ export class SessionEventStream extends RemoteJournalStream<
|
||||
request: ClientSessionPageRequest,
|
||||
throughSeq: number,
|
||||
signal: AbortSignal,
|
||||
): Promise<SessionPage> {
|
||||
): Promise<SessionJournalPage> {
|
||||
const result = await this.remote.session.page(
|
||||
{ address: this.address, throughSeq, ...request },
|
||||
signal,
|
||||
|
||||
Reference in New Issue
Block a user