|
|
@@ -48,14 +48,10 @@ interface BenchOptions {
|
|
|
omitSessionQuery?: boolean
|
|
|
/** Leave the persistence service unmounted to exercise the fail-loud path. */
|
|
|
omitPersistence?: boolean
|
|
|
- /** Mount the service but make it report no stored record for any id. */
|
|
|
- unbackedPersistence?: boolean
|
|
|
/** Register a live Agent under `sessionId` before the runner starts. */
|
|
|
prelive?: boolean
|
|
|
/** Header facts for that pre-registered live Agent. */
|
|
|
preliveMeta?: { cwd?: string; origin?: 'subagent'; agentPreset?: string }
|
|
|
- /** Run when the live path reads persistence, e.g. to mutate the live log. */
|
|
|
- onStat?: (agent: Agent) => void
|
|
|
}
|
|
|
|
|
|
const frameStates = new WeakMap<Agent, { attemptId: ReturnType<typeof LlmAttemptId>; revision: number; index: number }>()
|
|
|
@@ -182,14 +178,8 @@ async function bench(script: Script, options: BenchOptions = {}): Promise<{
|
|
|
const observe = options.observe ?? (() => Promise.reject(new SessionQueryError('missing', 'SESSION_QUERY_SESSION_NOT_FOUND')))
|
|
|
ctx.provide('sessionQuery', { observeSession: () => observe() } as never)
|
|
|
}
|
|
|
- let preliveAgent: Agent | undefined
|
|
|
if (options.omitPersistence !== true) {
|
|
|
- ctx.provide('sessionPersistence', {
|
|
|
- stat: () => {
|
|
|
- if (options.onStat !== undefined && preliveAgent !== undefined) options.onStat(preliveAgent)
|
|
|
- return Promise.resolve(options.unbackedPersistence === true ? undefined : { header: {} })
|
|
|
- },
|
|
|
- } as never)
|
|
|
+ ctx.provide('sessionPersistence', {} as never)
|
|
|
}
|
|
|
return {
|
|
|
ctx,
|
|
|
@@ -203,10 +193,10 @@ async function bench(script: Script, options: BenchOptions = {}): Promise<{
|
|
|
ctx.provide('appExit', (code: number) => { order.push('exit'); resolve(code) })
|
|
|
})
|
|
|
if (options.prelive === true || options.preliveMeta !== undefined) {
|
|
|
- preliveAgent = (await ctx.agents.create({
|
|
|
+ await ctx.agents.create({
|
|
|
sessionId: brandString<SessionId>(options.sessionId ?? 'session-exact'),
|
|
|
meta: { cwd: process.cwd(), ...options.preliveMeta },
|
|
|
- })).agent
|
|
|
+ })
|
|
|
}
|
|
|
apply(ctx, {
|
|
|
...options.useStdin === true ? {} : { task: options.task ?? 'do the thing' },
|
|
|
@@ -554,21 +544,6 @@ describe('headless runner', () => {
|
|
|
await test.ctx.fiber.dispose()
|
|
|
})
|
|
|
|
|
|
- it('rejects a live Session the persistence service does not know', async () => {
|
|
|
- const test = await bench({
|
|
|
- afterPrompt(session, message) { appendTurn(session, 1, message, 'live', true) },
|
|
|
- }, {
|
|
|
- sessionId: 'session-exact',
|
|
|
- prelive: true,
|
|
|
- unbackedPersistence: true,
|
|
|
- })
|
|
|
- const result = await test.run()
|
|
|
- expect(result.code).toBe(1)
|
|
|
- expect(result.err).toContain('has no persisted record')
|
|
|
- expect(result.out).toBe('')
|
|
|
- await test.ctx.fiber.dispose()
|
|
|
- })
|
|
|
-
|
|
|
it('resumes the persisted Session when the query finds it', async () => {
|
|
|
const test = await bench({
|
|
|
afterPrompt(session, message) { appendTurn(session, 1, message, 'resumed answer', true) },
|
|
|
@@ -713,14 +688,17 @@ describe('headless runner', () => {
|
|
|
await test.ctx.fiber.dispose()
|
|
|
})
|
|
|
|
|
|
- it('reuses a live Agent already registered under the requested identity', async () => {
|
|
|
+ it('refuses a live Agent identity it cannot own exclusively', async () => {
|
|
|
const test = await bench({
|
|
|
afterPrompt(session, message) { appendTurn(session, 1, message, 'live answer', true) },
|
|
|
}, {
|
|
|
sessionId: 'session-exact',
|
|
|
prelive: true,
|
|
|
})
|
|
|
- expect(await test.run()).toMatchObject({ code: 0, out: 'live answer\n', err: '' })
|
|
|
+ const result = await test.run()
|
|
|
+ expect(result.code).toBe(1)
|
|
|
+ expect(result.err).toContain('is live in this process, so the one-shot runner cannot own an exclusive run interval')
|
|
|
+ expect(result.out).toBe('')
|
|
|
await test.ctx.fiber.dispose()
|
|
|
})
|
|
|
|
|
|
@@ -777,21 +755,6 @@ describe('headless runner', () => {
|
|
|
await test.ctx.fiber.dispose()
|
|
|
})
|
|
|
|
|
|
- it('rejects a preset selected while the runner awaits idle', async () => {
|
|
|
- const test = await bench({
|
|
|
- afterPrompt(session, message) { appendTurn(session, 1, message, 'live', true) },
|
|
|
- }, {
|
|
|
- sessionId: 'session-exact',
|
|
|
- prelive: true,
|
|
|
- onStat: (agent) => { selectPreset(agent.session, 'minimal') },
|
|
|
- })
|
|
|
- const result = await test.run()
|
|
|
- expect(result.code).toBe(1)
|
|
|
- expect(result.err).toContain('runs under agent preset "minimal"')
|
|
|
- expect(result.out).toBe('')
|
|
|
- await test.ctx.fiber.dispose()
|
|
|
- })
|
|
|
-
|
|
|
it('rejects a preset appended after the observation snapshot was taken', async () => {
|
|
|
const test = await bench({ afterPrompt: () => {} }, {
|
|
|
sessionId: 'session-exact',
|