feat: decision tree visualization with React Flow + Dagre auto-layout

This commit is contained in:
Vectry
2026-02-09 23:58:41 +00:00
parent 21b4f9f316
commit 867e1e9eb1
6 changed files with 1151 additions and 24 deletions

View File

@@ -38,7 +38,44 @@ export async function GET(
return NextResponse.json({ error: "Trace not found" }, { status: 404 });
}
return NextResponse.json({ trace }, { status: 200 });
// Transform data to match frontend expectations
const transformedTrace = {
...trace,
decisionPoints: trace.decisionPoints.map((dp) => ({
id: dp.id,
type: dp.type,
chosenAction: typeof dp.chosen === "string" ? dp.chosen : JSON.stringify(dp.chosen),
alternatives: dp.alternatives.map((alt) => (typeof alt === "string" ? alt : JSON.stringify(alt))),
reasoning: dp.reasoning,
contextSnapshot: dp.contextSnapshot as Record<string, unknown> | null,
confidence: null, // Not in schema, default to null
timestamp: dp.timestamp.toISOString(),
parentSpanId: dp.parentSpanId,
})),
spans: trace.spans.map((span) => ({
id: span.id,
name: span.name,
type: span.type,
status: span.status === "COMPLETED" ? "OK" : span.status === "ERROR" ? "ERROR" : "CANCELLED",
startedAt: span.startedAt.toISOString(),
endedAt: span.endedAt?.toISOString() ?? null,
durationMs: span.durationMs,
input: span.input,
output: span.output,
metadata: (span.metadata as Record<string, unknown>) ?? {},
parentSpanId: span.parentSpanId,
})),
events: trace.events.map((event) => ({
id: event.id,
type: event.type,
name: event.name,
timestamp: event.timestamp.toISOString(),
metadata: (event.metadata as Record<string, unknown>) ?? {},
spanId: event.spanId,
})),
};
return NextResponse.json({ trace: transformedTrace }, { status: 200 });
} catch (error) {
console.error("Error retrieving trace:", error);
return NextResponse.json({ error: "Internal server error" }, { status: 500 });