import assert from "node:assert/strict"; import test from "node:test"; import { BUSINESS_QUESTIONS, conversationTitle } from "./conversation-presentation.js"; import { localPlan } from "../../../server/routes/asset-assistant/planner.js"; import { projectQuestion } from "../../../server/routes/asset-assistant/privacy.js"; import type { AssistantResult } from "../../../shared/assets/assistant.js"; test("business starters produce supported queries matching their promises even without a language model",()=>{ const plans=BUSINESS_QUESTIONS.map(question=>localPlan(projectQuestion(question,[])).plan); assert.equal(plans[0].analysis,"briefing");assert.equal(plans[0].category,"all"); assert.equal(plans[1].category,"inventory"); assert.deepEqual(new Set([plans[1].groupBy,plans[1].secondaryGroupBy]),new Set(["type","region"])); assert.equal(plans[2].kind,"flow");assert.equal(Date.parse(plans[2].end!)-Date.parse(plans[2].start!),6*86400000); assert.equal(plans[3].category,"abnormal");assert.equal(plans[3].view,"list"); }); test("history titles describe the actual result and keep long questions readable",()=>{ const base={plan:{kind:"assets",category:"inventory",groupBy:"type",filters:{},view:"chart"}} as AssistantResult; assert.equal(conversationTitle("a long question",base),"车型库存"); assert.equal(conversationTitle("a long question",{...base,plan:{...base.plan,category:"pending",view:"list"}}),"待交车清单"); assert.ok(conversationTitle("无法识别的很长很长很长很长很长的问题内容").length<=14); }); test("in-place drilldown keeps its question and previous results available for returning to a parent",async()=>{ const {findConversationResult,replaceAnalysisResult}=await import("./conversation-presentation.js"); const base={resultId:"root",plan:{kind:"assets",category:"inventory",groupBy:"region",filters:{},view:"chart"}} as AssistantResult; const drilled={...base,resultId:"east",plan:{...base.plan,groupBy:"city" as const,filters:{region:["华东"]}}}; const turn={id:1,question:"库存在哪里?",result:base}; const next=replaceAnalysisResult(turn,drilled); assert.equal(next.id,1);assert.equal(next.question,turn.question); assert.equal(next.result,drilled);assert.equal(findConversationResult([next],"root"),base); const restored=replaceAnalysisResult(next,{...base,resultId:"restored"}); assert.equal(findConversationResult([restored],"east"),drilled); assert.equal(restored.resultHistory?.length,2); assert.equal(findConversationResult([restored],"missing"),undefined); }); test("compound drilldown replaces only its section and can return to older child scopes", async () => { const {findConversationResult,replaceAnalysisResult}=await import("./conversation-presentation.js"); const plan={kind:"assets",category:"inventory",groupBy:"region",view:"chart",filters:{}} as const; const stock={resultId:"stock",plan} as AssistantResult; const pending={resultId:"pending",plan:{...plan,category:"pending"}} as AssistantResult; const root={...stock,resultId:"bundle",sections:[ {id:"a",title:"库存",question:"库存多少",display:"chart" as const,result:stock}, {id:"b",title:"待交车",question:"待交车多少",display:"metrics" as const,result:pending}, ]}; const drill={...stock,resultId:"east",plan:{...stock.plan,groupBy:"city" as const,filters:{region:["华东"]}}}; const next=replaceAnalysisResult({id:1,result:root},drill,"stock"); assert.equal(next.result?.resultId,"bundle"); assert.equal(next.result?.sections?.[0].result,drill); assert.equal(next.result?.sections?.[1].result,pending); assert.equal(findConversationResult([next],"stock"),stock); const deeper={...drill,resultId:"city",plan:{...drill.plan,view:"list" as const}}; const deep=replaceAnalysisResult(next,deeper,"east"); assert.equal(deep.result?.sections?.[0].display,"list"); assert.equal(findConversationResult([deep],"east"),drill); const returned=replaceAnalysisResult(deep,{...stock,resultId:"restored"},"stock"); assert.equal(returned.result?.sections?.[0].result?.resultId,"restored"); assert.equal(returned.result?.sections?.[1].result,pending); assert.equal(returned.id,1); });