fix request-messages boundary immutability
This commit is contained in:
@@ -727,9 +727,10 @@ async function runStep(
|
|||||||
// so a listener's session append lands past the boundary and joins the NEXT
|
// so a listener's session append lands past the boundary and joins the NEXT
|
||||||
// request — the same window rule as the `agent/request` waterfall.
|
// request — the same window rule as the `agent/request` waterfall.
|
||||||
const emptyRequestMessages: RequestMessages = deepFreeze({ before: [], after: [] })
|
const emptyRequestMessages: RequestMessages = deepFreeze({ before: [], after: [] })
|
||||||
|
const requestMessagesBoundary = deepFreeze([...boundaryMessages])
|
||||||
const requestMessages = await ctx.waterfall(
|
const requestMessages = await ctx.waterfall(
|
||||||
'agent/request-messages', agent, turn, step, emptyRequestMessages,
|
'agent/request-messages', agent, turn, step, emptyRequestMessages,
|
||||||
{ system, assembly, boundaryMessages, signal },
|
{ system, assembly, boundaryMessages: requestMessagesBoundary, signal },
|
||||||
() => Promise.resolve(emptyRequestMessages),
|
() => Promise.resolve(emptyRequestMessages),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -418,6 +418,29 @@ describe('agent/request-messages (RequestMessages)', () => {
|
|||||||
expect(adapter.requests[0]!.messages).toEqual([{ role: 'user', content: [{ type: 'text', text: 'hi' }] }])
|
expect(adapter.requests[0]!.messages).toEqual([{ role: 'user', content: [{ type: 'text', text: 'hi' }] }])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('the read-only boundary context rejects in-place mutation before the request is built', async () => {
|
||||||
|
const adapter = new MockAdapter([textResponse('ok')])
|
||||||
|
const ctx = await harness(adapter)
|
||||||
|
const agent = ctx.agentLoop.create(AgentId('a1'), { model: 'mock' })
|
||||||
|
|
||||||
|
let mutationError: unknown
|
||||||
|
ctx.on('agent/request-messages', async (_agent, _turn, _step, _messages, context, next): Promise<RequestMessages> => {
|
||||||
|
try {
|
||||||
|
const mutableBoundary = context.boundaryMessages as Message[]
|
||||||
|
mutableBoundary.push({ role: 'user', content: [{ type: 'text', text: 'smuggled' }] })
|
||||||
|
} catch (error: unknown) {
|
||||||
|
mutationError = error
|
||||||
|
}
|
||||||
|
return next()
|
||||||
|
})
|
||||||
|
|
||||||
|
send(agent, 'hi')
|
||||||
|
await waitForIdle(ctx, agent)
|
||||||
|
|
||||||
|
expect(mutationError).toBeInstanceOf(TypeError)
|
||||||
|
expect(adapter.requests[0]!.messages).toEqual([{ role: 'user', content: [{ type: 'text', text: 'hi' }] }])
|
||||||
|
})
|
||||||
|
|
||||||
it('a per-step contribution change is logged as a header delta, so every request stays reconstructable', async () => {
|
it('a per-step contribution change is logged as a header delta, so every request stays reconstructable', async () => {
|
||||||
const adapter = new MockAdapter([
|
const adapter = new MockAdapter([
|
||||||
toolCallResponse('c1', 'echo', { text: 'ping' }),
|
toolCallResponse('c1', 'echo', { text: 'ping' }),
|
||||||
|
|||||||
Reference in New Issue
Block a user