diff --git a/src/index.mjs b/src/index.mjs index b4a1129..ecb07e4 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -87,6 +87,12 @@ export function compact(payload, opts = {}) { requireNonNegativeNumber("maxToolResultTokens", maxToolResultTokens); if (maxTokens != null) requireNonNegativeNumber("maxTokens", maxTokens); requireNonNegativeNumber("keepLastTurns", keepLastTurns, { integer: true }); + if (payload == null) { + return { + payload: { messages: [] }, + report: { beforeTokens: 0, afterTokens: 0, savedTokens: 0, savedPct: 0, actions: [] }, + }; + } const before = analyzePayload(payload, { counter }).totalTokens; const out = clone(payload); const actions = []; diff --git a/test/basic.test.mjs b/test/basic.test.mjs index b637be4..a9caa39 100644 --- a/test/basic.test.mjs +++ b/test/basic.test.mjs @@ -93,6 +93,32 @@ test("compact rejects invalid budgets before transforming the payload", () => { } }); + +test("analyzePayload null / undefined yields zero tokens", () => { + assert.equal(analyzePayload(null).totalTokens, 0); + assert.equal(analyzePayload(undefined).totalTokens, 0); +}); + +test("analyzePayload system-only object counts system text", () => { + const a = analyzePayload({ system: "You are a careful assistant." }); + assert.ok(a.totalTokens > 0); + assert.ok(a.byRole.system > 0); + assert.equal(a.byRole.user ?? 0, 0); +}); + +test("compact preserves system-only payload under a tight budget", () => { + const payload = { system: "sys", messages: [] }; + const { payload: out, report } = compact(payload, { maxTokens: 1, keepLastTurns: 0 }); + assert.ok(out.system === "sys" || (out.messages && out.messages[0]?.role === "system")); + assert.ok(report.afterTokens >= 0); +}); + +test("compact null payload returns empty messages without throwing", () => { + const { payload: out, report } = compact(null); + assert.deepEqual(out, { messages: [] }); + assert.equal(report.beforeTokens, 0); + assert.equal(report.afterTokens, 0); +}); test("analyzePayload empty messages yields zero tokens", () => { const a = analyzePayload({ messages: [] }); assert.equal(a.totalTokens, 0);