|
|
@@ -2,8 +2,6 @@
|
|
|
|
|
|
import { mkdir, writeFile } from 'node:fs/promises'
|
|
|
import { join } from 'node:path'
|
|
|
-import { releasedV0SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v0-to-v1'
|
|
|
-import type { SessionFormatEvent } from '@deepseek-ai/dsh-session-format'
|
|
|
import { compressZstdFrame } from '../../packages/session/session-persistence-jsonl/src/zstd.ts'
|
|
|
|
|
|
/** Fixed workload parameters used by every Session-opening scenario. */
|
|
|
@@ -25,14 +23,7 @@ const TIME_ZERO = 1_700_000_000_000
|
|
|
/** One body frame per row preserves the historical many-frame workload deterministically. */
|
|
|
const ROWS_PER_FRAME = 1
|
|
|
|
|
|
-interface SyntheticEvent {
|
|
|
- readonly type: string
|
|
|
- readonly seq: number
|
|
|
- readonly time: number
|
|
|
- readonly data: unknown
|
|
|
- readonly sourceEventSeqs?: readonly number[]
|
|
|
- readonly surfaceOp?: 'append'
|
|
|
-}
|
|
|
+type SyntheticPhysicalRow = Readonly<Record<string, unknown>>
|
|
|
|
|
|
/** Complete metadata returned after writing one synthetic source generation. */
|
|
|
export interface SyntheticV0SessionWrite {
|
|
|
@@ -44,50 +35,52 @@ export interface SyntheticV0SessionWrite {
|
|
|
readonly frames: number
|
|
|
}
|
|
|
|
|
|
-function synthesizeEvents(shape: SyntheticV0SessionShape): readonly SyntheticEvent[] {
|
|
|
- const events: SyntheticEvent[] = []
|
|
|
- let seq = 0
|
|
|
- let time = TIME_ZERO
|
|
|
- const push = (type: string, data: unknown, extra: Partial<SyntheticEvent> = {}): number => {
|
|
|
- events.push({ type, seq, time, data, ...extra })
|
|
|
- seq += 1
|
|
|
- time += 1
|
|
|
- return seq - 1
|
|
|
+/** Owns the immutable released-v0 physical layout used only as benchmark input. */
|
|
|
+class ReleasedV0FixtureBuilder {
|
|
|
+ readonly rows: SyntheticPhysicalRow[] = []
|
|
|
+ private seq = 0
|
|
|
+ private time = TIME_ZERO
|
|
|
+
|
|
|
+ get eventCount(): number {
|
|
|
+ return this.seq
|
|
|
+ }
|
|
|
+
|
|
|
+ appendTurns(shape: SyntheticV0SessionShape): void {
|
|
|
+ const reasoningDeltas = Math.floor(shape.textDeltas / 4)
|
|
|
+ for (let turn = 1; turn <= shape.turns; turn += 1) {
|
|
|
+ this.appendTurn(turn, reasoningDeltas, shape.textDeltas)
|
|
|
+ }
|
|
|
}
|
|
|
- const reasoningDeltas = Math.floor(shape.textDeltas / 4)
|
|
|
- for (let turn = 1; turn <= shape.turns; turn += 1) {
|
|
|
- push('turn/start', { turn })
|
|
|
- push('user/message', {
|
|
|
+
|
|
|
+ private appendTurn(turn: number, reasoningDeltaCount: number, textDeltaCount: number): void {
|
|
|
+ this.appendEvent('turn/start', { turn })
|
|
|
+ this.appendEvent('user/message', {
|
|
|
id: `user-${String(turn)}`,
|
|
|
role: 'user',
|
|
|
content: [{ type: 'text', text: `prompt ${String(turn)}` }],
|
|
|
source: { kind: 'user' },
|
|
|
}, { surfaceOp: 'append' })
|
|
|
- push('step/start', { turn, step: 1 })
|
|
|
- const chunkSeqs: number[] = []
|
|
|
- const chunk = (value: unknown): void => {
|
|
|
- chunkSeqs.push(push('assistant/chunk', { turn, step: 1, chunk: value }))
|
|
|
- }
|
|
|
- chunk({ type: 'block-start', index: 0, blockType: 'reasoning' })
|
|
|
- let reasoning = ''
|
|
|
- for (let index = 0; index < reasoningDeltas; index += 1) {
|
|
|
- const delta = `r${String(index)} `
|
|
|
- reasoning += delta
|
|
|
- chunk({ type: 'reasoning-delta', index: 0, text: delta })
|
|
|
- }
|
|
|
- chunk({ type: 'block-end', index: 0, block: { type: 'reasoning', text: reasoning } })
|
|
|
- chunk({ type: 'block-start', index: 1, blockType: 'text' })
|
|
|
- let text = ''
|
|
|
- for (let index = 0; index < shape.textDeltas; index += 1) {
|
|
|
- const delta = `w${String(index)} `
|
|
|
- text += delta
|
|
|
- chunk({ type: 'text-delta', index: 1, text: delta })
|
|
|
- }
|
|
|
- chunk({ type: 'block-end', index: 1, block: { type: 'text', text } })
|
|
|
- const usage = { inputTokens: 100, outputTokens: shape.textDeltas }
|
|
|
- chunk({ type: 'usage', usage })
|
|
|
- chunk({ type: 'finish', reason: { kind: 'stop' } })
|
|
|
- push('assistant/message', {
|
|
|
+ this.appendEvent('step/start', { turn, step: 1 })
|
|
|
+ const firstChunkSeq = this.appendChunk(turn, { type: 'block-start', index: 0, blockType: 'reasoning' })
|
|
|
+ const reasoningDeltas = Array.from(
|
|
|
+ { length: reasoningDeltaCount },
|
|
|
+ (_, index) => `r${String(index)} `,
|
|
|
+ )
|
|
|
+ this.appendDeltas('reasoning', turn, 0, reasoningDeltas)
|
|
|
+ const reasoning = reasoningDeltas.join('')
|
|
|
+ this.appendChunk(turn, { type: 'block-end', index: 0, block: { type: 'reasoning', text: reasoning } })
|
|
|
+ this.appendChunk(turn, { type: 'block-start', index: 1, blockType: 'text' })
|
|
|
+ const textDeltas = Array.from(
|
|
|
+ { length: textDeltaCount },
|
|
|
+ (_, index) => `w${String(index)} `,
|
|
|
+ )
|
|
|
+ this.appendDeltas('text', turn, 1, textDeltas)
|
|
|
+ const text = textDeltas.join('')
|
|
|
+ this.appendChunk(turn, { type: 'block-end', index: 1, block: { type: 'text', text } })
|
|
|
+ const usage = { inputTokens: 100, outputTokens: textDeltaCount }
|
|
|
+ this.appendChunk(turn, { type: 'usage', usage })
|
|
|
+ const lastChunkSeq = this.appendChunk(turn, { type: 'finish', reason: { kind: 'stop' } })
|
|
|
+ this.appendEvent('assistant/message', {
|
|
|
turn,
|
|
|
step: 1,
|
|
|
message: {
|
|
|
@@ -97,11 +90,58 @@ function synthesizeEvents(shape: SyntheticV0SessionShape): readonly SyntheticEve
|
|
|
source: { kind: 'model', provider: 'bench', model: 'bench' },
|
|
|
},
|
|
|
usage,
|
|
|
- }, { sourceEventSeqs: chunkSeqs, surfaceOp: 'append' })
|
|
|
- push('step/end', { turn, step: 1 })
|
|
|
- push('turn/end', { turn, reason: { kind: 'completed' } })
|
|
|
+ }, { sourceEventSeqs: [[firstChunkSeq, lastChunkSeq]], surfaceOp: 'append' })
|
|
|
+ this.appendEvent('step/end', { turn, step: 1 })
|
|
|
+ this.appendEvent('turn/end', { turn, reason: { kind: 'completed' } })
|
|
|
+ }
|
|
|
+
|
|
|
+ private appendChunk(turn: number, chunk: unknown): number {
|
|
|
+ return this.appendEvent('assistant/chunk', { turn, step: 1, chunk })
|
|
|
+ }
|
|
|
+
|
|
|
+ private appendDeltas(
|
|
|
+ kind: 'reasoning' | 'text',
|
|
|
+ turn: number,
|
|
|
+ index: number,
|
|
|
+ deltas: readonly string[],
|
|
|
+ ): void {
|
|
|
+ if (deltas.length < 3) {
|
|
|
+ for (const delta of deltas) {
|
|
|
+ this.appendChunk(turn, {
|
|
|
+ type: `${kind}-delta`,
|
|
|
+ index,
|
|
|
+ text: delta,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.rows.push({
|
|
|
+ type: `${kind}-chunks`,
|
|
|
+ seq0: this.seq,
|
|
|
+ time0: this.time,
|
|
|
+ data: {
|
|
|
+ turn,
|
|
|
+ step: 1,
|
|
|
+ index,
|
|
|
+ dt: Array.from({ length: deltas.length - 1 }, () => 1),
|
|
|
+ texts: deltas,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ this.seq += deltas.length
|
|
|
+ this.time += deltas.length
|
|
|
+ }
|
|
|
+
|
|
|
+ private appendEvent(
|
|
|
+ type: string,
|
|
|
+ data: unknown,
|
|
|
+ extra: Readonly<Record<string, unknown>> = {},
|
|
|
+ ): number {
|
|
|
+ const seq = this.seq
|
|
|
+ this.rows.push({ type, seq, time: this.time, data, ...extra })
|
|
|
+ this.seq += 1
|
|
|
+ this.time += 1
|
|
|
+ return seq
|
|
|
}
|
|
|
- return events
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -114,24 +154,21 @@ export async function writeSyntheticReleasedV0Session(
|
|
|
root: string,
|
|
|
shape: SyntheticV0SessionShape,
|
|
|
): Promise<SyntheticV0SessionWrite> {
|
|
|
- const events = synthesizeEvents(shape)
|
|
|
+ const fixture = new ReleasedV0FixtureBuilder()
|
|
|
+ fixture.appendTurns(shape)
|
|
|
const header = {
|
|
|
+ type: 'session',
|
|
|
version: 0,
|
|
|
id: SYNTHETIC_SESSION_ID,
|
|
|
createdAt: TIME_ZERO,
|
|
|
cwd: SYNTHETIC_SESSION_CWD,
|
|
|
- isSeeded: false,
|
|
|
delegationDepth: 0,
|
|
|
}
|
|
|
- const encoded = releasedV0SessionFormatCodec.encodeArtifact(
|
|
|
- { header, inheritedEventCount: 0, events: events as unknown as readonly SessionFormatEvent[] },
|
|
|
- { packChunks: true },
|
|
|
- )
|
|
|
- const headerLine = `${JSON.stringify(encoded.header)}\n`
|
|
|
+ const headerLine = `${JSON.stringify(header)}\n`
|
|
|
const bodyFrames: Buffer[] = []
|
|
|
let logicalBytes = Buffer.byteLength(headerLine)
|
|
|
- for (let index = 0; index < encoded.rows.length; index += ROWS_PER_FRAME) {
|
|
|
- const rows = encoded.rows.slice(index, index + ROWS_PER_FRAME)
|
|
|
+ for (let index = 0; index < fixture.rows.length; index += ROWS_PER_FRAME) {
|
|
|
+ const rows = fixture.rows.slice(index, index + ROWS_PER_FRAME)
|
|
|
const text = `${rows.map(row => JSON.stringify(row)).join('\n')}\n`
|
|
|
logicalBytes += Buffer.byteLength(text)
|
|
|
bodyFrames.push(await compressZstdFrame(text))
|
|
|
@@ -148,8 +185,8 @@ export async function writeSyntheticReleasedV0Session(
|
|
|
path,
|
|
|
compressedBytes: physical.byteLength,
|
|
|
logicalBytes,
|
|
|
- events: events.length,
|
|
|
- rows: encoded.rows.length,
|
|
|
- frames: encoded.rows.length + 1,
|
|
|
+ events: fixture.eventCount,
|
|
|
+ rows: fixture.rows.length,
|
|
|
+ frames: fixture.rows.length + 1,
|
|
|
}
|
|
|
}
|