Skip to content
Merged
6 changes: 3 additions & 3 deletions apps/viewer/app/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ html.dark {
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--border: oklch(0.3023 0 0);
--input: oklch(0.3023 0 0);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
Expand All @@ -140,7 +140,7 @@ html.dark {
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-border: oklch(0.3023 0 0);
--sidebar-ring: oklch(0.556 0 0);
}

Expand Down
21 changes: 18 additions & 3 deletions apps/viewer/app/components/analysis-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Badge } from "~/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { CodeBlock } from "~/components/ui/code-block";
import type { AnalysisCheck } from "~/lib/types";
import { cn } from "~/lib/utils";

export function ContentBlock({ text }: { text: string }) {
try {
Expand Down Expand Up @@ -43,21 +44,30 @@ function titleCase(name: string): string {
export function AnalysisContent({
analysis,
title = "Analysis",
titleClassName,
sectionHeaderClassName,
}: {
analysis: { summary?: string | null; checks?: Record<string, AnalysisCheck> };
title?: string;
titleClassName?: string;
sectionHeaderClassName?: string;
}) {
const checks = Object.entries(analysis.checks ?? {});
return (
<Card>
<CardHeader>
<CardTitle>{title}</CardTitle>
<CardTitle className={titleClassName}>{title}</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{analysis.summary && (
<div>
<div className="flex min-h-[22px] items-center justify-between gap-2 mb-1">
<h5 className="text-xs font-medium text-muted-foreground truncate">
<h5
className={cn(
"text-xs font-medium text-muted-foreground truncate",
sectionHeaderClassName
)}
>
Summary
</h5>
</div>
Expand All @@ -72,7 +82,12 @@ export function AnalysisContent({
return (
<div key={name}>
<div className="flex min-h-[22px] items-center justify-between gap-2 mb-1">
<h5 className="text-xs font-medium text-muted-foreground truncate">
<h5
className={cn(
"text-xs font-medium text-muted-foreground truncate",
sectionHeaderClassName
)}
>
{titleCase(name)}
</h5>
<Badge variant={badge.variant} className={badge.className}>
Expand Down
4 changes: 2 additions & 2 deletions apps/viewer/app/components/page-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function PageTitle({
return (
<h1
className={cn(
"max-w-full min-w-0 grow shrink basis-[max-content] font-mono text-4xl font-normal tracking-tighter",
"max-w-full min-w-0 grow shrink basis-[max-content] font-sans text-4xl font-normal tracking-tighter",
className
)}
{...props}
Expand All @@ -56,7 +56,7 @@ export function PageDetailTitle({
return (
<PageTitle
className={cn(
"truncate pb-1 leading-tight transition-colors cursor-default hover:text-foreground/80",
"grow-0 basis-auto truncate pb-1 leading-tight transition-colors cursor-default hover:text-foreground/80",
className
)}
{...props}
Expand Down
37 changes: 34 additions & 3 deletions apps/viewer/app/components/trajectory/split-json-view.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CodeBlock } from "~/components/ui/code-block";
import { cn } from "~/lib/utils";
import {
formatPayloadLabel,
parseJsonPayloadDisplay,
Expand All @@ -9,10 +10,12 @@ import {
export function SplitJsonView({
display,
labelPrefix = "",
labelClassName,
}: {
display: JsonPayloadDisplay;
/** Root for payload labels, e.g. `observation` or tool name `create`. */
labelPrefix?: string;
labelClassName?: string;
}) {
const { display: tree, blocks } = display;

Expand All @@ -23,7 +26,12 @@ export function SplitJsonView({
<div className="mt-3 space-y-4">
{blocks.map((block) => (
<div key={block.path}>
<code className="mb-2 inline-block bg-muted px-1.5 py-0.5 font-mono text-xs text-foreground">
<code
className={cn(
"mb-2 inline-block bg-muted px-1.5 py-0.5 font-mono text-xs text-foreground",
labelClassName
)}
>
{labelPrefix
? formatPayloadLabel(labelPrefix, block.path)
: block.path}
Expand All @@ -37,20 +45,34 @@ export function SplitJsonView({
);
}

function formatJsonValue(value: unknown): string {
export function formatJsonValue(value: unknown): string {
try {
return JSON.stringify(value, null, 2) ?? String(value);
} catch {
return String(value);
}
}

export function getSplitJsonCodeBlocks(value: unknown) {
if (value === null || typeof value !== "object") {
return [{ code: formatJsonValue(value), lang: "json" }];
}

const { display, blocks } = splitJsonForDisplay(value);
return [
{ code: JSON.stringify(display, null, 2), lang: "json" },
...blocks.map((block) => ({ code: block.text, lang: "text" })),
];
}

export function SplitJsonViewFromValue({
value,
labelPrefix,
labelClassName,
}: {
value: unknown;
labelPrefix?: string;
labelClassName?: string;
}) {
if (value === null || typeof value !== "object") {
return <CodeBlock code={formatJsonValue(value)} lang="json" wrap />;
Expand All @@ -59,20 +81,29 @@ export function SplitJsonViewFromValue({
<SplitJsonView
display={splitJsonForDisplay(value)}
labelPrefix={labelPrefix}
labelClassName={labelClassName}
/>
);
}

export function SplitJsonViewFromText({
text,
labelPrefix = "observation",
labelClassName,
}: {
text: string;
labelPrefix?: string;
labelClassName?: string;
}) {
const split = parseJsonPayloadDisplay(text);
if (split === null) {
return null;
}
return <SplitJsonView display={split} labelPrefix={labelPrefix} />;
return (
<SplitJsonView
display={split}
labelPrefix={labelPrefix}
labelClassName={labelClassName}
/>
);
}
10 changes: 7 additions & 3 deletions apps/viewer/app/lib/highlighter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ export async function highlight(
const themes = options.themes ?? defaultThemes;
const cacheKey = `${options.lang}:${themes.light}:${themes.dark}:${code}`;

const cached = cache.get(cacheKey);
if (cached) return cached;
if (!options.components) {
const cached = cache.get(cacheKey);
if (cached) return cached;
}

const promise = (async () => {
const highlighter = await getHighlighter();
Expand Down Expand Up @@ -111,7 +113,9 @@ export async function highlight(
return hastToJsx(hast as Root, { components: options.components });
})();

cache.set(cacheKey, promise);
if (!options.components) {
cache.set(cacheKey, promise);
}
return promise;
}

Expand Down
Loading