fix: improve code agent trace visibility
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { createHash, randomBytes } from "node:crypto";
|
||||
|
||||
const OTLP_TIMEOUT_MS = 1500;
|
||||
const MIN_VALID_EPOCH_MS = Date.UTC(2020, 0, 1);
|
||||
const ZERO_TRACE_ID = "00000000000000000000000000000000";
|
||||
const ZERO_SPAN_ID = "0000000000000000";
|
||||
|
||||
@@ -36,8 +37,9 @@ export async function emitCodeAgentOtelSpan(name, traceId, env = process.env, op
|
||||
const endpoint = resolveOtlpTracesEndpoint(env);
|
||||
if (!endpoint || typeof fetch !== "function") return { ok: false, skipped: true, reason: "otlp-endpoint-missing", valuesPrinted: false };
|
||||
const context = codeAgentOtelTraceContext(traceId);
|
||||
const startedAtMs = Number.isFinite(Number(options.startTimeMs)) ? Number(options.startTimeMs) : Date.now();
|
||||
const endedAtMs = Number.isFinite(Number(options.endTimeMs)) ? Number(options.endTimeMs) : Date.now();
|
||||
const now = Date.now();
|
||||
const startedAtMs = epochUnixMs(options.startTimeMs, now);
|
||||
const endedAtMs = epochUnixMs(options.endTimeMs, now);
|
||||
const spanId = nonZeroHex(String(options.spanId ?? randomBytes(8).toString("hex")).slice(0, 16), ZERO_SPAN_ID);
|
||||
const parentSpanId = typeof options.parentSpanId === "string" && /^[0-9a-f]{16}$/u.test(options.parentSpanId) ? options.parentSpanId : context.parentSpanId;
|
||||
const statusCode = options.status === "error" || options.error ? 2 : 1;
|
||||
@@ -120,6 +122,11 @@ function unixNano(ms) {
|
||||
return String(Math.trunc(ms * 1_000_000));
|
||||
}
|
||||
|
||||
function epochUnixMs(value, fallback) {
|
||||
const numeric = Number(value);
|
||||
return Number.isFinite(numeric) && numeric >= MIN_VALID_EPOCH_MS ? numeric : fallback;
|
||||
}
|
||||
|
||||
function firstNonEmpty(...values) {
|
||||
for (const value of values) {
|
||||
const text = String(value ?? "").trim();
|
||||
|
||||
@@ -68,6 +68,8 @@ export function traceDisplayRows(trace: Record<string, unknown> = {}, events: Tr
|
||||
if (lastAssistantRow) rows[lastAssistantRowIndex] = markAssistantRowTerminal(effectiveTrace, lastAssistantRow, completionEvent);
|
||||
else rows.push(traceCompletionSummaryRow(effectiveTrace, completionEvent));
|
||||
}
|
||||
const progressRow = traceBackendProgressSummaryRow(effectiveTrace, rows, events);
|
||||
if (progressRow) rows.push(progressRow);
|
||||
if (rows.length > 0) return rows;
|
||||
if (events.length === 0) return [];
|
||||
return events.filter((event) => !isSuppressedTraceEvent(event)).map((event) => traceDisplayRow(effectiveTrace, event));
|
||||
@@ -373,6 +375,17 @@ function traceNoiseSummaryRow(trace: Record<string, unknown>, events: TraceEvent
|
||||
};
|
||||
}
|
||||
|
||||
function traceBackendProgressSummaryRow(trace: Record<string, unknown>, rows: TraceEventRow[], events: TraceEvent[]): TraceEventRow | null {
|
||||
if (!Array.isArray(events) || events.length === 0) return null;
|
||||
if (rows.some((row) => row.rowId.startsWith("tool:") || /助手|轮次完成/u.test(row.header))) return null;
|
||||
const lastRenderedSeq = Math.max(0, ...rows.map((row) => row.seq ?? 0).filter(Number.isFinite));
|
||||
const hiddenProgress = events.filter((event) => {
|
||||
const seq = numberOrNull(event.seq) ?? 0;
|
||||
return seq > lastRenderedSeq && (isRequestTraceEvent(event) || isSetupTraceEvent(event) || isNoisyTraceEvent(event));
|
||||
});
|
||||
return hiddenProgress.length > 0 ? traceNoiseSummaryRow(trace, hiddenProgress) : null;
|
||||
}
|
||||
|
||||
function traceDisplayRow(trace: Record<string, unknown>, event: TraceEvent): TraceEventRow {
|
||||
const label = readableTraceLabel(event);
|
||||
return {
|
||||
|
||||
@@ -366,6 +366,7 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
|
||||
function applyTurnStatusSnapshot(traceId: string, result: AgentChatResultResponse | TraceSnapshot): void {
|
||||
if (!shouldApplyActiveTraceAuthority(traceId, traceResultSessionId(result))) return;
|
||||
recordActivity(`turn:${firstNonEmptyString(result.lastEventLabel, result.status, result.waitingFor, "status") ?? "status"}`);
|
||||
rememberTurnStatus(traceId, result);
|
||||
syncTurnStatusToMessage(traceId, result);
|
||||
}
|
||||
@@ -572,6 +573,8 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
const authoritySessionId = traceResultSessionId(result);
|
||||
if (!shouldApplyActiveTraceAuthority(traceId, authoritySessionId)) return;
|
||||
const events = Array.isArray(result.events) ? result.events : Array.isArray(result.traceEvents) ? result.traceEvents : [];
|
||||
const activityLabel = firstNonEmptyString(result.lastEventLabel, events.at(-1)?.label, events.at(-1)?.type, result.status);
|
||||
if (events.length > 0 || result.terminal === true || isTerminalMessageStatus(result.status)) recordActivity(`trace:${activityLabel ?? "hydrated"}`);
|
||||
markWorkbenchTraceEventsReceived({ traceId, events, transport: "rest_gap" });
|
||||
updateActiveMessages((source) => source.map((message) => {
|
||||
if (!shouldApplyTraceToMessage(message, traceId, authoritySessionId)) return message;
|
||||
@@ -912,6 +915,7 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
function completeTrace(traceId: string, result: AgentChatResultResponse): void {
|
||||
const authoritySessionId = traceResultSessionId(result);
|
||||
if (!shouldApplyActiveTraceAuthority(traceId, authoritySessionId)) return;
|
||||
recordActivity(`trace:terminal:${firstNonEmptyString(result.lastEventLabel, result.status, "completed") ?? "completed"}`);
|
||||
const terminalStatus = result.status === "completed" ? "completed" : statusFromResult(result.status);
|
||||
const finalText = finalResponseText(result.finalResponse);
|
||||
const errorText = agentErrorDisplayText(result.error);
|
||||
|
||||
Reference in New Issue
Block a user