File size: 5,849 Bytes
ca6c0e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { Link } from "react-router-dom";
import { Activity, Brain, GitBranch } from "lucide-react";

export default function StepList({ runId, steps = [], n_steps, activeStep, onSelect, status, progress }) {
    const placeholder = Array.from({ length: n_steps || 3 });
    const rows = steps.length
        ? steps
        : placeholder.map((_, i) => ({ step_n: i + 1, _placeholder: true }));
    return (
        <div className="ns-card overflow-hidden" data-testid="step-list">
            <header
                className="flex items-center justify-between px-4 pt-3.5 pb-2"
                style={{ borderBottom: "1px solid var(--ns-border-subtle)" }}
            >
                <span className="ns-section-title">trajectory</span>
                <span className="font-mono text-[10px] text-[color:var(--ns-fg-muted)]">
                    {steps.length}/{n_steps} steps
                </span>
            </header>
            <ul>
                {rows.map((s) => {
                    const isActive = activeStep === s.step_n;
                    const done = !s._placeholder;
                    return (
                        <li
                            key={s.step_n}
                            className="cursor-pointer"
                            style={{
                                background: isActive
                                    ? "var(--ns-bg-surface-2)"
                                    : "transparent",
                                borderLeft: isActive
                                    ? "2px solid var(--ns-accent)"
                                    : "2px solid transparent",
                            }}
                            onClick={() => onSelect && onSelect(s.step_n)}
                            data-testid={`step-list-row-${s.step_n}`}
                        >
                            <div
                                className="flex items-start gap-3 px-4 py-2.5"
                                style={{ borderBottom: "1px solid var(--ns-border-subtle)" }}
                            >
                                <div className="flex flex-col items-center pt-0.5">
                                    <span
                                        className="font-mono text-[10px]"
                                        style={{ color: done ? "var(--ns-accent)" : "var(--ns-fg-muted)" }}
                                    >
                                        s{s.step_n}
                                    </span>
                                    <span
                                        className="mt-1 h-1.5 w-1.5 rounded-full"
                                        style={{
                                            background: done
                                                ? s.hallucination?.flag
                                                    ? "var(--ns-warning)"
                                                    : "var(--ns-success)"
                                                : status === "running" && progress?.completed_steps + 1 === s.step_n
                                                ? "var(--ns-accent)"
                                                : "var(--ns-fg-faint)",
                                        }}
                                    />
                                </div>
                                <div className="min-w-0 flex-1">
                                    <div className="flex items-center gap-2 text-[11px]">
                                        <Brain size={11} color="var(--ns-fg-muted)" />
                                        <span className="truncate text-[color:var(--ns-fg-secondary)]">
                                            {done ? s.output : "…"}
                                        </span>
                                    </div>
                                    {done && (
                                        <div className="mt-1 flex items-center gap-3 font-mono text-[10px] text-[color:var(--ns-fg-muted)]">
                                            <span title="hallucination risk">
                                                <Activity size={9} className="inline" /> risk{" "}
                                                <span style={{ color: s.hallucination.flag ? "var(--ns-warning)" : "var(--ns-fg-secondary)" }}>
                                                    {s.hallucination.composite.toFixed(2)}
                                                </span>
                                            </span>
                                            <span title="tool routed">
                                                <GitBranch size={9} className="inline" />{" "}
                                                {s.tool_called || "—"}
                                            </span>
                                            {runId && (
                                                <Link
                                                    to={`/run/${runId}/step/${s.step_n}`}
                                                    className="ml-auto text-[color:var(--ns-accent)] hover:underline"
                                                    onClick={(e) => e.stopPropagation()}
                                                    data-testid={`step-list-detail-${s.step_n}`}
                                                >
                                                    detail →
                                                </Link>
                                            )}
                                        </div>
                                    )}
                                </div>
                            </div>
                        </li>
                    );
                })}
            </ul>
        </div>
    );
}