Răsfoiți Sursa

fix(web-tests): author preset and stats seeds in current format

Generated V0 logs put user surfaces before the first step and cannot migrate to a protected V3 system head without changing chronology. Author native current headers, open the first step before the empty system head and user, keep title sequence references aligned, and supply embedded assistant streams.

Give the preset child a current identified user message. Preserve all paging, geometry, preset assertions and committed historical fixtures. Validated both generators red/green through the source seed reader, one full build, all preset/stats/trajectory browser tests (11), and scoped type-aware lint.
Tianyi Cui 3 săptămâni în urmă
părinte
comite
d1e9254454

+ 19 - 7
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<void> {
 /**
  * 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, unknown>): 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',
     },
     {

+ 17 - 7
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 } })