From 5605901cdb310d0be049f39869267c06d9fb6567 Mon Sep 17 00:00:00 2001 From: wized2 Date: Mon, 14 Sep 2026 01:50:17 +0000 Subject: [PATCH] fix: handle null payload in compact; cover system-only edge cases compact(null) no longer throws. Tests for null/undefined analyze, system-only payloads, and compact(null). Related to #2 --- src/index.mjs | 6 ++++++ test/basic.test.mjs | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) 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 24f213e..47b1b65 100644 --- a/test/basic.test.mjs +++ b/test/basic.test.mjs @@ -92,3 +92,29 @@ 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); +});