50 lines
3.8 KiB
JavaScript
50 lines
3.8 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const e = require('../site/engine.js');
|
|
const source = fs.readFileSync(path.join(__dirname,'../sample.jsonl'),'utf8');
|
|
const exchanges = e.parse(source);
|
|
test('parse four complete exchanges and preserve the exact source',()=>{
|
|
assert.equal(exchanges.length,4);assert.equal(exchanges.map(x=>x.raw).join(''),source);
|
|
assert.match(exchanges[1].raw,/tool_call_id/);
|
|
});
|
|
test('pins survive verbatim; whole tool exchange stays paired; chronological output',()=>{
|
|
const budget=e.bytes(e.select(exchanges,{e001:'pinned',e003:'aside'},99999).packet)-e.bytes(e.block(exchanges[2]));
|
|
const result=e.select(exchanges,{e001:'pinned',e003:'aside'},budget);
|
|
assert.deepEqual(result.manifest.exchanges.filter(x=>x.selected).map(x=>x.id),['e001','e002','e004']);
|
|
assert.ok(result.packet.includes(exchanges[0].raw));assert.ok(result.packet.includes(exchanges[1].raw));assert.ok(result.manifest.packetBytes<=budget);
|
|
assert.ok(result.packet.indexOf('## e001')<result.packet.indexOf('## e002'));
|
|
});
|
|
test('pinned minimum is exact, and too-small budget refuses',()=>{
|
|
const pinned=e.select([exchanges[1]],{e002:'pinned'},99999);
|
|
assert.throws(()=>e.select(exchanges,{e002:'pinned'},pinned.manifest.packetBytes-1),/Budget too small/);
|
|
const result=e.select(exchanges,{e002:'pinned'},pinned.manifest.packetBytes);
|
|
assert.deepEqual(result.manifest.exchanges.filter(x=>x.selected).map(x=>x.id),['e002']);
|
|
});
|
|
test('normal beats an earlier aside; oversized normal can be skipped whole',()=>{
|
|
const budget=e.select([exchanges[3]],{},99999).manifest.packetBytes;
|
|
const r=e.select(exchanges,{e001:'aside',e002:'normal',e003:'aside'},budget);
|
|
assert.deepEqual(r.manifest.exchanges.filter(x=>x.selected).map(x=>x.id),['e004']);
|
|
});
|
|
test('bad priorities, budgets, incomplete exchanges and tool mismatches fail closed',()=>{
|
|
for(const n of [-1,NaN,Infinity,1.5])assert.throws(()=>e.select(exchanges,{},n));
|
|
assert.throws(()=>e.select(exchanges,{e999:'pinned'},9999));assert.throws(()=>e.select(exchanges,{e001:'urgent'},9999));
|
|
for(const s of ['', '{broken', '{"role":"user","content":"hi"}\n', '{"type":"system","content":"metadata"}\n', source.replace('"tool_call_id":"schema-1"','"tool_call_id":"wrong"'), source.split('\n').filter(l=>!l.includes('"role":"tool"')).join('\n'), source.split('\n').slice(0,5).join('\n')]) assert.throws(()=>e.parse(s));
|
|
});
|
|
test('message-wrapped tool blocks belong to the same exchange',()=>{
|
|
const rows=[{type:'user',message:{role:'user',content:'read'}},{type:'assistant',message:{role:'assistant',content:[{type:'tool_use',id:'a',name:'read',input:{}}]}},{type:'user',message:{role:'user',content:[{type:'tool_result',tool_use_id:'a',content:'result'}]}},{type:'assistant',message:{role:'assistant',content:'done'}}];
|
|
const raw=rows.map(r=>JSON.stringify(r)).join('\r\n');
|
|
assert.equal(e.parse(raw).length,1);assert.equal(e.parse(raw)[0].raw,raw);
|
|
rows[2].message.content.push({type:'text',text:'new question'});assert.throws(()=>e.parse(rows.map(r=>JSON.stringify(r)).join('\n')),/Mixed/);
|
|
});
|
|
test('fences grow around hostile Markdown and Unicode byte counts are exact',()=>{
|
|
const raw='{"role":"user","content":"```` </script> 🍵"}\n{"role":"assistant","content":"ok"}\n';
|
|
const r=e.select(e.parse(raw),{e001:'pinned'},9999);
|
|
assert.ok(r.packet.includes('`````jsonl'));assert.ok(r.packet.includes(raw));assert.equal(r.manifest.packetBytes,Buffer.byteLength(r.packet));
|
|
});
|
|
test('selection is deterministic and leaves inputs intact',()=>{
|
|
const before=JSON.stringify(exchanges), priorities={e003:'aside'};
|
|
assert.deepEqual(e.select(exchanges,priorities,1000),e.select(exchanges,priorities,1000));assert.equal(JSON.stringify(exchanges),before);assert.deepEqual(priorities,{e003:'aside'});
|
|
});
|