Skip to content

Commit 3158289

Browse files
samejrericallam
authored andcommitted
Display details as a property table instead of pills
1 parent f17dd64 commit 3158289

File tree

3 files changed

+48
-72
lines changed

3 files changed

+48
-72
lines changed

apps/webapp/app/components/runs/v3/ai/AIChatMessages.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { lazy, Suspense, useState } from "react";
22
import { CodeBlock } from "~/components/code/CodeBlock";
3+
import { Header3 } from "~/components/primitives/Headers";
34
import type { DisplayItem, ToolUse } from "./types";
45

56
// Lazy load streamdown to avoid SSR issues
@@ -45,7 +46,7 @@ function SectionHeader({
4546
}) {
4647
return (
4748
<div className="flex items-center justify-between">
48-
<span className="text-xs font-medium uppercase tracking-wide text-text-dimmed">{label}</span>
49+
<Header3>{label}</Header3>
4950
{right && <div className="flex items-center gap-2">{right}</div>}
5051
</div>
5152
);
Lines changed: 42 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,53 @@
11
import { formatCurrencyAccurate } from "~/utils/numberFormatter";
2+
import { Header3 } from "~/components/primitives/Headers";
23
import type { AISpanData } from "./types";
34

45
export function AITagsRow({ aiData }: { aiData: AISpanData }) {
56
return (
6-
<div className="flex flex-wrap items-center gap-1.5 py-2.5">
7-
<Pill>{aiData.model}</Pill>
8-
{aiData.provider !== "unknown" && <Pill variant="dimmed">{aiData.provider}</Pill>}
9-
{aiData.resolvedProvider && (
10-
<Pill variant="dimmed">via {aiData.resolvedProvider}</Pill>
11-
)}
12-
{aiData.finishReason && <Pill variant="dimmed">{aiData.finishReason}</Pill>}
13-
{aiData.serviceTier && <Pill variant="dimmed">tier: {aiData.serviceTier}</Pill>}
14-
{aiData.toolChoice && <Pill variant="dimmed">tools: {aiData.toolChoice}</Pill>}
15-
{aiData.toolCount != null && aiData.toolCount > 0 && (
16-
<Pill variant="dimmed">
17-
{aiData.toolCount} {aiData.toolCount === 1 ? "tool" : "tools"}
18-
</Pill>
19-
)}
20-
{aiData.messageCount != null && (
21-
<Pill variant="dimmed">
22-
{aiData.messageCount} {aiData.messageCount === 1 ? "msg" : "msgs"}
23-
</Pill>
24-
)}
25-
{aiData.telemetryMetadata &&
26-
Object.entries(aiData.telemetryMetadata).map(([key, value]) => (
27-
<Pill key={key} variant="dimmed">
28-
{key}: {value}
29-
</Pill>
30-
))}
7+
<div className="flex flex-col gap-1 py-2.5">
8+
<div className="flex flex-col text-xs @container">
9+
<MetricRow label="Model" value={aiData.model} />
10+
{aiData.provider !== "unknown" && <MetricRow label="Provider" value={aiData.provider} />}
11+
{aiData.resolvedProvider && (
12+
<MetricRow label="Resolved provider" value={aiData.resolvedProvider} />
13+
)}
14+
{aiData.finishReason && <MetricRow label="Finish reason" value={aiData.finishReason} />}
15+
{aiData.serviceTier && <MetricRow label="Service tier" value={aiData.serviceTier} />}
16+
{aiData.toolChoice && <MetricRow label="Tool choice" value={aiData.toolChoice} />}
17+
{aiData.toolCount != null && aiData.toolCount > 0 && (
18+
<MetricRow
19+
label="Tools provided"
20+
value={`${aiData.toolCount} ${aiData.toolCount === 1 ? "tool" : "tools"}`}
21+
/>
22+
)}
23+
{aiData.messageCount != null && (
24+
<MetricRow
25+
label="Messages"
26+
value={`${aiData.messageCount} ${aiData.messageCount === 1 ? "message" : "messages"}`}
27+
/>
28+
)}
29+
{aiData.telemetryMetadata &&
30+
Object.entries(aiData.telemetryMetadata).map(([key, value]) => (
31+
<MetricRow key={key} label={key} value={value} />
32+
))}
33+
</div>
3134
</div>
3235
);
3336
}
3437

3538
export function AIStatsSummary({ aiData }: { aiData: AISpanData }) {
3639
return (
3740
<div className="flex flex-col gap-1 py-2.5">
38-
<span className="text-xs font-medium uppercase tracking-wide text-text-dimmed">Stats</span>
39-
40-
<div className="flex flex-col text-[11px]">
41+
<Header3>Stats</Header3>
42+
<div className="flex flex-col text-xs @container">
4143
<MetricRow label="Input" value={aiData.inputTokens.toLocaleString()} unit="tokens" />
4244
<MetricRow label="Output" value={aiData.outputTokens.toLocaleString()} unit="tokens" />
4345
{aiData.cachedTokens != null && aiData.cachedTokens > 0 && (
44-
<MetricRow label="Cache read" value={aiData.cachedTokens.toLocaleString()} unit="tokens" />
46+
<MetricRow
47+
label="Cache read"
48+
value={aiData.cachedTokens.toLocaleString()}
49+
unit="tokens"
50+
/>
4551
)}
4652
{aiData.cacheCreationTokens != null && aiData.cacheCreationTokens > 0 && (
4753
<MetricRow
@@ -57,13 +63,7 @@ export function AIStatsSummary({ aiData }: { aiData: AISpanData }) {
5763
unit="tokens"
5864
/>
5965
)}
60-
<MetricRow
61-
label="Total"
62-
value={aiData.totalTokens.toLocaleString()}
63-
unit="tokens"
64-
bold
65-
border
66-
/>
66+
<MetricRow label="Total" value={aiData.totalTokens.toLocaleString()} unit="tokens" bold />
6767

6868
{aiData.totalCost != null && (
6969
<MetricRow label="Cost" value={formatCurrencyAccurate(aiData.totalCost)} />
@@ -84,22 +84,20 @@ function MetricRow({
8484
value,
8585
unit,
8686
bold,
87-
border,
8887
}: {
8988
label: string;
9089
value: string;
9190
unit?: string;
9291
bold?: boolean;
93-
border?: boolean;
9492
}) {
9593
return (
96-
<div
97-
className={`flex items-center justify-between py-1 ${
98-
border ? "border-t border-grid-dimmed" : ""
99-
}`}
100-
>
94+
<div className="grid h-7 grid-cols-[1fr_auto] items-center gap-4 rounded-sm px-1.5 transition odd:bg-charcoal-750/40 @[28rem]:grid-cols-[8rem_1fr] hover:bg-white/[0.04]">
10195
<span className="text-text-dimmed">{label}</span>
102-
<span className={bold ? "font-medium text-text-bright" : "text-text-bright"}>
96+
<span
97+
className={`text-right @[28rem]:text-left ${
98+
bold ? "font-medium text-text-bright" : "text-text-bright"
99+
}`}
100+
>
103101
{value}
104102
{unit && <span className="ml-1 text-text-dimmed">{unit}</span>}
105103
</span>
@@ -113,23 +111,3 @@ function formatTtfc(ms: number): string {
113111
}
114112
return `${Math.round(ms)}ms`;
115113
}
116-
117-
function Pill({
118-
children,
119-
variant = "default",
120-
}: {
121-
children: React.ReactNode;
122-
variant?: "default" | "dimmed";
123-
}) {
124-
return (
125-
<span
126-
className={`inline-flex items-center rounded-sm px-1.5 py-0.5 text-[11px] font-medium ${
127-
variant === "dimmed"
128-
? "bg-charcoal-750 text-text-dimmed"
129-
: "bg-charcoal-700 text-text-bright"
130-
}`}
131-
>
132-
{children}
133-
</span>
134-
);
135-
}

apps/webapp/app/components/runs/v3/ai/AISpanDetails.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { CheckIcon, ClipboardDocumentIcon } from "@heroicons/react/20/solid";
22
import { useState } from "react";
33
import { Button } from "~/components/primitives/Buttons";
4+
import { Header3 } from "~/components/primitives/Headers";
45
import { TabButton, TabContainer } from "~/components/primitives/Tabs";
56
import { useHasAdminAccess } from "~/hooks/useUser";
67
import { AIChatMessages, AssistantResponse } from "./AIChatMessages";
@@ -77,17 +78,15 @@ function OverviewTab({ aiData }: { aiData: AISpanData }) {
7778
const { userText, outputText, outputToolNames } = extractInputOutput(aiData);
7879

7980
return (
80-
<div className="flex flex-col divide-y divide-grid-bright px-3">
81+
<div className="flex flex-col px-3">
8182
{/* Tags + Stats */}
8283
<AITagsRow aiData={aiData} />
8384
<AIStatsSummary aiData={aiData} />
8485

8586
{/* Input (last user prompt) */}
8687
{userText && (
8788
<div className="flex flex-col gap-1 py-2.5">
88-
<span className="text-xs font-medium uppercase tracking-wide text-text-dimmed">
89-
Input
90-
</span>
89+
<Header3>Input</Header3>
9190
<p className="text-sm text-text-bright">{userText}</p>
9291
</div>
9392
)}
@@ -96,9 +95,7 @@ function OverviewTab({ aiData }: { aiData: AISpanData }) {
9695
{outputText && <AssistantResponse text={outputText} headerLabel="Output" />}
9796
{outputToolNames.length > 0 && !outputText && (
9897
<div className="flex flex-col gap-1 py-2.5">
99-
<span className="text-xs font-medium uppercase tracking-wide text-text-dimmed">
100-
Output
101-
</span>
98+
<Header3>Output</Header3>
10299
<p className="text-sm text-text-dimmed">
103100
Called {outputToolNames.length === 1 ? "tool" : "tools"}:{" "}
104101
<span className="font-mono text-text-bright">{outputToolNames.join(", ")}</span>

0 commit comments

Comments
 (0)