bf8ad0d1ff
Session history was silently clipped to the first 4000 characters of the last 12 messages, so follow-ups could not see timing or audit tables. Keep an append-only tail plus a checkpoint summary, retry overflow in the same request, and expose cache hit rate in admin usage. Co-authored-by: Cursor <cursoragent@cursor.com>
61 lines
3.2 KiB
TypeScript
61 lines
3.2 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
const consultRoute = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8");
|
|
const history = readFileSync(new URL("../src/lib/consultation-session-history.ts", import.meta.url), "utf8");
|
|
const migration = readFileSync(
|
|
new URL("../supabase/migrations/20260906010000_chat_session_context_summary.sql", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const generation = readFileSync(new URL("../src/lib/agent-generation-settings.ts", import.meta.url), "utf8");
|
|
|
|
test("consult history uses the checkpoint tail and puts the summary after the time line", () => {
|
|
assert.match(consultRoute, /consultationHistoryWindow\(chatSession\.messages, contextSummary/);
|
|
assert.match(consultRoute, /SESSION_CONTEXT_SUMMARY_HEADING|consultationUserTurnContent/);
|
|
assert.match(consultRoute, /summaryText: historyWindow\.summaryText/);
|
|
assert.match(history, /【会话摘要(服务端维护)】/);
|
|
const helper = history.slice(history.indexOf("export function consultationUserTurnContent"));
|
|
const timeLine = helper.indexOf("input.currentTime");
|
|
const summaryLine = helper.indexOf("SESSION_CONTEXT_SUMMARY_HEADING");
|
|
const questionLine = helper.indexOf("input.question");
|
|
assert.ok(timeLine >= 0 && summaryLine > timeLine && questionLine > summaryLine);
|
|
});
|
|
|
|
test("consult retries once on context overflow with summary plus the last pair", () => {
|
|
assert.match(consultRoute, /isContextOverflowError/);
|
|
assert.match(consultRoute, /streamWithOverflowRetry/);
|
|
assert.match(consultRoute, /consultationBaseMessages\(true\)/);
|
|
assert.match(consultRoute, /lastConsultationPair\(history\)/);
|
|
assert.match(history, /context_length_exceeded/);
|
|
});
|
|
|
|
test("consult checkpoints the session summary after a successful completion", () => {
|
|
assert.match(consultRoute, /void checkpointConsultationContext\(\)/);
|
|
assert.match(consultRoute, /checkpointSessionContextSummary/);
|
|
assert.match(consultRoute, /context_summary ->>updatedAt|context_summary->>updatedAt/);
|
|
assert.match(consultRoute, /console\.warn\("session context summary failed"/);
|
|
assert.doesNotMatch(consultRoute, /AbortSignal\.timeout\(\s*15/);
|
|
});
|
|
|
|
test("the context summary migration only adds one jsonb column", () => {
|
|
assert.match(migration, /add column if not exists context_summary jsonb null/);
|
|
assert.match(migration, /jsonb_typeof\(context_summary\) = 'object'/);
|
|
assert.match(migration, /grant update \(context_summary\)/);
|
|
assert.doesNotMatch(migration, /create index|backfill|update public\.chat_sessions set/);
|
|
});
|
|
|
|
test("Anthropic history cache is applied only to the last history message", () => {
|
|
assert.match(consultRoute, /cachedHistoryMessage/);
|
|
assert.match(generation, /export function cachedHistoryMessage/);
|
|
const helper = consultRoute.slice(consultRoute.indexOf("const consultationBaseMessages"));
|
|
assert.match(helper, /mapped\.length > 0/);
|
|
assert.match(helper, /cachedHistoryMessage\(mapped\[mapped\.length - 1\]/);
|
|
});
|
|
|
|
test("the published model catalog reads context_window", () => {
|
|
const catalog = readFileSync(new URL("../src/lib/model-catalog.ts", import.meta.url), "utf8");
|
|
assert.match(catalog, /v\.context_window/);
|
|
assert.match(catalog, /contextWindow:/);
|
|
});
|