Files
bare-operating-system/packages/bare-os-coreutils/test/agent-trim-ctx.test.mjs
T
2026-08-18 18:11:34 -04:00

231 lines
7.3 KiB
JavaScript

import test from 'brittle'
import { readFileSync } from 'node:fs'
import vm from 'node:vm'
const STATE_SRC = readFileSync(new URL('../lib/agent/agent-state.js', import.meta.url), 'utf8')
const COMPACT_SRC = readFileSync(
new URL('../lib/agent/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('full-replace') ||
packed.meta.tiers.includes('rolling-summary') ||
packed.meta.tiers.some((x) => String(x).startsWith('tighten-keep'))
)
t.ok(packed.messages.some((m) => bareAgentIsCompactionMessage(m)))
// Last user question survives (Grok assemble keeps it as a wrapped query).
const blob = packed.messages
.map((m) => String(/** @type {any} */ (m).content || ''))
.join('\n')
t.ok(/last files/.test(blob))
t.ok(/<user_query>/.test(blob))
const summary = packed.messages.find((m) => bareAgentIsCompactionMessage(m))
t.ok(summary)
t.ok(
/Primary Request|run_command|\/tmp\/file|Tool Usage/i.test(
String(/** @type {any} */ (summary).content || '')
)
)
t.ok(
/This session is being continued from a previous conversation/.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)
})
test('full-replace assemble keeps last user query and structured summary', async (t) => {
const {
bareAgentAssembleCompactedHistory,
bareAgentBuildStructuredSummary,
bareAgentIsDegenerateSummary,
bareAgentWrapUserQuery,
bareAgentFormatCompactSummaryContent,
bareAgentBeginAutonomousRun,
bareAgentAutonomousShouldContinue,
bareAgentAutonomousContinuationPrompt
} = load()
const assembled = bareAgentAssembleCompactedHistory({
system: { role: 'system', content: 'sys' },
lastUserQuery: 'fix the agent runner',
recent: [{ role: 'assistant', content: 'looking' }],
summaryText: bareAgentFormatCompactSummaryContent(
'1. Primary Request and Intent:\n fix the agent runner\n'
),
reminder: '<system-reminder>\nAutonomous run: fix the agent runner\n</system-reminder>'
})
t.is(/** @type {any} */ (assembled[0]).role, 'system')
t.ok(
String(/** @type {any} */ (assembled[1]).content).includes('<user_query>')
)
t.ok(
String(/** @type {any} */ (assembled[1]).content).includes('fix the agent runner')
)
t.is(/** @type {any} */ (assembled[2]).role, 'assistant')
t.ok(String(/** @type {any} */ (assembled[3]).content).includes('continued from a previous'))
t.ok(String(/** @type {any} */ (assembled[4]).content).includes('<system-reminder>'))
const structured = bareAgentBuildStructuredSummary(
[
[
{ role: 'user', content: 'inspect ~/notes.txt' },
{
role: 'tool',
name: 'read_file',
content: 'ENOENT missing file'
}
]
],
{ maxChars: 2000, perMsg: 80 }
)
t.ok(/1\. Primary Request/.test(structured))
t.ok(/3\. Tool Usage/.test(structured))
t.ok(/notes\.txt|read_file|ENOENT/.test(structured))
t.absent(bareAgentIsDegenerateSummary(structured + '\n'.repeat(5) + 'x'.repeat(80)))
t.ok(bareAgentIsDegenerateSummary('too short'))
t.ok(bareAgentWrapUserQuery('hi').indexOf('<user_query>') === 0)
const started = bareAgentBeginAutonomousRun(
{ autonomous_mode_enabled: false, autonomous_active: false },
{ goal: 'ship compaction', maxRuntimeMs: 120000 }
)
t.ok(started.autonomous_mode_enabled)
t.ok(started.autonomous_active)
t.is(started.autonomous_goal, 'ship compaction')
t.ok(
bareAgentAutonomousShouldContinue(started, {
completed: false,
hasTools: false,
stopRequested: false
})
)
t.absent(
bareAgentAutonomousShouldContinue(started, {
completed: true,
hasTools: false
})
)
t.ok(
/AUTONOMOUS RUN still active/.test(
bareAgentAutonomousContinuationPrompt(started, { remainingMs: 90000 })
)
)
})