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(//.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: '\nAutonomous run: fix the agent runner\n' }) t.is(/** @type {any} */ (assembled[0]).role, 'system') t.ok( String(/** @type {any} */ (assembled[1]).content).includes('') ) 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('')) 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('') === 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 }) ) ) })