147 lines
4.4 KiB
JavaScript
147 lines
4.4 KiB
JavaScript
import test from 'brittle'
|
|
import { readFileSync } from 'node:fs'
|
|
import vm from 'node:vm'
|
|
|
|
const STATE_SRC = readFileSync(new URL('../lib/agent-state.js', import.meta.url), 'utf8')
|
|
const COMPACT_SRC = readFileSync(
|
|
new URL('../lib/agent-compact.js', import.meta.url),
|
|
'utf8'
|
|
)
|
|
|
|
function load() {
|
|
const sandbox = { console, TextEncoder, TextDecoder }
|
|
vm.createContext(sandbox)
|
|
vm.runInContext(STATE_SRC, sandbox)
|
|
vm.runInContext(COMPACT_SRC, sandbox)
|
|
return sandbox
|
|
}
|
|
|
|
test('trim for ctx shrinks system when tools consume budget', async (t) => {
|
|
const { bareAgentTrimMessagesForCtx, bareAgentEstimateTokens } = load()
|
|
const tools = [{ name: 'x', description: 'y'.repeat(8000), parameters: {} }]
|
|
const msgs = [
|
|
{ role: 'system', content: 'S'.repeat(20_000) },
|
|
{ role: 'user', content: 'hello' }
|
|
]
|
|
const out = bareAgentTrimMessagesForCtx(msgs, 4096, {
|
|
tools,
|
|
reserveCompletion: 512
|
|
})
|
|
t.is(out.length, 2)
|
|
t.ok(String(/** @type {any} */ (out[0]).content).length < 20_000)
|
|
t.ok(
|
|
bareAgentEstimateTokens(out) + bareAgentEstimateTokens(tools) + 512 <=
|
|
4096 + 200
|
|
)
|
|
})
|
|
|
|
test('advanced compaction summarizes older turns instead of dropping blindly', async (t) => {
|
|
const { bareAgentCompactMessagesForCtx, bareAgentIsCompactionMessage } = load()
|
|
/** @type {unknown[]} */
|
|
const msgs = [{ role: 'system', content: 'You are Bare OS agent.' }]
|
|
for (let i = 0; i < 20; i++) {
|
|
msgs.push({
|
|
role: 'user',
|
|
content: 'Please inspect /tmp/file-' + i + ' and report status code ' + i
|
|
})
|
|
msgs.push({
|
|
role: 'assistant',
|
|
content: null,
|
|
tool_calls: [
|
|
{
|
|
id: 'c' + i,
|
|
type: 'function',
|
|
function: {
|
|
name: 'run_command',
|
|
arguments: JSON.stringify({ command: 'cat /tmp/file-' + i })
|
|
}
|
|
}
|
|
]
|
|
})
|
|
msgs.push({
|
|
role: 'tool',
|
|
tool_call_id: 'c' + i,
|
|
name: 'run_command',
|
|
content: 'EXIT:0\n' + ('payload-' + i + '-').repeat(400)
|
|
})
|
|
msgs.push({
|
|
role: 'assistant',
|
|
content: 'File ' + i + ' looks fine with exit 0.'
|
|
})
|
|
}
|
|
msgs.push({ role: 'user', content: 'What did we learn about the last files?' })
|
|
|
|
const packed = bareAgentCompactMessagesForCtx(msgs, 4096, {
|
|
reserveCompletion: 256,
|
|
mode: 'aggressive',
|
|
keepRecent: 3,
|
|
toolMaxChars: 400,
|
|
summaryMaxChars: 1800
|
|
})
|
|
t.ok(packed.meta.afterTokens <= packed.meta.budget + 80)
|
|
t.ok(packed.meta.compacted)
|
|
t.ok(
|
|
packed.meta.droppedGroups > 0 ||
|
|
packed.meta.tiers.includes('rolling-summary') ||
|
|
packed.meta.tiers.some((x) => String(x).startsWith('tighten-keep'))
|
|
)
|
|
t.ok(packed.messages.some((m) => bareAgentIsCompactionMessage(m)))
|
|
// Recent user question survives.
|
|
const last = packed.messages[packed.messages.length - 1]
|
|
t.ok(
|
|
String(/** @type {any} */ (last).content || '').includes('last files')
|
|
)
|
|
// Summary mentions tools or paths.
|
|
const summary = packed.messages.find((m) => bareAgentIsCompactionMessage(m))
|
|
t.ok(summary)
|
|
t.ok(
|
|
/run_command|\/tmp\/file|assistant|tool:/i.test(
|
|
String(/** @type {any} */ (summary).content || '')
|
|
)
|
|
)
|
|
})
|
|
|
|
test('compaction mode off falls back to hard trim only', async (t) => {
|
|
const { bareAgentCompactMessagesForCtx } = load()
|
|
const msgs = [
|
|
{ role: 'system', content: 'S'.repeat(5000) },
|
|
{ role: 'user', content: 'a' },
|
|
{ role: 'assistant', content: 'b'.repeat(5000) },
|
|
{ role: 'user', content: 'c' }
|
|
]
|
|
const packed = bareAgentCompactMessagesForCtx(msgs, 2048, {
|
|
mode: 'off',
|
|
reserveCompletion: 256
|
|
})
|
|
t.is(packed.meta.mode, 'off')
|
|
t.ok(packed.meta.afterTokens <= packed.meta.budget + 100)
|
|
})
|
|
|
|
test('fat tool payloads shrink even under soft budget', async (t) => {
|
|
const { bareAgentCompactMessagesForCtx, bareAgentEstimateTokens } = load()
|
|
const msgs = [
|
|
{ role: 'system', content: 'sys' },
|
|
{ role: 'user', content: 'run it' },
|
|
{
|
|
role: 'tool',
|
|
name: 'run_command',
|
|
content: 'X'.repeat(20_000)
|
|
}
|
|
]
|
|
const before = bareAgentEstimateTokens(msgs)
|
|
const packed = bareAgentCompactMessagesForCtx(msgs, 32768, {
|
|
mode: 'auto',
|
|
reserveCompletion: 512,
|
|
toolMaxChars: 1000
|
|
})
|
|
const tool = /** @type {any} */ (
|
|
packed.messages.find(
|
|
(m) => m && /** @type {any} */ (m).role === 'tool'
|
|
)
|
|
)
|
|
t.ok(tool)
|
|
t.ok(String(tool.content).length < 20_000)
|
|
t.ok(packed.meta.afterTokens < before)
|
|
t.ok(packed.meta.tiers.includes('shrink-tools') || packed.meta.compacted)
|
|
})
|