fix(agent): correct session-prefix composition-order docs; scrub messagePrefix in snapshots
Two ds-review-bot findings:
The seam JSDoc claimed extending 'await next()' composes in
registration order — false for the append form: the waterfall unwinds
innermost-first, so appending places later-registered contributions
first. The canonical contribution is now documented as the PREPEND
'[mine, ...await next()]' (registration order on the wire), with the
append form's reverse-order behavior stated explicitly; the ordering
test now uses the canonical pattern in both listeners.
scrubRequestHeaders tokenized only system/tools, so a fixture recording
a composed session prefix would carry its raw text (workspace-specific
churn/leak). The scrubber now maps each header/delta messagePrefix
entry to a {{messagePrefix}} token — count stays a structural fact,
absence stays absent, the empty-array transition stays visible — with
normalize.spec coverage for the header, delta, absence, and odd-shape
paths.
This commit is contained in:
@@ -155,6 +155,38 @@ describe('scrubRequestHeaders', () => {
|
||||
expect(toolsOnly).not.toContain('{{system}}')
|
||||
})
|
||||
|
||||
it('scrubs the header session prefix to one token per message, keeping the count', () => {
|
||||
const ev = headerEvent({
|
||||
config: { model: 'm' },
|
||||
messagePrefix: [
|
||||
{ role: 'user', content: [{ type: 'text', text: 'workspace AGENTS digest' }] },
|
||||
{ role: 'user', content: [{ type: 'text', text: 'skills catalog' }] },
|
||||
],
|
||||
})
|
||||
const out = scrubRequestHeaders(`${headerLine}\n${ev}\n`)
|
||||
expect(out).toContain('"messagePrefix":["{{messagePrefix}}","{{messagePrefix}}"]')
|
||||
expect(out).not.toContain('AGENTS digest')
|
||||
expect(out).not.toContain('skills catalog')
|
||||
// Absence stays absent — a prefix-less header gains no token…
|
||||
expect(scrubRequestHeaders(`${headerLine}\n${headerEvent({ system: 's' })}\n`)).not.toContain('{{messagePrefix}}')
|
||||
// …and a non-array shape passes through untouched.
|
||||
const odd = JSON.stringify({ type: 'request/header', seq: 4, time: 9, data: { header: { config: { model: 'm' }, messagePrefix: 'weird' }, reason: 'initial' } })
|
||||
expect(scrubRequestHeaders(`${headerLine}\n${odd}\n`)).toContain('"messagePrefix":"weird"')
|
||||
})
|
||||
|
||||
it('scrubs a header-delta prefix replacement to one token per message', () => {
|
||||
const delta = JSON.stringify({
|
||||
type: 'request/header-delta', seq: 8, time: 9,
|
||||
data: { messagePrefix: [{ role: 'user', content: [{ type: 'text', text: 'leaked opener' }] }] },
|
||||
})
|
||||
const out = scrubRequestHeaders(`${headerLine}\n${delta}\n`)
|
||||
expect(out).toContain('"messagePrefix":["{{messagePrefix}}"]')
|
||||
expect(out).not.toContain('leaked opener')
|
||||
// The empty-array transition-to-absence stays a structural fact.
|
||||
const toNone = JSON.stringify({ type: 'request/header-delta', seq: 9, time: 9, data: { messagePrefix: [] } })
|
||||
expect(scrubRequestHeaders(`${headerLine}\n${toNone}\n`)).toContain('"messagePrefix":[]')
|
||||
})
|
||||
|
||||
it('leaves a delta with no scrubbable payload byte-identical (config-only, or non-array shapes)', () => {
|
||||
const configOnly = JSON.stringify({ type: 'request/header-delta', seq: 8, time: 9, data: { config: { model: 'm2' } } })
|
||||
const oddShapes = JSON.stringify({ type: 'request/header-delta', seq: 9, time: 9, data: { system: { insert: 'not-an-array' }, tools: null } })
|
||||
|
||||
Reference in New Issue
Block a user