fix(web-probe): scope trace timing evidence (#741)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -1579,16 +1579,17 @@ async function sampleOnePage(targetPage, { reason, groupSeq, pageRole, targetPag
|
|||||||
};
|
};
|
||||||
const summarize = (selector, limit) => Array.from(document.querySelectorAll(selector)).filter(visible).slice(-limit).map((element, index) => {
|
const summarize = (selector, limit) => Array.from(document.querySelectorAll(selector)).filter(visible).slice(-limit).map((element, index) => {
|
||||||
const rect = element.getBoundingClientRect();
|
const rect = element.getBoundingClientRect();
|
||||||
|
const owner = element.closest('article.message-card, .message-card[data-message-id], article[data-message-id], [data-trace-id]');
|
||||||
return {
|
return {
|
||||||
index,
|
index,
|
||||||
tag: element.tagName.toLowerCase(),
|
tag: element.tagName.toLowerCase(),
|
||||||
testId: element.getAttribute("data-testid"),
|
testId: element.getAttribute("data-testid"),
|
||||||
role: element.getAttribute("role"),
|
role: element.getAttribute("role"),
|
||||||
status: element.getAttribute("data-status") || element.getAttribute("aria-busy") || null,
|
status: element.getAttribute("data-status") || element.getAttribute("aria-busy") || null,
|
||||||
sessionId: element.getAttribute("data-session-id") || null,
|
sessionId: element.getAttribute("data-session-id") || owner?.getAttribute("data-session-id") || null,
|
||||||
messageId: element.getAttribute("data-message-id") || element.getAttribute("id") || null,
|
messageId: element.getAttribute("data-message-id") || owner?.getAttribute("data-message-id") || element.getAttribute("id") || null,
|
||||||
traceId: element.getAttribute("data-trace-id") || null,
|
traceId: element.getAttribute("data-trace-id") || owner?.getAttribute("data-trace-id") || null,
|
||||||
turnId: element.getAttribute("data-turn-id") || null,
|
turnId: element.getAttribute("data-turn-id") || owner?.getAttribute("data-turn-id") || null,
|
||||||
text: textHashInput(element),
|
text: textHashInput(element),
|
||||||
rect: { x: Math.round(rect.x), y: Math.round(rect.y), width: Math.round(rect.width), height: Math.round(rect.height) },
|
rect: { x: Math.round(rect.x), y: Math.round(rect.y), width: Math.round(rect.width), height: Math.round(rect.height) },
|
||||||
};
|
};
|
||||||
@@ -3737,7 +3738,7 @@ function isTerminalTraceText(text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isFinalResultText(text) {
|
function isFinalResultText(text) {
|
||||||
return /已完成第\d+轮|final response|sealed final response|最终结果|已完成[::]/iu.test(String(text || ""));
|
return /已完成第\d+轮|已按第\d+轮完成|final response|sealed final response|最终结果|已完成[::]|smoke\s*测试结果|benchmark|PVC\/workspace|修改文件|Results:/iu.test(String(text || ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSampleMetrics(samples, control) {
|
function buildSampleMetrics(samples, control) {
|
||||||
@@ -4611,7 +4612,7 @@ function buildCodeAgentCardDurationUnderreportedMetrics(samples, timeline) {
|
|||||||
const cardSeconds = Number.isFinite(Number(card.totalElapsedSeconds)) ? Number(card.totalElapsedSeconds) : parsedCardSeconds.length > 0 ? Math.max(...parsedCardSeconds) : NaN;
|
const cardSeconds = Number.isFinite(Number(card.totalElapsedSeconds)) ? Number(card.totalElapsedSeconds) : parsedCardSeconds.length > 0 ? Math.max(...parsedCardSeconds) : NaN;
|
||||||
if (!Number.isFinite(cardSeconds)) continue;
|
if (!Number.isFinite(cardSeconds)) continue;
|
||||||
const traceMatched = traceRows.filter((row) => traceRowMatchesCard(row, card, terminalCards.length));
|
const traceMatched = traceRows.filter((row) => traceRowMatchesCard(row, card, terminalCards.length));
|
||||||
const traceEvidence = maxTraceDurationEvidence(traceMatched.length ? traceMatched : traceRows);
|
const traceEvidence = maxTraceDurationEvidence(traceMatched);
|
||||||
const textEvidence = maxSelfReportedDurationEvidence([card.text, card.preview, card.finalResponseText, card.runningRecordText, terminalCards.length === 1 ? sampleText : ''].filter(Boolean).join('\n'));
|
const textEvidence = maxSelfReportedDurationEvidence([card.text, card.preview, card.finalResponseText, card.runningRecordText, terminalCards.length === 1 ? sampleText : ''].filter(Boolean).join('\n'));
|
||||||
const evidences = [traceEvidence, textEvidence].filter((item) => item && Number.isFinite(item.seconds));
|
const evidences = [traceEvidence, textEvidence].filter((item) => item && Number.isFinite(item.seconds));
|
||||||
if (!evidences.length) continue;
|
if (!evidences.length) continue;
|
||||||
@@ -4812,13 +4813,14 @@ function parseTraceRowTraceId(text) {
|
|||||||
|
|
||||||
function traceRowGroupKey(row) {
|
function traceRowGroupKey(row) {
|
||||||
const identity = row.traceId ? 'trace:' + row.traceId : 'sample:' + (row.sampleIndex ?? '-') + ':' + (row.source || 'unknown');
|
const identity = row.traceId ? 'trace:' + row.traceId : 'sample:' + (row.sampleIndex ?? '-') + ':' + (row.source || 'unknown');
|
||||||
return [row.pageRole || '', row.pageId || '', row.sessionId || '', identity].join('|');
|
return [row.pageRole || '', row.pageId || '', row.sessionId || '', row.source || '', row.sampleIndex ?? '', identity].join('|');
|
||||||
}
|
}
|
||||||
|
|
||||||
function traceRowMatchesCard(row, card, terminalCardCount) {
|
function traceRowMatchesCard(row, card, terminalCardCount) {
|
||||||
if (!row) return false;
|
if (!row) return false;
|
||||||
if (row.traceId && card.traceId) return row.traceId === card.traceId;
|
if (card.traceId) return row.traceId === card.traceId;
|
||||||
if (row.sessionId && card.sessionId) return row.sessionId === card.sessionId;
|
if (row.traceId) return false;
|
||||||
|
if (row.sessionId && card.sessionId) return terminalCardCount === 1 && row.sessionId === card.sessionId;
|
||||||
if (terminalCardCount === 1) return true;
|
if (terminalCardCount === 1) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -5004,6 +5006,7 @@ function isCodeAgentCardTerminal(item) {
|
|||||||
|
|
||||||
function buildRoundCompletionMetrics(samples, timeline, turnTiming) {
|
function buildRoundCompletionMetrics(samples, timeline, turnTiming) {
|
||||||
const events = [];
|
const events = [];
|
||||||
|
const elapsedMismatchToleranceSeconds = Math.max(5, Number(alertThresholds.turnTimingSampleSlackSeconds || 0));
|
||||||
for (let index = 0; index < (Array.isArray(samples) ? samples : []).length; index += 1) {
|
for (let index = 0; index < (Array.isArray(samples) ? samples : []).length; index += 1) {
|
||||||
const sample = samples[index];
|
const sample = samples[index];
|
||||||
const timelineItem = timeline[index] || {};
|
const timelineItem = timeline[index] || {};
|
||||||
@@ -5021,13 +5024,13 @@ function buildRoundCompletionMetrics(samples, timeline, turnTiming) {
|
|||||||
const bestCard = cards.filter((card) => Number.isFinite(Number(card.totalElapsedSeconds)))[0] || null;
|
const bestCard = cards.filter((card) => Number.isFinite(Number(card.totalElapsedSeconds)))[0] || null;
|
||||||
if (Number.isFinite(Number(event.elapsedSeconds)) && bestCard) {
|
if (Number.isFinite(Number(event.elapsedSeconds)) && bestCard) {
|
||||||
const delta = Math.abs(Number(bestCard.totalElapsedSeconds) - Number(event.elapsedSeconds));
|
const delta = Math.abs(Number(bestCard.totalElapsedSeconds) - Number(event.elapsedSeconds));
|
||||||
if (delta > alertThresholds.turnTimingSampleSlackSeconds) {
|
if (delta > elapsedMismatchToleranceSeconds) {
|
||||||
elapsedMismatches.push({
|
elapsedMismatches.push({
|
||||||
...eventRef(event),
|
...eventRef(event),
|
||||||
cardTotalElapsedSeconds: Number(bestCard.totalElapsedSeconds),
|
cardTotalElapsedSeconds: Number(bestCard.totalElapsedSeconds),
|
||||||
completionElapsedSeconds: Number(event.elapsedSeconds),
|
completionElapsedSeconds: Number(event.elapsedSeconds),
|
||||||
deltaSeconds: Number(delta.toFixed(3)),
|
deltaSeconds: Number(delta.toFixed(3)),
|
||||||
toleranceSeconds: alertThresholds.turnTimingSampleSlackSeconds,
|
toleranceSeconds: elapsedMismatchToleranceSeconds,
|
||||||
cardTraceId: bestCard.traceId ?? null,
|
cardTraceId: bestCard.traceId ?? null,
|
||||||
cardMessageId: bestCard.messageId ?? null,
|
cardMessageId: bestCard.messageId ?? null,
|
||||||
valuesRedacted: true
|
valuesRedacted: true
|
||||||
@@ -5127,7 +5130,7 @@ function hasFinalResponseAfterCompletion(samples, timeline, event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sampleHasVisibleFinalResponse(sample, event = {}) {
|
function sampleHasVisibleFinalResponse(sample, event = {}) {
|
||||||
for (const group of [sample?.messages, sample?.turns]) {
|
for (const [groupName, group] of [["messages", sample?.messages], ["turns", sample?.turns]]) {
|
||||||
if (!Array.isArray(group)) continue;
|
if (!Array.isArray(group)) continue;
|
||||||
for (const item of group) {
|
for (const item of group) {
|
||||||
if (event.traceId && item?.traceId && item.traceId !== event.traceId) continue;
|
if (event.traceId && item?.traceId && item.traceId !== event.traceId) continue;
|
||||||
@@ -5135,6 +5138,7 @@ function sampleHasVisibleFinalResponse(sample, event = {}) {
|
|||||||
const text = normalizedText([item?.text, item?.textPreview].filter(Boolean).join(" "));
|
const text = normalizedText([item?.text, item?.textPreview].filter(Boolean).join(" "));
|
||||||
if (text.length < 24) continue;
|
if (text.length < 24) continue;
|
||||||
if (isDiagnosticText(text)) continue;
|
if (isDiagnosticText(text)) continue;
|
||||||
|
if (groupName === "messages" && isTerminalTurnStatus(item?.status)) return true;
|
||||||
if (isFinalResultText(text)) return true;
|
if (isFinalResultText(text)) return true;
|
||||||
if (/运行记录/iu.test(text) && /(?:已完成|完成|新增|实现|验证|测试|结果|README|文件|summary)/iu.test(text)) return true;
|
if (/运行记录/iu.test(text) && /(?:已完成|完成|新增|实现|验证|测试|结果|README|文件|summary)/iu.test(text)) return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user