diff --git a/scripts/src/hwlab-node-web-observe-collect.ts b/scripts/src/hwlab-node-web-observe-collect.ts index c3483431..c01f5736 100644 --- a/scripts/src/hwlab-node-web-observe-collect.ts +++ b/scripts/src/hwlab-node-web-observe-collect.ts @@ -43,15 +43,23 @@ function unique(values){return Array.from(new Set(values.filter(Boolean)));} function numOrNull(value){const n=Number(value); return Number.isFinite(n)?n:null} function promptIndexOf(value){const n=Number(value); return Number.isInteger(n)&&n>0?n:null} function tsMs(value){const ms=Date.parse(String(value||'')); return Number.isFinite(ms)?ms:null} +function sessionIdFromUrl(value){const match=String(value||'').match(/\\/workbench\\/sessions\\/(ses_[A-Za-z0-9_-]+)/u); return match?match[1]:null} +function commandSessionId(item){return item?.sessionId||item?.detail?.sessionId||item?.input?.sessionId||sessionIdFromUrl(item?.afterUrl)||sessionIdFromUrl(item?.detail?.afterUrl)||null} +function commandTraceId(item){return item?.traceId||item?.detail?.chatSubmit?.traceId||item?.detail?.traceId||item?.input?.traceId||null} function promptCommands(){ const map=new Map(); for(const item of control){ if(item.type!=='sendPrompt'||(item.phase!=='started'&&item.phase!=='completed'&&item.phase!=='failed')) continue; const id=item.commandId||item.seq||String(map.size+1); const existing=map.get(id)||{}; - map.set(id,{...existing,...item,input:{...(existing.input||{}),...(item.input||{})},firstTs:existing.firstTs||item.ts,lastTs:item.ts}); + map.set(id,{...existing,...item,input:{...(existing.input||{}),...(item.input||{})},sessionId:existing.sessionId||commandSessionId(item),traceId:existing.traceId||commandTraceId(item),firstTs:existing.firstTs||item.ts,lastTs:item.ts}); } - return Array.from(map.values()).filter((item)=>tsMs(item.firstTs)!==null).sort((a,b)=>tsMs(a.firstTs)-tsMs(b.firstTs)); + const prompts=Array.from(map.values()).filter((item)=>tsMs(item.firstTs)!==null).sort((a,b)=>tsMs(a.firstTs)-tsMs(b.firstTs)); + const latestSession=samples.slice().reverse().find((sample)=>sample.routeSessionId||sample.activeSessionId); + const sessionId=latestSession?.routeSessionId||latestSession?.activeSessionId||null; + if(!sessionId) return prompts; + const scoped=prompts.filter((item)=>item.sessionId===sessionId); + return scoped.length>0?scoped:prompts; } function segmentFor(index,prompts){ const start=tsMs(prompts[index]?.firstTs); const end=index+1segmentIds.size===0||segmentIds.has(column.traceId)||column.source==='turn') .sort((a,b)=>(a.firstSeq??0)-(b.firstSeq??0)||(a.lastSeq??0)-(b.lastSeq??0)||String(a.label||'').localeCompare(String(b.label||''))); } -function choosePrimaryTraceId(index,segment){ +function choosePrimaryTraceId(index,segment,prompt=null){ + const promptTraceId=commandTraceId(prompt)||prompt?.traceId||null; + if(promptTraceId){ + const segmentIds=new Set(traceIdsFromSamples(segment)); + if(segmentIds.size===0||segmentIds.has(promptTraceId)) return {traceId:promptTraceId,columns:reportColumnsForPrompt(index,segment)}; + } const columns=reportColumnsForPrompt(index,segment); const promptIndex=index+1; const promptColumns=columns.filter((column)=>column.promptIndex===promptIndex); @@ -245,7 +258,7 @@ function turnSummaryRows(){ return [{round:0,commandId:null,commandType:null,userPreview:'(无 sendPrompt control 记录)',userHash:null,userBytes:null,traceId:allTraceIds[0]||null,status:statusFor(samples,allTraceIds[0]||null),elapsedSeconds:null,recentUpdateSeconds:null,marks:'-',firstSeq:samples[0]?.seq??null,lastSeq:samples[samples.length-1]?.seq??null,lastTs:samples[samples.length-1]?.ts??null,finalResponse:finalResponseFor(samples,allTraceIds[0]||null),valuesRedacted:true}]; } return prompts.map((prompt,index)=>{ - const segment=segmentFor(index,prompts); const segmentControls=controlsFor(index,prompts); const selected=choosePrimaryTraceId(index,segment); const traceId=selected.traceId; const user=userMessageFor(segment,prompt); + const segment=segmentFor(index,prompts); const segmentControls=controlsFor(index,prompts); const selected=choosePrimaryTraceId(index,segment,prompt); const traceId=selected.traceId; const user=userMessageFor(segment,prompt); const primaryColumn=selected.columns.find((column)=>column.traceId===traceId)||null; const traceSample=latestSampleForTrace(segment,traceId,primaryColumn?.lastSeq??null); const texts=textsFor(segment,traceId);