Compare commits

..

9 Commits

Author SHA1 Message Date
Gaurav Tewari
f3040c2a70 feat(llm-observability): open traces on the thread tab 2026-10-21 22:25:15 +05:30
Gaurav Tewari
88539ba67f feat(trace-details): thread tab view 2026-10-21 22:25:15 +05:30
Gaurav Tewari
2f3da65219 feat(trace-details): show AI messages in span details 2026-10-21 22:25:15 +05:30
Gaurav Tewari
6041a00e68 feat(trace-details): add AI message model and renderer 2026-10-21 22:25:15 +05:30
Gaurav Tewari
6e2bd63db9 fix(pretty-view): skip the actions menu when it has no items 2026-10-21 21:00:11 +05:30
Gaurav Tewari
28d68c28bc refactor: review changes 2026-10-21 17:07:54 +05:30
Gaurav Tewari
09b8d764c0 feat(trace-details): overview and thread tabs 2026-10-21 16:30:28 +05:30
Gaurav Tewari
3ae12a4eaf refactor(trace-details): lift header and store sync into page shell 2026-10-21 16:29:36 +05:30
Gaurav Tewari
077ce9529d refactor(trace-details): read search params at call time
The router's search goes stale once nuqs writes to the URL,
so span selection and links read the live URL instead.
2026-10-21 16:28:40 +05:30
7 changed files with 12 additions and 14 deletions

View File

@@ -22,7 +22,7 @@ function CollapsibleBlock({
children,
}: CollapsibleBlockProps): JSX.Element {
// Toggling must not count as a click on the message card; the body still does.
const stopHeaderClick = (event: MouseEvent): void => {
const stopToggleFromSelectingCard = (event: MouseEvent): void => {
if ((event.target as HTMLElement).closest('.ant-collapse-header')) {
event.stopPropagation();
}
@@ -30,7 +30,7 @@ function CollapsibleBlock({
return (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<div onClick={stopHeaderClick}>
<div onClick={stopToggleFromSelectingCard}>
<Collapse
ghost
className={cx(styles.collapsible, isBoxed && styles.boxed)}

View File

@@ -25,7 +25,7 @@ function JsonBlock({ data }: JsonBlockProps): JSX.Element {
const isLong = treeHeight > COLLAPSED_MAX_HEIGHT;
const isClamped = isLong && !isExpanded;
const stopToggleClick = (event: MouseEvent): void => {
const stopTreeToggleFromSelectingCard = (event: MouseEvent): void => {
if ((event.target as HTMLElement).closest(TREE_TOGGLES)) {
event.stopPropagation();
}
@@ -42,7 +42,7 @@ function JsonBlock({ data }: JsonBlockProps): JSX.Element {
<div
className={cx(styles.json, isClamped && styles.jsonCollapsed)}
style={isClamped ? { maxHeight: COLLAPSED_MAX_HEIGHT } : undefined}
onClick={stopToggleClick}
onClick={stopTreeToggleFromSelectingCard}
data-testid="ai-json-block"
>
<span className={styles.jsonCopy}>

View File

@@ -6,7 +6,6 @@ interface RoleLabelProps {
label: string;
}
/** Message role in the design's Paragraph/Base/400 style. */
function RoleLabel({ label }: RoleLabelProps): JSX.Element {
return (
<Typography.Text size="base" weight="normal" className={styles.roleLabel}>

View File

@@ -34,6 +34,7 @@ export type MessagePart =
| LoosePart<AiobservabilitytypesBlobPartDTO>
| LoosePart<AiobservabilitytypesFilePartDTO>
| LoosePart<AiobservabilitytypesUriPartDTO>
// The API's generic part is an untyped index signature, which defeats narrowing on `type`.
| { type: 'generic'; content?: unknown };
export type MessagePartType = MessagePart['type'];

View File

@@ -19,7 +19,7 @@ function SpanAIMessages({ span }: SpanAIMessagesProps): JSX.Element | null {
const data = useMemo(() => getSpanMessages(span), [span]);
const rootRef = useRef<HTMLDivElement>(null);
const toolCallKeys = useMemo(() => buildToolCallIndex([span]), [span]);
const toolCallKeys = useMemo(() => buildToolCallIndex(span), [span]);
const { canLinkToToolCall, onToolLinkClick } = useToolCallLinks(
rootRef,
toolCallKeys,

View File

@@ -23,7 +23,7 @@ function ThreadSpanCard({
}: ThreadSpanCardProps): JSX.Element {
const cardRef = useRef<HTMLDivElement>(null);
// A result links only to a call in its own span.
const toolCallKeys = useMemo(() => buildToolCallIndex([span]), [span]);
const toolCallKeys = useMemo(() => buildToolCallIndex(span), [span]);
const { canLinkToToolCall, onToolLinkClick } = useToolCallLinks(
cardRef,
toolCallKeys,

View File

@@ -17,13 +17,11 @@ export function isNotFoundError(error: unknown): boolean {
return isAxiosError(error) && error.response?.status === 404;
}
export function buildToolCallIndex(spans: ThreadSpan[]): Set<string> {
return new Set(
spans.flatMap((span) => [
...collectToolCallKeys(span.formattedInput ?? []),
...collectToolCallKeys(span.formattedOutput ?? []),
]),
);
export function buildToolCallIndex(span: ThreadSpan): Set<string> {
return new Set([
...collectToolCallKeys(span.formattedInput ?? []),
...collectToolCallKeys(span.formattedOutput ?? []),
]);
}
export function getInterestedSpanStatus(