|
|
|
|
@@ -209,8 +209,7 @@ async function workspaceContextOf(agent: Agent): Promise<UserMessage> {
|
|
|
|
|
|
|
|
|
|
async function syncWorkspaceContext(ctx: Context, agent: Agent): Promise<void> {
|
|
|
|
|
await agentEvents(ctx, agent).waterfall(
|
|
|
|
|
'agent/pre-step', [],
|
|
|
|
|
{ turn: 1, step: 1, signal: testToolSignal },
|
|
|
|
|
'agent/pre-step', { messages: [], turn: 1, step: 1, signal: testToolSignal },
|
|
|
|
|
async () => ({ kind: 'enter' as const, messages: [] }),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
@@ -245,15 +244,13 @@ async function composeBaselinePrefix(ctx: Context, agent: Agent): Promise<Messag
|
|
|
|
|
const signal = AbortSignal.timeout(1000)
|
|
|
|
|
await agentEvents(ctx, agent).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
[],
|
|
|
|
|
{ turn: 1, step: 1, signal },
|
|
|
|
|
{ messages: [], turn: 1, step: 1, signal },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: [] }),
|
|
|
|
|
)
|
|
|
|
|
const claimed = agent.inbox.claim('next-step', 1)
|
|
|
|
|
const decision = await agentEvents(ctx, agent).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
claimed,
|
|
|
|
|
{ turn: 1, step: 2, signal },
|
|
|
|
|
{ messages: claimed, turn: 1, step: 2, signal },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: claimed }),
|
|
|
|
|
)
|
|
|
|
|
const entered = decision.kind === 'enter' ? decision.messages : []
|
|
|
|
|
@@ -968,8 +965,7 @@ describe('workspace context request injection', () => {
|
|
|
|
|
const original = stubAgent(root)
|
|
|
|
|
await agentEvents(ctx, original).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
[],
|
|
|
|
|
{ turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
{ messages: [], turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: [] }),
|
|
|
|
|
)
|
|
|
|
|
const inserted = original.inbox.nextStep[0]
|
|
|
|
|
@@ -978,12 +974,11 @@ describe('workspace context request injection', () => {
|
|
|
|
|
await fiber.dispose()
|
|
|
|
|
await ctx.plugin(workspaceContext, { dshHome: home, maxBytes: 65536 })
|
|
|
|
|
const resumed = stubAgent(root, [...original.session.events])
|
|
|
|
|
agentEvents(ctx, resumed).emit('agent/session-start', 'resume')
|
|
|
|
|
agentEvents(ctx, resumed).emit('agent/session-start', { source: 'resume' })
|
|
|
|
|
const claimed = resumed.inbox.claim('next-step', 1)
|
|
|
|
|
const decision = await agentEvents(ctx, resumed).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
claimed,
|
|
|
|
|
{ turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
{ messages: claimed, turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: claimed }),
|
|
|
|
|
)
|
|
|
|
|
if (decision.kind !== 'enter') throw new Error('recovered baseline was rejected')
|
|
|
|
|
@@ -1015,8 +1010,7 @@ describe('workspace context request injection', () => {
|
|
|
|
|
const original = stubAgent(root)
|
|
|
|
|
await agentEvents(ctx, original).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
[],
|
|
|
|
|
{ turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
{ messages: [], turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: [] }),
|
|
|
|
|
)
|
|
|
|
|
const stale = original.inbox.nextStep[0]
|
|
|
|
|
@@ -1026,12 +1020,11 @@ describe('workspace context request injection', () => {
|
|
|
|
|
await fiber.dispose()
|
|
|
|
|
await ctx.plugin(workspaceContext, { dshHome: home, maxBytes: 65536 })
|
|
|
|
|
const resumed = stubAgent(root, [...original.session.events])
|
|
|
|
|
agentEvents(ctx, resumed).emit('agent/session-start', 'resume')
|
|
|
|
|
agentEvents(ctx, resumed).emit('agent/session-start', { source: 'resume' })
|
|
|
|
|
const staleClaim = resumed.inbox.claim('next-step', 1)
|
|
|
|
|
const staleDecision = await agentEvents(ctx, resumed).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
staleClaim,
|
|
|
|
|
{ turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
{ messages: staleClaim, turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: staleClaim }),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@@ -1070,8 +1063,7 @@ describe('workspace context request injection', () => {
|
|
|
|
|
const original = stubAgent(root)
|
|
|
|
|
await agentEvents(originalCtx, original).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
[],
|
|
|
|
|
{ turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
{ messages: [], turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: [] }),
|
|
|
|
|
)
|
|
|
|
|
const stale = original.inbox.nextStep[0]
|
|
|
|
|
@@ -1081,12 +1073,11 @@ describe('workspace context request injection', () => {
|
|
|
|
|
if (provideFs) await resumedCtx.plugin(LocalFileSystem, { cwd: '/' })
|
|
|
|
|
await resumedCtx.plugin(workspaceContext, { dshHome: home, maxBytes })
|
|
|
|
|
const resumed = stubAgent(root, [...original.session.events])
|
|
|
|
|
agentEvents(resumedCtx, resumed).emit('agent/session-start', 'resume')
|
|
|
|
|
agentEvents(resumedCtx, resumed).emit('agent/session-start', { source: 'resume' })
|
|
|
|
|
const claimed = resumed.inbox.claim('next-step', 1)
|
|
|
|
|
const decision = await agentEvents(resumedCtx, resumed).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
claimed,
|
|
|
|
|
{ turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
{ messages: claimed, turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: claimed }),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@@ -1188,8 +1179,7 @@ describe('workspace context request injection', () => {
|
|
|
|
|
|
|
|
|
|
const decision = await agentEvents(ctx, agent).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
[prompt],
|
|
|
|
|
{ turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
{ messages: [prompt], turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
() => Promise.resolve(downstream),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@@ -1246,8 +1236,7 @@ describe('workspace context request injection', () => {
|
|
|
|
|
|
|
|
|
|
const decision = await agentEvents(ctx, agent).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
[],
|
|
|
|
|
{ turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
{ messages: [], turn: 1, step: 1, signal: AbortSignal.timeout(1000) },
|
|
|
|
|
() => Promise.resolve(downstream),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@@ -1353,7 +1342,7 @@ describe('workspace context request injection', () => {
|
|
|
|
|
const resumed = stubAgent(root, [...original.session.events])
|
|
|
|
|
|
|
|
|
|
// Resume announces its lifecycle start before the first step.
|
|
|
|
|
agentEvents(ctx, resumed).emit('agent/session-start', 'resume')
|
|
|
|
|
agentEvents(ctx, resumed).emit('agent/session-start', { source: 'resume' })
|
|
|
|
|
await composeBaselinePrefix(ctx, resumed)
|
|
|
|
|
|
|
|
|
|
const baselines = baselineEvents(resumed)
|
|
|
|
|
@@ -1401,7 +1390,7 @@ describe('workspace context request injection', () => {
|
|
|
|
|
await write(join(root, 'AGENTS.md'), 'repo rule')
|
|
|
|
|
const ctx = new Context()
|
|
|
|
|
await mountWorkspaceContext(ctx, { dshHome: home, maxBytes: 65536 })
|
|
|
|
|
ctx.on('agent/pre-step', async (_agent, _messages, _context, next) => {
|
|
|
|
|
ctx.on('agent/pre-step', async (_payload, next) => {
|
|
|
|
|
const decision = await next()
|
|
|
|
|
if (decision.kind === 'reject') return decision
|
|
|
|
|
return {
|
|
|
|
|
@@ -1675,8 +1664,7 @@ describe('workspace context request injection', () => {
|
|
|
|
|
const reason = new Error('cancel prefix')
|
|
|
|
|
const pending = agentEvents(ctx, stubAgent(root)).waterfall(
|
|
|
|
|
'agent/pre-step',
|
|
|
|
|
[],
|
|
|
|
|
{ turn: 1, step: 1, signal: controller.signal },
|
|
|
|
|
{ messages: [], turn: 1, step: 1, signal: controller.signal },
|
|
|
|
|
() => Promise.resolve({ kind: 'enter' as const, messages: [] }),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@@ -3860,8 +3848,7 @@ describe('workspace context inbox synchronization', () => {
|
|
|
|
|
controller.abort(new Error('abort pre-step reconciliation'))
|
|
|
|
|
|
|
|
|
|
await expect(agentEvents(ctx, agent).waterfall(
|
|
|
|
|
'agent/pre-step', [],
|
|
|
|
|
{ turn: 1, step: 1, signal: controller.signal },
|
|
|
|
|
'agent/pre-step', { messages: [], turn: 1, step: 1, signal: controller.signal },
|
|
|
|
|
async () => ({ kind: 'enter' as const, messages: [] }),
|
|
|
|
|
)).rejects.toThrow('abort pre-step reconciliation')
|
|
|
|
|
|
|
|
|
|
@@ -3971,8 +3958,7 @@ describe('workspace context inbox synchronization', () => {
|
|
|
|
|
const downstream = { kind: 'enter' as const, messages: claimed }
|
|
|
|
|
|
|
|
|
|
const decision = await agentEvents(ctx, agent).waterfall(
|
|
|
|
|
'agent/pre-step', claimed,
|
|
|
|
|
{ turn: 1, step: 1, signal: testToolSignal },
|
|
|
|
|
'agent/pre-step', { messages: claimed, turn: 1, step: 1, signal: testToolSignal },
|
|
|
|
|
async () => downstream,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|