import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; const page = readFileSync(new URL("../src/app/page.tsx", import.meta.url), "utf8"); const listRoute = readFileSync(new URL("../src/app/api/sessions/route.ts", import.meta.url), "utf8"); const itemRoute = readFileSync(new URL("../src/app/api/sessions/[id]/route.ts", import.meta.url), "utf8"); const consultRoute = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8"); const sql = readFileSync( new URL("../supabase/migrations/20260901010000_append_consultation_question.sql", import.meta.url), "utf8", ); const sendSource = page.slice(page.indexOf(" async function send("), page.indexOf("\n\n consultationReplay.current")); test("session list GET omits messages while detail GET returns them", () => { assert.match( listRoute, /SESSION_LIST_COLUMNS = "id,title,theme,model_id,session_type,rectification_case_id,chart_profile_id,chart_profile_name,chart_profile_role,updated_at"/, ); assert.doesNotMatch(listRoute, /select\(SESSION_LIST_COLUMNS\)[\s\S]*messages/); assert.match(itemRoute, /export async function GET/); assert.match( itemRoute, /sessionSelect = "id,title,theme,model_id,messages,session_type,rectification_case_id,chart_profile_id,chart_profile_name,chart_profile_role,updated_at"/, ); assert.match(page, /async function fetchSessionDetail\(/); assert.match(page, /async function ensureSessionMessages\(/); assert.match(page, /session-messages-loading/); assert.match(page, /messagesHydrated: messagesPresent/); }); test("consult reads stored history and never applies the client history field", () => { assert.match(consultRoute, /history: z\s*\.array\([\s\S]*?\)\s*\.max\(20\)\s*\.optional\(\)\s*\.default\(\[\]\)/); assert.match(consultRoute, /const storedHistory = consultationHistoryFromStoredMessages\(chatSession\.messages\)/); assert.match(consultRoute, /const history = storedHistory/); assert.doesNotMatch(consultRoute, /parsed\.data\.history/); assert.match(sendSource, /history: currentSession\.messages\.slice\(-12\)/); }); test("consult appends the user question after reserve and returns session_full", () => { assert.match(consultRoute, /accounting\.rpc\("append_consultation_question"/); assert.match(consultRoute, /error_code === "session_full"/); assert.match(consultRoute, /code: "session_full"/); assert.match(consultRoute, /这段对话已写满,开个新对话继续吧/); assert.match(sql, /create or replace function public\.append_consultation_question/); assert.match(sql, /pg_advisory_xact_lock/); assert.match(sql, /session_type = 'consultation'/); assert.match(sql, /'session_full'::text/); assert.match(sql, /grant execute on function public\.append_consultation_question/); assert.match(sendSource, /caught\.code === "session_full"/); assert.match(sendSource, /label: "开新对话"/); assert.match(sendSource, /continueInNewChat\(\{ question: originalQuestion, theme \}\)/); }); test("PATCH compatibility accepts and ignores a legacy messages write", () => { assert.match(itemRoute, /logIgnoredSessionMessages\(id, user\.id, ignoredMessageCount\(payload\)\)/); assert.match(itemRoute, /if \(!values && payloadHasMessages\(payload\)\) \{/); assert.match(itemRoute, /return NextResponse\.json\(\{ ok: true \}\)/); assert.doesNotMatch(itemRoute, /\.update\(\{[\s\S]*messages:/); });