test: adapt application and benchmark fixtures to async activation

This commit is contained in:
_Kerman committed 2026-10-12 12:03:37 +08:00
1 parent 08e48f34b5
commit 7ac8f92b70
13 files changed
+62 -22

No files matched your search

@@ -18,8 +18,8 @@
en: 1310a89c351e5bfe
zh: e6386ae10b893c2d
/agent-note-performance-baselines-for-large-session-corpora/decision/measured-endpoints:
en: b4d81575ac574f6f
zh: f4f291ab7ce83094
en: 11937dfa4a349a19
zh: b91a136890fe92e8
/agent-note-performance-baselines-for-large-session-corpora/calibration-evidence:
en: f934c95748dcbfe0
zh: df6a68286c21510f
@@ -37,6 +37,8 @@ The projection cache is part of the list endpoint: each cold row carries cached
Workers are compiled plain-Node processes, each started fresh against a seeded root. They compose the production Session store, projection registry, JSONL persistence, SQLite Session query with `openAt: first-search` on an in-memory index, JSON storage and projection cache, the Web projection set, AgentLoop, and the real `SessionController`. Transport lookups, upload registration, default model selection, and the Workspace registry are inert providers, because no measured path depends on them.
The shared corpus and projection-list controller fixture awaits controller activation and supplies the fixed attachment image policy. Its snapshots therefore include the production `imageLimits` unit; attachment I/O remains outside these workloads. Event corpora, measurement endpoints, and budgets are unchanged.
| Case | Corpus | Samples | Endpoint |
|---|---|---:|---|
| List | 3,000 | 3 | Host boot; first `session.list`; repeated `session.list` in the same process |
@@ -37,6 +37,8 @@ Status: implemented
worker 是编译后的纯 Node 进程,每次都针对已播种根目录全新启动。它们组合生产 Session store、投影注册表、JSONL 持久化、使用 `openAt: first-search` 和内存索引的 SQLite Session query、JSON 存储和投影缓存、Web 投影集合、AgentLoop 以及真实的 `SessionController`。传输查找、上传注册、默认模型选择和 Workspace 注册表使用惰性提供者,因为没有被测路径依赖它们。
语料与 projection-list 共用的控制器夹具等待控制器激活,并提供固定附件图片策略。因此快照包含生产 `imageLimits` 单元;附件 I/O 仍不在这些负载中。事件语料、测量端点和预算保持不变。
| 用例 | 语料 | 样本数 | 终点 |
|---|---|---:|---|
| 列表 | 3,000 | 3 | Host 启动;首次 `session.list`;同一进程中重复的 `session.list` |
+4 -2
View File
@@ -1,3 +1,4 @@
import { agentPresetProjectionDefinition } from '@deepseek-ai/dsh-agent-preset-registry'
import { createRequire } from 'node:module'
import { randomUUID } from 'node:crypto'
import { mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
@@ -730,7 +731,7 @@ describe('a switch survives the session', () => {
// The header keeps the creation fact; the log carries what it runs.
expect(handle.agent.session.header.agentPreset).toBe('standard')
expect(ctx.sessionProjections.stateOf(handle.agent.session, 'agentPreset')).toBe('minimal')
expect(ctx.sessionProjections.checkpoint(handle.agent.session).agentPreset?.val).toBe('minimal')
} finally {
await handle.dispose()
}
@@ -745,7 +746,8 @@ describe('a forked session', () => {
meta: { agentPreset: 'minimal' },
setup: agentCtx => ctx.agentPresets.mount(agentCtx, 'minimal').then(() => undefined),
})
const inherited = ctx.sessionProjections.stateOf(parent.agent.session, 'agentPreset') ?? undefined
const projection = await ctx.sessionProjections.register(agentPresetProjectionDefinition)
const inherited = projection.stateOf(parent.agent.session) ?? undefined
const child = await ctx.agents.create({
sessionId: SessionId('preset-fork-child'),
seed: [],
+3 -3
View File
@@ -465,7 +465,7 @@ it.each([false, true])('starts Creator from Plugins with Coding Tools=%s without
expect(await composer.innerText()).toBe(draft)
expect(await picker.getAttribute('aria-haspopup')).toBe('menu')
expect(await page.getByRole('dialog', { name: 'Add plugin', exact: true }).count()).toBe(0)
expect(scaffold.ctx.sessionProjections.stateOf(creator.session, 'agentPreset')).toBe('cordis')
expect(scaffold.ctx.sessionProjections.checkpoint(creator.session).agentPreset?.val).toBe('cordis')
expect(scaffold.ctx.agentPresets.composedPreset(creator.ctx)).toBe('cordis')
expect(scaffold.ctx.tools.schemas(creator).map(tool => tool.name))
.toEqual(expect.arrayContaining(['cordis_inspect_list', 'cordis_inspect_query', 'plugin_manager']))
@@ -490,9 +490,9 @@ it.each([false, true])('starts Creator from Plugins with Coding Tools=%s without
const next = scaffold.ctx.agents.list().find(agent => agent.id !== creator.id)!
expect(next.id).not.toBe(creator.id)
expect(next.session.header.agentPreset).toBe('standard')
expect(scaffold.ctx.sessionProjections.stateOf(next.session, 'agentPreset')).toBe('standard')
expect(scaffold.ctx.sessionProjections.checkpoint(next.session).agentPreset?.val).toBe('standard')
expect(scaffold.ctx.agentPresets.composedPreset(next.ctx)).toBe('standard')
expect(scaffold.ctx.sessionProjections.stateOf(creator.session, 'agentPreset')).toBe('cordis')
expect(scaffold.ctx.sessionProjections.checkpoint(creator.session).agentPreset?.val).toBe('cordis')
await page.getByRole('button', { name: 'Standard mode', exact: true }).waitFor()
expect(scaffold.ctx.settings.describe().find(row => row.ns === 'ui-settings')?.value).toMatchObject({ enabled: developerTools })
expect(scaffold.ctx.agentPresets.defaultId).toBe('standard')
+1 -1
View File
@@ -72,7 +72,7 @@ describe.each([false, true])('web e2e: selected blank writer held: %s', (held) =
if (!held) {
expect(selectedId).toBe(HELD)
const reclaimed = scaffold.ctx.agents.get(HELD)!
expect(scaffold.ctx.sessionProjections.stateOf(reclaimed.session, 'plan')).toMatchObject({ active: true })
expect(scaffold.ctx.sessionProjections.checkpoint(reclaimed.session).plan?.val).toMatchObject({ active: true })
await expect(scaffold.ctx.sessionPersistence.open(HELD, 'write'))
.rejects.toMatchObject({ name: 'SessionAlreadyOwnedError' })
}
@@ -3,7 +3,7 @@
- button "Close"
- paragraph: “ARCHIVE_ACTIVE run the long command” still has work in progress. Archiving stops it first; you can restore the session later from the “All conversations (show archived)” filter in the sidebar, and the stopped work will not resume on its own.
- list "Work that will be stopped":
- listitem: The turn in progress
- listitem: "1 background job: node -e \"const fs=require('node:fs'); fs.writeFileSync('started.txt', 'started'); setInterval(() => { fs.appendFileSync('heartbeat.txt', '.') }, 200); setTimeout(() => { fs.writeFileSync('finished.txt', 'finished') }, 60000)\""
- listitem: The turn in progress
- button "Cancel"
- button "Stop and archive"
+1 -1
View File
@@ -162,7 +162,7 @@ describe.skipIf(MODE === 'record')('web e2e: archiving a running Session stops i
// A foreground Bash command is a registered job from its start, so the
// Host reports it beside the turn; stopping the turn kills it.
await expect.poll(() => dialog.getByRole('list', { name: 'Work that will be stopped' }).locator('li').allTextContents())
.toEqual(['The turn in progress', `1 background job: ${WAIT_COMMAND}`])
.toEqual([`1 background job: ${WAIT_COMMAND}`, 'The turn in progress'])
// Asking is not archiving: the Host set is untouched, the turn and its
// Bash child keep running, and the row stays in the sidebar.
expect([...scaffold.ctx.workspaceRegistry.archivedSessionIds]).toEqual([])
+2 -2
View File
@@ -43,8 +43,8 @@ async function remote<T>(
}
/** POST one generated Session Remote unary through the API Gateway carrier. */
function sessionRemote<T>(scaffold: WebScaffold, method: string, request: unknown): Promise<RpcResult<T>> {
return remote<T>(scaffold, `session/${method}`, { request })
async function sessionRemote<T>(scaffold: WebScaffold, method: string, request: unknown): Promise<RpcResult<T>> {
return await remote<T>(scaffold, `session/${method}`, { request })
}
/** Poll a synchronous condition (hook-safe; expect.poll is test-body only). */
@@ -7,7 +7,7 @@ import { monitorEventLoopDelay, performance } from 'node:perf_hooks'
import { scheduler, setTimeout as delay } from 'node:timers/promises'
import { Context } from '@deepseek-ai/cordis'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import SessionController from '@deepseek-ai/dsh-api-session-controller'
import type SessionController from '@deepseek-ai/dsh-api-session-controller'
import SessionStore, { SESSION_FORMAT_VERSION, SessionId, SessionLogOffset, type SessionHeader } from '@deepseek-ai/dsh-session'
import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl'
import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
@@ -20,6 +20,7 @@ import { z } from 'zod'
import { generationLogPath, sessionDir, toHeaderLine } from '../../packages/session/session-persistence-jsonl/src/format.ts'
import { compressZstdFrame } from '../../packages/session/session-persistence-jsonl/src/zstd.ts'
import { assertBuiltBenchmarkRuntime } from '../support/built-worker.ts'
import { createBenchmarkSessionController } from './session-controller.ts'
const KEY = 'syntheticProjectionList'
const CWD = '/synthetic-projection-benchmark'
@@ -171,7 +172,7 @@ async function mountHost(ctx: Context, root: string, workload: typeof WORKLOADS[
await ctx.plugin(SessionStore)
await ctx.plugin(AgentRegistry)
await ctx.plugin(SessionProjectionRegistry)
ctx.sessionProjections.register({
await ctx.sessionProjections.register({
key: KEY, stateVersion: 1, stateSchema,
init: header => makeState(Number(header.id.slice('projection-bench-'.length)), workload.baseRows),
apply: state => state,
@@ -200,7 +201,7 @@ async function mountHost(ctx: Context, root: string, workload: typeof WORKLOADS[
ctx.provide('fileUploads', { registerAgentResolver: () => dispose } as never)
ctx.provide('agentDefaultModel', { currentSelection: () => ({ provider: 'synthetic', model: 'generated-model' }) } as never)
ctx.provide('workspaceRegistry', { list: () => [], archivedSessionIds: [] } as never)
return new SessionController(ctx, { nativeOpen: false, ...(listWorkSliceMs === undefined ? {} : { listWorkSliceMs }) }, { canOpenPath: () => false })
return createBenchmarkSessionController(ctx, { nativeOpen: false, ...(listWorkSliceMs === undefined ? {} : { listWorkSliceMs }) })
}
async function memory(): Promise<Memory> {
@@ -0,0 +1,32 @@
/** Session-controller initialization for synthetic corpus workers without attachment I/O. */
import { Service, type Context } from '@deepseek-ai/cordis'
import SessionController, { type Config } from '@deepseek-ai/dsh-api-session-controller'
class BenchmarkSessionController extends SessionController {
initialize(): Promise<void> {
return this[Service.init]()
}
}
/**
* Initialize the controller against the worker's partial Host services.
* @param ctx - worker context owning service disposal.
* @param config - native-opener and list-scheduling settings.
* @returns controller ready for list, search, and fork calls.
*/
export async function createBenchmarkSessionController(ctx: Context, config: Config): Promise<SessionController> {
ctx.provide('attachments', {
imageLimits: {
maxImageBytes: 5 * 1024 * 1024,
maxImagesPerMessage: 20,
maxMessageImageBytes: 100 * 1024 * 1024,
maxImagePixels: 40_000_000,
maxImageDimension: 2000,
mediaTypes: ['image/png'],
},
} as never)
const controller = new BenchmarkSessionController(ctx, config, { canOpenPath: () => false })
await controller.initialize()
return controller
}
@@ -8,7 +8,7 @@ import { Context } from '@deepseek-ai/cordis'
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit'
import { agentPresetProjectionDefinition } from '@deepseek-ai/dsh-agent-preset-registry'
import SessionController from '@deepseek-ai/dsh-api-session-controller'
import type SessionController from '@deepseek-ai/dsh-api-session-controller'
import { currentSessionMessageProjections } from '@deepseek-ai/dsh-session-format-catalog/message-projections'
import { Session, SessionLogOffset } from '@deepseek-ai/dsh-session'
import type { SessionId } from '@deepseek-ai/dsh-session'
@@ -27,6 +27,7 @@ import TokenMeter from '@deepseek-ai/dsh-token-meter'
import { assertBuiltBenchmarkRuntime } from '../support/built-worker.ts'
import { serializeRecord } from '../../packages/storage/storage-json/src/format.ts'
import { ANCHOR_COUNT } from './corpus-shape.ts'
import { createBenchmarkSessionController } from './session-controller.ts'
import {
anchorHeader,
corpusSessionId,
@@ -140,7 +141,7 @@ async function mountHost(root: string): Promise<{ readonly ctx: Context; readonl
await ctx.plugin(SessionProjectionCache, { writeEveryEvents: 200, writeIntervalMs: 5_000 })
// Content search is opt-in; enabled deployments defer the in-memory index to the first search.
await ctx.plugin(SqliteSessionQueryEngine, { path: ':memory:', openAt: 'first-search' })
ctx.sessionProjections.register(agentPresetProjectionDefinition)
await ctx.sessionProjections.register(agentPresetProjectionDefinition)
await ctx.plugin(SessionTitleService, { fallbackMaxWords: 5, fallbackMaxBytes: 40, maxTitleBytes: 80 })
await ctx.plugin(SessionStatsPlugin)
await ctx.plugin(SessionTurnOutlinePlugin)
@@ -152,7 +153,7 @@ async function mountHost(root: string): Promise<{ readonly ctx: Context; readonl
ctx.provide('fileUploads', { registerAgentResolver: () => dispose } as never)
ctx.provide('agentDefaultModel', { currentSelection: () => BENCH_MODEL } as never)
ctx.provide('workspaceRegistry', { list: () => [], archivedSessionIds: [] } as never)
const controller = new SessionController(ctx, { nativeOpen: false }, { canOpenPath: () => false })
const controller = await createBenchmarkSessionController(ctx, { nativeOpen: false })
return { ctx, controller }
}
@@ -30,7 +30,7 @@ import * as SessionTurnOutlinePlugin from '@deepseek-ai/dsh-session-turn-outline
import TokenMeter from '@deepseek-ai/dsh-token-meter'
// These Host-only adapters have no public Node export and are compiled into the benchmark worker.
import { SessionHistoryController } from '../../packages/api/session-controller/src/history.ts'
import { installModelSelectionProjection } from '../../packages/api/session-controller/src/model-selection-projection.ts'
import { modelSelectionProjection } from '../../packages/api/session-controller/src/model-selection-projection.ts'
import { assertBuiltBenchmarkRuntime } from '../support/built-worker.ts'
import { SYNTHETIC_SESSION_ID } from './session-open.constants.ts'
@@ -130,9 +130,9 @@ function memoryDelta(
async function installProjectionSet(ctx: Context, agentLoopOwnsBoundary: boolean): Promise<void> {
// Mirrors projection owners mounted by the base and web-app bundles without timing profile boot.
if (!agentLoopOwnsBoundary) ctx.sessionProjections.register(turnBoundaryProjectionDefinition)
ctx.sessionProjections.register(agentPresetProjectionDefinition)
installModelSelectionProjection(ctx)
if (!agentLoopOwnsBoundary) await ctx.sessionProjections.register(turnBoundaryProjectionDefinition)
await ctx.sessionProjections.register(agentPresetProjectionDefinition)
await ctx.sessionProjections.register(modelSelectionProjection)
await ctx.plugin(SessionTitleService, {
fallbackMaxWords: 5,
fallbackMaxBytes: 40,