feat(coding-agent): added snapcompact savings journaling for imaged tool results

- Added a `snapcompact-savings.jsonl` append-only journal for per-tool savings records.
- Extended `SnapcompactInlineTransformer` to compute `savedTokens` and emit savings to an optional sink.
- Integrated `createSnapcompactSavingsRecorder` into `createAgentSession` for session-aware tool-result metrics.
- Skipped journaling entries without a session and deduped duplicate `toolCallId`s per recorder lifecycle.
- Added tests for savings-sink emissions and savings-journal read/write behavior.
This commit is contained in:
can1357
2026-06-14 04:28:43 +02:00
parent 323c666ebf
commit d63b1530f8
6 changed files with 269 additions and 7 deletions
@@ -115,6 +115,40 @@ describe("SnapcompactInlineTransformer", () => {
expect(result.systemPrompt).toBe(context.systemPrompt);
});
it("reports per-tool-result savings to the sink for each imaged result only", () => {
const received: Array<{ toolCallId: string; savedTokens: number }>[] = [];
let model = "";
const transformer = new SnapcompactInlineTransformer(
{ renderSystemPrompt: "none", renderToolResults: true },
(savings, m) => {
received.push(savings.map(s => ({ ...s })));
model = m.id;
},
);
transformer.transform(makeContext(), makeModel());
// Only the large historical result (call_1) is imaged; call_2 is small,
// call_3 is the most-recent (kept crisp).
expect(received).toHaveLength(1);
expect(received[0]).toHaveLength(1);
expect(received[0][0].toolCallId).toBe("call_1");
expect(received[0][0].savedTokens).toBeGreaterThan(0);
expect(model).toBe("test-model");
});
it("never calls the savings sink when nothing is imaged", () => {
let calls = 0;
const transformer = new SnapcompactInlineTransformer(
{ renderSystemPrompt: "none", renderToolResults: true },
() => {
calls++;
},
);
// Text-only model → vision gate short-circuits before any swap.
transformer.transform(makeContext(), makeModel({ input: ["text"] }));
expect(calls).toBe(0);
});
it("never mutates the input context (persisted history shares these references)", () => {
const transformer = new SnapcompactInlineTransformer({ renderSystemPrompt: "all", renderToolResults: true });
const context = makeContext();