diff --git a/apps/web/tests/agent-preset-selection.e2e.ts b/apps/web/tests/agent-preset-selection.e2e.ts index 49e302c4c3..b153e29dff 100644 --- a/apps/web/tests/agent-preset-selection.e2e.ts +++ b/apps/web/tests/agent-preset-selection.e2e.ts @@ -19,6 +19,7 @@ import { SESSION_FORMAT_VERSION, SessionId as sessionId, type SessionEvent, type SessionHeader, type SessionId, } from '@deepseek-ai/dsh-session' import { snapshotSubagentDescriptor } from '@deepseek-ai/dsh-subagent' +import { createSystemMessage, createUserMessage } from '@deepseek-ai/dsh-llm' import { captureStableAria, compareOrRefreshGolden, launchWebScaffold, seedSession, watchConsole, webSnapshotMode, type WebScaffold, @@ -81,7 +82,8 @@ async function seedWorkspaceSkill(workspaceCwd: string): Promise { /** * A settled one-turn session with no model content: this lane asserts chrome * around a conversation, not a conversation, and a recorded turn would tie - * the golden to a provider's wording for no gain. + * the golden to a provider's wording for no gain. Its empty system head + * belongs to the first step, before the user message. * @returns a tokenized session log ending on a closed turn. */ function seedLog(): string { @@ -89,9 +91,18 @@ function seedLog(): string { const at = (index: number, event: Record): string => JSON.stringify({ ...event, seq: index, time: time + index }) return [ - JSON.stringify({ type: 'session', version: 0, id: '{{sessionId}}', createdAt: time, cwd: '{{cwd}}/workspace' }), + JSON.stringify({ + type: 'session', version: SESSION_FORMAT_VERSION, id: '{{sessionId}}', + createdAt: time, cwd: '{{cwd}}/workspace', isSeeded: false, delegationDepth: 0, + }), at(0, { type: 'turn/start', data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user', rpcId: 'seed' } } } }), - at(1, { + at(1, { type: 'step/start', data: { turn: 1, step: 1 } }), + at(2, { + type: 'system/message', + data: { turn: 1, step: 1, message: createSystemMessage('', '@deepseek-ai/dsh-system-prompt') }, + surfaceOp: 'append', + }), + at(3, { type: 'user/message', data: { id: '00000000-0000-4000-9000-000000000001', @@ -101,8 +112,9 @@ function seedLog(): string { }, surfaceOp: 'append', }), - at(2, { type: 'session/title', data: { title: 'Seeded turn', messageSeqs: [1], source: { kind: 'fallback' } } }), - at(3, { type: 'turn/end', data: { turn: 1, reason: { kind: 'completed' } } }), + at(4, { type: 'session/title', data: { title: 'Seeded turn', messageSeqs: [3], source: { kind: 'fallback' } } }), + at(5, { type: 'step/end', data: { turn: 1, step: 1 } }), + at(6, { type: 'turn/end', data: { turn: 1, reason: { kind: 'completed' } } }), ].join('\n') } @@ -138,10 +150,10 @@ async function seedSubagent(scaffold: WebScaffold, parentId: SessionId): Promise type: 'user/message', seq: 1, time: createdAt + 1, - data: { + data: createUserMessage({ content: [{ type: 'text', text: 'Check the session-header action order.' }], source: { kind: 'user' }, - }, + }), surfaceOp: 'append', }, { diff --git a/apps/web/tests/stats-paged-history.e2e.ts b/apps/web/tests/stats-paged-history.e2e.ts index 6e6174232c..18e2b06edc 100644 --- a/apps/web/tests/stats-paged-history.e2e.ts +++ b/apps/web/tests/stats-paged-history.e2e.ts @@ -1,5 +1,5 @@ // Web e2e scenario: full-session stats over paged history. A deterministic -// 28-turn log (56 surface messages — more than one 50-message history page) +// 28-turn log (56 chat messages — more than one 50-message history page) // seeded cold through the REAL persistence API must render whole-log turn/step // counts from the sessionStats projection on first open, and loading the // older page must NOT change them. This pins the bug the projection fixed: @@ -9,6 +9,8 @@ import { fileURLToPath } from 'node:url' import type { Browser, Page } from 'playwright' import { chromium } from 'playwright' +import { createSystemMessage } from '@deepseek-ai/dsh-llm' +import { SESSION_FORMAT_VERSION } from '@deepseek-ai/dsh-session' import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest' import { assertFixtureInventory, captureStableAria, compareOrRefreshGolden, @@ -21,20 +23,21 @@ const UI_EXPECTED = fileURLToPath(new URL('./expected/stats-paged-history/ui.exp const MODE = webSnapshotMode() const SEED_ID = 'stats-paged-history-web-e2e' -/** Turn count: 2 surface messages per turn, so 28 turns overflow one 50-message page. */ +/** Turn count: 2 chat messages per turn, so 28 turns overflow one 50-message page. */ const TURNS = 28 const FULL_COUNTS = `${TURNS} turns · ${TURNS} steps` /** * Generate the seed: TURNS closed single-step turns of one short user prompt - * and one short assistant reply each. Times are fixed so the fixture is - * byte-deterministic; message ids are synthetic uuids (aria normalizes them). + * and one short assistant reply each. Fixed times pin displayed dates; + * the empty system head precedes every user message in the current format. * @param turns - closed turns to generate. * @returns session.jsonl text for {@link seedSession}. */ function buildSeed(turns: number): string { const lines = [JSON.stringify({ - type: 'session', version: 0, id: '{{sessionId}}', createdAt: 1784974100000, cwd: '{{cwd}}/workspace', + type: 'session', version: SESSION_FORMAT_VERSION, id: '{{sessionId}}', + createdAt: 1784974100000, cwd: '{{cwd}}/workspace', isSeeded: false, delegationDepth: 0, })] let seq = 0 let time = 1784974100000 @@ -43,6 +46,14 @@ function buildSeed(turns: number): string { } for (let turn = 1; turn <= turns; turn++) { at({ type: 'turn/start', data: { turn } }) + at({ type: 'step/start', data: { turn, step: 1 } }) + if (turn === 1) { + at({ + type: 'system/message', + data: { turn, step: 1, message: createSystemMessage('', '@deepseek-ai/dsh-system-prompt') }, + surfaceOp: 'append', + }) + } at({ type: 'user/message', data: { @@ -53,10 +64,10 @@ function buildSeed(turns: number): string { }, surfaceOp: 'append', }) - at({ type: 'step/start', data: { turn, step: 1 } }) at({ type: 'assistant/message', data: { + stream: [], turn, step: 1, message: { @@ -66,7 +77,6 @@ function buildSeed(turns: number): string { source: { kind: 'model', provider: 'snapshot', model: 'snapshot-replier' }, }, }, - sourceEventSeqs: [], surfaceOp: 'append', }) at({ type: 'step/end', data: { turn, step: 1 } })