feat(studio): Implement designs for intake trace and span views#460
feat(studio): Implement designs for intake trace and span views#460rrhyne wants to merge 7 commits into
Conversation
7302f47 to
2b444ad
Compare
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds intake UI primitives, span template infrastructure, span and trace detail views, route wiring, and a deterministic showcase seeding script. ChangesStudio intake detail rebuild
Intake showcase seed script
Sequence Diagram(s)Trace detail flow sequenceDiagram
participant IntakeTraceDetailView
participant TraceSpanAccordions
participant TraceSpanTreeView
participant TraceSpanListView
participant TraceSpanAccordionContent
IntakeTraceDetailView->>TraceSpanAccordions: trace and workspace
TraceSpanAccordions->>TraceSpanTreeView: tree mode state
TraceSpanAccordions->>TraceSpanListView: list mode state
TraceSpanTreeView->>TraceSpanAccordionContent: selected span details
TraceSpanListView->>TraceSpanAccordionContent: open span details
Showcase seed flow sequenceDiagram
participant main
participant DeterministicIdGenerator
participant Seeder
participant OTLPHTTPExporter
participant IntakeRESTAPI
participant _verify
main->>DeterministicIdGenerator: workspace seed
main->>Seeder: emit scenarios
main->>OTLPHTTPExporter: export spans
main->>IntakeRESTAPI: POST evaluator-results and annotations
main->>_verify: verify expected sessions
Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (3)
web/packages/studio/src/util/intakeTelemetry.ts (1)
162-184: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated span-partitioning logic.
Lines 163-184 replicate the
spansById/childrenByParent/roots/orphansbuild and sort frombuildSpanHierarchyRows(102-123) verbatim. Extract a shared helper so the two views can't diverge.♻️ Extract partition helper
interface SpanPartition { childrenByParent: Map<string, Span[]>; roots: Span[]; orphans: Span[]; } const partitionSpans = (spans: Span[]): SpanPartition => { const spansById = new Map(spans.map((span) => [span.span_id, span])); const childrenByParent = new Map<string, Span[]>(); const roots: Span[] = []; const orphans: Span[] = []; for (const span of spans) { if (span.parent_span_id && spansById.has(span.parent_span_id)) { const children = childrenByParent.get(span.parent_span_id) ?? []; children.push(span); childrenByParent.set(span.parent_span_id, children); } else if (span.parent_span_id) { orphans.push(span); } else { roots.push(span); } } for (const children of childrenByParent.values()) children.sort(compareSpansByStartedAt); roots.sort(compareSpansByStartedAt); orphans.sort(compareSpansByStartedAt); return { childrenByParent, roots, orphans }; };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/packages/studio/src/util/intakeTelemetry.ts` around lines 162 - 184, The span partitioning logic in buildSpanTree is duplicated from buildSpanHierarchyRows, so extract the shared span-partition helper and have both callers use it. Create a reusable helper near these functions that returns childrenByParent, roots, and orphans, with the same sorting behavior, then update buildSpanTree and buildSpanHierarchyRows to consume that helper instead of rebuilding the maps inline. Use the existing symbols buildSpanTree, buildSpanHierarchyRows, and compareSpansByStartedAt to keep the implementation aligned.web/packages/studio/src/components/IntakeDetail/TraceDetailSummaryHeader.tsx (1)
96-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse a density token instead of raw
gap-4.Rest of this file uses
gap="density-*"/gap-density-*;gap-4breaks token consistency.Proposed tweak
- <div className="ml-auto flex max-w-full flex-nowrap items-start gap-4 overflow-x-auto"> + <div className="ml-auto flex max-w-full flex-nowrap items-start gap-density-xl overflow-x-auto">As per coding guidelines: "Follow NVIDIA Foundations React's design tokens and theming system for consistent visual design".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/packages/studio/src/components/IntakeDetail/TraceDetailSummaryHeader.tsx` at line 96, The flex container in TraceDetailSummaryHeader is using a raw gap-4 value instead of the established density token pattern used elsewhere in the file. Update that class on the main wrapper div to use the matching density-based gap token so it stays consistent with the surrounding layout and NVIDIA Foundations React design tokens.Source: Coding guidelines
web/packages/studio/src/components/SpanKindBadge/index.tsx (1)
4-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse a type-only import for
SpanKind.
SpanKindis only referenced inSpanKindBadgeProps, so this should beimport typeto match the repo rule and avoid a needless runtime import when type-preserving emit is enabled. As per coding guidelines, "web/**/*.{ts,tsx}: Useimport typefor type-only imports in TypeScript".Proposed fix
-import { SpanKind } from '`@nemo/sdk/generated/platform/schema`'; +import type { SpanKind } from '`@nemo/sdk/generated/platform/schema`';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/packages/studio/src/components/SpanKindBadge/index.tsx` at line 4, `SpanKind` is only used in the `SpanKindBadgeProps` type, so update the import in `SpanKindBadge` to a type-only import. Keep the existing usage in the props type, but change the `@nemo/sdk/generated/platform/schema` import to `import type` to satisfy the repo’s `web/**/*.{ts,tsx}` rule and avoid generating a runtime import.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/packages/common/src/components/IntakeAccordion/index.tsx`:
- Around line 79-80: The IntakeAccordion trigger in the `IntakeAccordion`
component is wrapping arbitrary `ReactNode` values from `item.slotLabel` and
`item.slotEnd` in inline `span` elements, which can create invalid DOM for block
children. Update the rendering in `IntakeAccordion` to use wrappers that safely
support both inline and block content, or tighten the `slotLabel`/`slotEnd` API
so callers can only pass inline phrasing content. Keep the fix localized to the
`IntakeAccordion` component where these slots are rendered.
In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/keyValueFormatting.ts`:
- Around line 8-19: The isMeaningfulValue type guard currently narrows to string
| number | boolean even though it returns true for non-empty arrays and objects,
which can mislead callers. Update the signature on isMeaningfulValue in
keyValueFormatting so it either returns plain boolean or widens the predicate to
include the object/array cases it accepts, while keeping the existing truthiness
checks unchanged.
In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/KeyValueGrid.tsx`:
- Around line 14-15: The presence check in isPresentValue still treats boolean
ReactNode values as present, which can produce empty-looking rows in
KeyValueGrid; update the isPresentValue helper to also reject true and false (or
normalize booleans before they reach this component) so only renderable values
are considered present.
In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/KeyValueRows.tsx`:
- Around line 15-23: The row renderer in KeyValueRows currently ignores
KeyValueEntry.wrapValue and always applies break-all to the value cell, which
makes it inconsistent with the shared KeyValueEntry contract and KeyValueGrid.
Update the value rendering inside the entries.map block to respect
entry.wrapValue, using the wrapped styling only when that flag is set and
preserving the non-wrapping/default behavior otherwise.
In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/RawJsonDebug.tsx`:
- Around line 21-22: `RawJsonDebug` currently serializes `value` directly in the
`useMemo` callback, which can throw for circular references or `BigInt` and
break the detail view. Update the `json` computation in `RawJsonDebug.tsx` to
wrap `JSON.stringify(value, null, 2)` in a `try/catch`, and return a safe
fallback like `[unserializable value]` when serialization fails so the component
still renders.
In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanFeedbackControls.tsx`:
- Line 37: The header feedback action in SpanFeedbackControls is swallowing
failures because useSpanAnnotationActions is destructured without the exposed
error state. Update the SpanFeedbackControls component to also read error from
useSpanAnnotationActions and surface it through the existing UI pattern used in
this area, such as a toast or tooltip, so a failed submitFeedback click is
visible instead of silently ignored.
In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.tsx`:
- Around line 17-22: The SpanPayloadBlock rendering logic is altering the
payload by calling trim() before passing it to CodeSnippet, which changes the
displayed request/response body. Update the value handling in SpanPayloadBlock
so the original value is rendered unchanged, and use trimming only to determine
whether the payload is empty (keep the existing content check but pass the
unmodified value through).
In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/useSpanAnnotationActions.ts`:
- Around line 56-77: The submitFeedback callback in useSpanAnnotationActions
currently only creates a new feedback annotation, so repeated submissions can
duplicate rows and counts. Update this flow to replace any existing feedback for
the same span before calling createAnnotation.mutateAsync, or switch to an
explicit upsert/replace API path keyed by span_id and feedback kind. Keep the
change localized to submitFeedback and any related annotation mutation helpers
used there.
In
`@web/packages/studio/src/components/IntakeDetail/SpanTemplates/DefaultSpanTemplate.ts`:
- Around line 12-15: The fallback span template is not matching the shared
SpanTemplate contract because defaultSpanTemplate includes both Content and the
'kind' section even though the generic fallback is documented to omit them.
Update DefaultSpanTemplate so the fallback layout aligns with types.ts by
removing the extra Content and 'kind' entry, and keep the template shape
consistent with the intended fallback behavior.
In
`@web/packages/studio/src/components/IntakeDetail/SpanTemplates/ToolSpanContent.tsx`:
- Around line 22-28: The Tool span template is rendering duration twice because
TemplateKeyValues already adds the shared timing fields. Update
ToolSpanContent’s fields array to remove the explicit Duration entry and keep
only the tool-specific values (e.g. Tool and Description), so the rendered
output does not duplicate duration.
---
Nitpick comments:
In
`@web/packages/studio/src/components/IntakeDetail/TraceDetailSummaryHeader.tsx`:
- Line 96: The flex container in TraceDetailSummaryHeader is using a raw gap-4
value instead of the established density token pattern used elsewhere in the
file. Update that class on the main wrapper div to use the matching
density-based gap token so it stays consistent with the surrounding layout and
NVIDIA Foundations React design tokens.
In `@web/packages/studio/src/components/SpanKindBadge/index.tsx`:
- Line 4: `SpanKind` is only used in the `SpanKindBadgeProps` type, so update
the import in `SpanKindBadge` to a type-only import. Keep the existing usage in
the props type, but change the `@nemo/sdk/generated/platform/schema` import to
`import type` to satisfy the repo’s `web/**/*.{ts,tsx}` rule and avoid
generating a runtime import.
In `@web/packages/studio/src/util/intakeTelemetry.ts`:
- Around line 162-184: The span partitioning logic in buildSpanTree is
duplicated from buildSpanHierarchyRows, so extract the shared span-partition
helper and have both callers use it. Create a reusable helper near these
functions that returns childrenByParent, roots, and orphans, with the same
sorting behavior, then update buildSpanTree and buildSpanHierarchyRows to
consume that helper instead of rebuilding the maps inline. Use the existing
symbols buildSpanTree, buildSpanHierarchyRows, and compareSpansByStartedAt to
keep the implementation aligned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 3de569f7-e4f6-4ee9-9ee6-7d92ba82f920
📒 Files selected for processing (68)
web/packages/common/src/components/IntakeAccordion/IntakeAccordion.cssweb/packages/common/src/components/IntakeAccordion/index.test.tsxweb/packages/common/src/components/IntakeAccordion/index.tsxweb/packages/studio/src/components/IntakeAnnotationsPanel/index.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/AnnotationsPanel.test.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/AnnotationsPanel.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/IntakeErrorBanner.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/IntakeTelemetryStatusBadge.test.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/IntakeTelemetryStatusBadge.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/KeyValueGrid.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/KeyValueRows.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/RawJsonDebug.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanFeedbackControls.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/keyValueFormatting.tsweb/packages/studio/src/components/IntakeDetail/IntakeComponents/keyValueTypes.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.test.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/traceKeyValues.test.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/traceKeyValues.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/useSpanAnnotationActions.tsweb/packages/studio/src/components/IntakeDetail/SpanDetailView.tsxweb/packages/studio/src/components/IntakeDetail/SpanMetadataAccordions.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/AgentSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/AgentSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/ChainSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/ChainSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/DefaultSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/DefaultSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/EmbeddingSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/EmbeddingSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/EvaluatorSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/EvaluatorSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/GuardrailSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/GuardrailSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/LlmSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/LlmSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/RerankerSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/RerankerSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/RetrieverSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/RetrieverSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/ToolSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/ToolSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/rawAttributes.test.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/rawAttributes.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/registry.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/templateFields.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/types.tsweb/packages/studio/src/components/IntakeDetail/TraceDetailSpanTree.cssweb/packages/studio/src/components/IntakeDetail/TraceDetailSpanTree.tsxweb/packages/studio/src/components/IntakeDetail/TraceDetailSummaryHeader.tsxweb/packages/studio/src/components/IntakeDetail/TraceDetailView.tsxweb/packages/studio/src/components/IntakeDetail/TraceSpanAccordionContent.tsxweb/packages/studio/src/components/IntakeDetail/TraceSpanAccordions.tsxweb/packages/studio/src/components/IntakeDetail/intakeDetail-readme.mdweb/packages/studio/src/components/IntakeLists/IntakeSpansTable.test.tsxweb/packages/studio/src/components/IntakeLists/IntakeSpansTable.tsxweb/packages/studio/src/components/IntakeLists/IntakeTelemetryDataView.tsxweb/packages/studio/src/components/IntakeLists/IntakeTracesTable.test.tsxweb/packages/studio/src/components/IntakeLists/IntakeTracesTable.tsxweb/packages/studio/src/components/SpanKindBadge/index.test.tsxweb/packages/studio/src/components/SpanKindBadge/index.tsxweb/packages/studio/src/components/SpanKindBadge/spanKindConfig.tsweb/packages/studio/src/routes/IntakeSpanDetailRoute/index.tsxweb/packages/studio/src/routes/IntakeTraceDetailRoute/index.tsxweb/packages/studio/src/routes/groups/intakeRoutes.tsxweb/packages/studio/src/util/intakeTelemetry.test.tsweb/packages/studio/src/util/intakeTelemetry.ts
💤 Files with no reviewable changes (1)
- web/packages/studio/src/components/IntakeAnnotationsPanel/index.tsx
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
services/intake/scripts/spans/seed_span_type_showcase.py (1)
48-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse concrete annotations here.
from __future__ import annotationsstringifies all annotations; this file has no forward refs requiring it. Remove it. As per coding guidelines,**/*.py: "Always prefer concrete type hints over string-based ones in Python code; do not import types under TYPE_CHECKING, instead import types as regular imports when possible."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@services/intake/scripts/spans/seed_span_type_showcase.py` at line 48, Remove the unnecessary from __future__ import annotations from seed_span_type_showcase.py and keep the file using concrete type hints directly, since there are no forward references. Review the annotations in the module-level code and any functions/classes there to ensure they remain valid without stringification, and leave regular imports in place rather than relying on postponed evaluation.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@services/intake/scripts/spans/seed_span_type_showcase.py`:
- Around line 765-772: The _post_annotations helper currently POSTs every
showcase annotation on each run, which creates duplicate ann-{uuid} records.
Update _post_annotations in seed_span_type_showcase.py to make writes idempotent
by checking for existing showcase annotations before posting, or by
deleting/cleaning existing ones first; use the existing client, base_url,
workspace, and annotations flow to locate the logic and ensure reruns do not
create duplicate feedback, labels, or notes.
- Around line 796-805: The _verify helper currently only prints the visible
showcase sessions, so it can report success even when no seeded traces were
ingested. Update _verify in seed_span_type_showcase.py to validate the expected
showcase- session IDs after the httpx.get call, and raise an error if the
filtered showcase list is empty or otherwise missing required sessions. Keep the
existing response.raise_for_status and session collection logic, but make the
verification fail fast instead of printing a success message when ingestion did
not produce the expected traces.
---
Nitpick comments:
In `@services/intake/scripts/spans/seed_span_type_showcase.py`:
- Line 48: Remove the unnecessary from __future__ import annotations from
seed_span_type_showcase.py and keep the file using concrete type hints directly,
since there are no forward references. Review the annotations in the
module-level code and any functions/classes there to ensure they remain valid
without stringification, and leave regular imports in place rather than relying
on postponed evaluation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 6050bbfd-75e6-475e-9e91-ee789ff547e6
📒 Files selected for processing (1)
services/intake/scripts/spans/seed_span_type_showcase.py
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
web/packages/studio/src/components/IntakeDetail/IntakeComponents/useSpanAnnotationActions.ts (1)
58-77: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftFeedback replacement is still race-prone.
This is still
list -> delete -> createacross separate requests, andisMutatingstaysfalseduring the initiallistAnnotationscall. Two rapid clicks can start overlapping runs before the buttons disable, and concurrent clients can still leave duplicatefeedbackrows. Use a single replace/upsert contract server-side, or at minimum track a local pending state for the whole callback.Also applies to: 139-141
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/packages/studio/src/components/IntakeDetail/IntakeComponents/useSpanAnnotationActions.ts` around lines 58 - 77, The feedback replace flow in useSpanAnnotationActions.submitFeedback is still race-prone because it does listAnnotations, deleteMutation.mutateAsync, then create in separate requests while isMutating is false during the initial fetch. Update the feedback path to use a single server-side replace/upsert contract if available, or add a local pending state around the entire submitFeedback callback so the UI blocks re-entry until the full operation completes. Also make the same fix for the other feedback submission path referenced in the component so duplicate feedback rows cannot be created by rapid clicks or concurrent clients.web/packages/studio/src/components/IntakeDetail/SpanTemplates/templateFields.tsx (1)
75-86: 🎯 Functional Correctness | 🟡 MinorUse a stable key instead of
field.label.TemplateKeyValuespasses display labels through as React keys, so any repeated label or param-label collision will trigger duplicate keys and can drop rows. Add a separate field id and use that here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/packages/studio/src/components/IntakeDetail/SpanTemplates/templateFields.tsx` around lines 75 - 86, TemplateKeyValues is using field.label as the React key in KeyValueGrid, which can collide when labels repeat or when param labels match. Update the TemplateKeyValues mapping to carry a stable unique identifier on each item, and use that identifier for key instead of the display label. Adjust the related field construction in statusField, timingFields, and the TemplateField shape as needed so each rendered row has a unique id while keeping label and value unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/useSpanAnnotationActions.ts`:
- Around line 58-77: The feedback replace flow in
useSpanAnnotationActions.submitFeedback is still race-prone because it does
listAnnotations, deleteMutation.mutateAsync, then create in separate requests
while isMutating is false during the initial fetch. Update the feedback path to
use a single server-side replace/upsert contract if available, or add a local
pending state around the entire submitFeedback callback so the UI blocks
re-entry until the full operation completes. Also make the same fix for the
other feedback submission path referenced in the component so duplicate feedback
rows cannot be created by rapid clicks or concurrent clients.
In
`@web/packages/studio/src/components/IntakeDetail/SpanTemplates/templateFields.tsx`:
- Around line 75-86: TemplateKeyValues is using field.label as the React key in
KeyValueGrid, which can collide when labels repeat or when param labels match.
Update the TemplateKeyValues mapping to carry a stable unique identifier on each
item, and use that identifier for key instead of the display label. Adjust the
related field construction in statusField, timingFields, and the TemplateField
shape as needed so each rendered row has a unique id while keeping label and
value unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 956514fc-2cc7-47c2-9c57-47e62c710f6a
📒 Files selected for processing (32)
services/intake/scripts/spans/seed_span_type_showcase.pyweb/packages/common/src/components/IntakeAccordion/index.tsxweb/packages/common/src/components/KeyValueGrid/index.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/AnnotationsPanel.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/KeyValueRows.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/RawJsonDebug.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanFeedbackControls.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanTriggerLabel.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanTriggerMeta.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/keyValueFormatting.tsweb/packages/studio/src/components/IntakeDetail/IntakeComponents/keyValueTypes.tsweb/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.test.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/traceKeyValues.tsxweb/packages/studio/src/components/IntakeDetail/IntakeComponents/useSpanAnnotationActions.tsweb/packages/studio/src/components/IntakeDetail/SpanMetadataAccordions.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/EvaluatorSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/GuardrailSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/LlmSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/RerankerSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/RerankerSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/RetrieverSpanContent.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/RetrieverSpanTemplate.tsweb/packages/studio/src/components/IntakeDetail/SpanTemplates/templateFields.tsxweb/packages/studio/src/components/IntakeDetail/SpanTemplates/types.tsweb/packages/studio/src/components/IntakeDetail/TraceSpanAccordions.tsxweb/packages/studio/src/components/IntakeDetail/TraceSpanListView.tsxweb/packages/studio/src/components/IntakeDetail/TraceSpanTreeView.tsxweb/packages/studio/src/components/IntakeDetail/traceSpanShared.tsweb/packages/studio/src/components/dataViews/ExperimentGroupDataView/useExperimentGroupExperiments.tsweb/packages/studio/src/routes/groups/experimentRoutes.tsx
💤 Files with no reviewable changes (1)
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/keyValueTypes.ts
✅ Files skipped from review due to trivial changes (1)
- web/packages/studio/src/components/IntakeDetail/SpanTemplates/types.ts
🚧 Files skipped from review as they are similar to previous changes (16)
- web/packages/studio/src/components/IntakeDetail/SpanTemplates/RerankerSpanTemplate.ts
- web/packages/studio/src/components/IntakeDetail/SpanTemplates/GuardrailSpanContent.tsx
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/KeyValueRows.tsx
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/RawJsonDebug.tsx
- web/packages/studio/src/components/IntakeDetail/SpanTemplates/RetrieverSpanTemplate.ts
- web/packages/studio/src/components/IntakeDetail/SpanTemplates/LlmSpanContent.tsx
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.test.tsx
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.tsx
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanFeedbackControls.tsx
- web/packages/common/src/components/IntakeAccordion/index.tsx
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.tsx
- web/packages/studio/src/components/IntakeDetail/SpanTemplates/EvaluatorSpanContent.tsx
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/AnnotationsPanel.tsx
- web/packages/studio/src/components/IntakeDetail/SpanMetadataAccordions.tsx
- web/packages/studio/src/components/IntakeDetail/IntakeComponents/traceKeyValues.tsx
- services/intake/scripts/spans/seed_span_type_showcase.py
a273b0d to
18304ec
Compare
Accordion + trajectory-tree trace/span detail views with self-describing per-kind templates. - Trace view: a hierarchical trajectory tree beside collapsible span accordions; a summary header (status + start/end timing on the left; Total Tokens and Total Cost KPIs with hover popovers for the per-direction breakdown); a trace error banner beside the tree when the trace failed; and trace metadata + raw-JSON debug below. - Per-kind span templates (LLM, Tool, Retriever, Embedding, Agent, Reranker, Evaluator, Guardrail, Chain): each is a self-describing descriptor (`*SpanTemplate.ts`) + body (`*SpanContent.tsx`) that owns its elevated fields, section selection, and row-header title/badge. The registry is pure wiring with a generic default template for UNKNOWN, so it is total. - Span body: error banner, kind body, a shared section catalog (Usage / Input / Output / Metadata / Annotations), and a raw-JSON debug toggle. Metadata drops fields already surfaced elsewhere (status/error, template-claimed attributes). - Row headers: kind badge with accent-tinted icon, kind-elevated title (e.g. evaluator name), and compact tooltip-labeled metrics (e.g. "9tk", "3.50s"). - Reusable atoms under IntakeComponents (key/value grid + rows, payload block, error banner, raw-JSON debug, status badge); lists under IntakeLists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
Move the trace-tree and IntakeAccordion styling off `.css` files and onto the components. KUI's styles are variable-driven and live in Tailwind's `base` layer, so component-level Tailwind utilities (and `--nv-*` variable overrides) win the cascade without `\!important`. - Delete TraceDetailSpanTree.css: row width/rounding/padding, label layout, and kind/error icon colors are now Tailwind utilities on the rendered elements. - IntakeAccordion: set surface, trigger/content padding, and the last-row border via KUI's `--nv-accordion-*` variables on the component; lay out the label/end groups with Tailwind. IntakeAccordion.css is reduced to the single `.nv-accordion-label-text` flex rule — KUI's internal trigger-children wrapper, which exposes neither a className nor a variable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
18304ec to
46629d6
Compare
Apply prettier formatting (studio), fix ruff check/format in the intake span showcase seed script, and rename intakeDetail-readme.md -> README.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
40cd1c4 to
3d64ffa
Compare
Summary
Adds accordion + trajectory-tree trace/span detail views to Studio, with self-describing per-kind span templates.
*SpanTemplate.ts) + body (*SpanContent.tsx) owning its elevated fields, section selection, and row-header title/badge. Registry is pure wiring with a generic default for UNKNOWN, so it is total.IntakeComponents; lists underIntakeLists.Annotations form (Figma alignment)
AnnotationsPanel: "Note" → "Notes" label; feedback column given a fixed width (wasw-fit, which collapsed underFormField's intrinsicwidth:100%and wrapped/clipped the thumb buttons); row now wraps gracefully on narrow containers.Testing
pnpm --filter nemo-studio-ui test— AnnotationsPanel suite passes.🤖 Generated with Claude Code
Summary by CodeRabbit