test: adapt application and benchmark fixtures to async activation
This commit is contained in:
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` |
|
||||
|
||||
@@ -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: [],
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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"
|
||||
@@ -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([])
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user