refactor(agent): complete inbox lifecycle migration
This commit is contained in:
@@ -48,6 +48,7 @@ function sessionAgent(session: Session, id = 'agent'): Agent {
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('time-context must append directly to the open step') },
|
||||
cancel() {},
|
||||
runMaintenance: task => task(new AbortController().signal),
|
||||
whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ function sessionAgent(session: Session, id = 'agent'): Agent {
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('tmux-context must append directly to the open step') },
|
||||
cancel() {},
|
||||
runMaintenance: task => task(new AbortController().signal),
|
||||
whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,12 +201,8 @@ export function apply(ctx: Context, config: Config): void {
|
||||
}
|
||||
|
||||
const waitForProjections = async (agent: Agent): Promise<void> => {
|
||||
while (true) {
|
||||
const projection = projectionTails.get(agent)
|
||||
if (projection === undefined) return
|
||||
await projection
|
||||
if (projectionTails.get(agent) === projection) return
|
||||
}
|
||||
let projection: Promise<void> | undefined
|
||||
while ((projection = projectionTails.get(agent)) !== undefined) await projection
|
||||
}
|
||||
|
||||
ctx.on('agent/pre-step', async (
|
||||
|
||||
@@ -182,6 +182,7 @@ function stubAgent(cwd?: string, seed: SessionEvent[] = []): Agent {
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('workspace-context must append directly to the open step') },
|
||||
cancel() {},
|
||||
runMaintenance: task => task(new AbortController().signal),
|
||||
whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
}
|
||||
@@ -2640,7 +2641,13 @@ describe('dynamic nested workspace context injection', () => {
|
||||
warmCache.set(agent.session, new Map(loaded.versions))
|
||||
const options = {
|
||||
authorityMessages,
|
||||
scopeMessages: [],
|
||||
scopeMessages: [createUserMessage({
|
||||
content: [{ type: 'text', text: 'pending baseline duplicate' }],
|
||||
source: {
|
||||
kind: 'workspace-instructions',
|
||||
changes: [{ action: 'set', scope: sk('.', 'AGENTS.md'), path: 'AGENTS.md' }],
|
||||
},
|
||||
})],
|
||||
touchedPaths: [],
|
||||
includeBaselineScopes: false,
|
||||
signal: testToolSignal,
|
||||
@@ -3497,6 +3504,14 @@ describe('dynamic nested workspace context injection', () => {
|
||||
signal: testToolSignal,
|
||||
callId: CallId('null-arguments'), name: 'read', arguments: null, agent,
|
||||
}), plainResult)
|
||||
ctx.emit('tools/result', stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('missing-path'), name: 'read', arguments: {}, agent,
|
||||
}), plainResult)
|
||||
ctx.emit('tools/result', stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('non-string-path'), name: 'read', arguments: { file_path: 1 }, agent,
|
||||
}), plainResult)
|
||||
ctx.emit('tools/result', stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('blank-path'), name: 'read', arguments: { file_path: ' ' }, agent,
|
||||
@@ -3514,6 +3529,35 @@ describe('dynamic nested workspace context injection', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('warns when an asynchronous file-result projection fails', async () => {
|
||||
const ctx = new Context()
|
||||
try {
|
||||
await ctx.plugin(RecordingFileSystem)
|
||||
await ctx.plugin(workspaceContext, { maxBytes: 65536 })
|
||||
const fs = ctx.fs as RecordingFileSystem
|
||||
const agent = stubAgent('/')
|
||||
const failure = new Error('projection failed')
|
||||
const warn = vi.spyOn(ctx.logger, 'warn').mockImplementation(() => undefined)
|
||||
fs.entries.set('/.git', { type: 'directory' })
|
||||
fs.entries.set('/AGENTS.md', { type: 'file', content: 'workspace rule' })
|
||||
vi.spyOn(agent.inbox, 'prepend').mockImplementationOnce(() => { throw failure })
|
||||
|
||||
ctx.emit('tools/result', stubToolExecution({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('projection-failure'),
|
||||
name: 'read',
|
||||
arguments: { file_path: 'file.txt' },
|
||||
agent,
|
||||
}), { content: [], isError: false, value: null })
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(warn).toHaveBeenCalledWith('workspace instruction refresh failed: %o', failure)
|
||||
})
|
||||
} finally {
|
||||
await ctx.fiber.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('does not attach nested instructions when the byte budget is disabled', async () => {
|
||||
const root = await tempRepo()
|
||||
const home = await tempRepo()
|
||||
|
||||
Reference in New Issue
Block a user