Skip to content

feat(intake): reduce data loaded for nemo studio trace views#558

Merged
BrianNewsom merged 4 commits into
mainfrom
brnewsom/ase-447-client-performance-issues-for-large-traces
Jul 2, 2026
Merged

feat(intake): reduce data loaded for nemo studio trace views#558
BrianNewsom merged 4 commits into
mainfrom
brnewsom/ase-447-client-performance-issues-for-large-traces

Conversation

@BrianNewsom

@BrianNewsom BrianNewsom commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added a mode option for experiment session listings (summary vs detailed), with summary truncating root-span input and span error messages.
    • Enhanced Studio deep-linking to open a specific span within a trace using a URL query parameter.
  • Bug Fixes
    • Added automatic fallback to the default response mode when summary isn’t supported by the backend.
    • Refined intake trace/span navigation and URL synchronization, including corrected link destinations.
  • Performance / UX
    • Improved large span payload rendering to avoid UI blocking and improved loading/empty states.

@BrianNewsom
BrianNewsom requested review from a team as code owners July 2, 2026 21:11
@github-actions github-actions Bot added the feat label Jul 2, 2026
Comment thread web/packages/sdk/generated/agents/schema/DeploymentLogsResponse.ts Outdated
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: acf8d021-5388-4ad1-8e79-336a98dd24dc

📥 Commits

Reviewing files that changed from the base of the PR and between 8a67c91 and 324a06d.

📒 Files selected for processing (2)
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.test.tsx
  • web/packages/studio/src/components/IntakeDetail/README.md
✅ Files skipped from review due to trivial changes (2)
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.test.tsx
  • web/packages/studio/src/components/IntakeDetail/README.md

📝 Walkthrough

Walkthrough

Adds mode=summary|detailed support for experiment sessions, truncating summary payload fields and updating tests/docs. Replaces standalone intake span routing with trace-based spanId deep links across Studio, including route helpers, navigation, trace-detail selection, and related tests.

Changes

Backend session/span mode and truncation

Layer / File(s) Summary
OpenAPI docs for mode and truncation
openapi/ga/individual/platform.openapi.yaml, openapi/ga/openapi.yaml, openapi/openapi.yaml
Adds the mode query parameter and updates input/error_message descriptions for summary-mode truncation.
Mode propagation and truncation logic
services/intake/src/nmp/intake/api/v2/experiments/schemas.py, services/intake/src/nmp/intake/spans/api/spans_schemas.py, services/intake/src/nmp/intake/api/v2/experiments/endpoints.py, services/intake/src/nmp/intake/spans/experiment_session_repository.py
Defines mode and truncation constants, wires mode through the endpoint, and truncates session inputs and span error messages in summary mode.
Backend tests for truncation behavior
services/intake/tests/test_experiment_session_schemas.py, services/intake/tests/test_spans_schemas.py
Adds coverage for session input preservation and summary-mode span error truncation/bulk-field omission.

Studio trace-linked span navigation

Layer / File(s) Summary
Studio link destinations and route helpers
services/studio/src/nmp/studio/studio_links.py, services/studio/tests/unit/test_coding_agents.py, web/packages/studio/src/routes/agents/ClaudeCodeChatRoute/artifacts.ts, web/packages/studio/src/routes/agents/ClaudeCodeChatRoute/artifacts.test.ts, web/packages/studio/src/constants/routes.ts, web/packages/studio/src/routes/constants.ts, web/packages/studio/src/routes/groups/intakeRoutes.tsx, web/packages/studio/src/routes/index.test.tsx, web/packages/studio/src/routes/utils.ts, web/packages/studio/src/routes/utils.test.ts, web/packages/studio/src/tests/title-change.test.tsx
Switches intake span links and route helpers to trace-based deep links and removes the standalone intake span route.
Trace and list navigation to span deep links
web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.tsx, web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.test.tsx, web/packages/studio/src/components/IntakeDetail/IntakeComponents/traceKeyValues.tsx, web/packages/studio/src/components/IntakeLists/IntakeSpansTable.tsx, web/packages/studio/src/components/IntakeLists/IntakeSpansTable.test.tsx, web/packages/studio/src/components/IntakeLists/IntakeTracesTable.test.tsx
Updates span and trace link rendering and intake list navigation to use trace+span routes, with request-mode coverage in tests.
Trace detail deep-link state
web/packages/studio/src/components/IntakeDetail/TraceSpanAccordions.tsx, web/packages/studio/src/components/IntakeDetail/TraceSpanTreeView.tsx, web/packages/studio/src/components/IntakeDetail/TraceSpanAccordionContent.tsx, web/packages/studio/src/components/IntakeDetail/AnnotationsPanel.test.tsx, web/packages/studio/src/components/IntakeDetail/README.md, web/packages/studio/src/routes/IntakeTraceDetailRoute/index.test.tsx
Reads and writes spanId in the URL, fetches deep-linked spans, passes empty-state content into the tree view, and updates trace-detail tests and docs.
Trace detail integration tests
web/packages/studio/src/routes/IntakeTraceDetailRoute/index.test.tsx
Covers summary-first loading, spanId restore, and deep-linked spans outside the initially loaded page.
Payload rendering and session list fallback
web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.tsx, web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.test.tsx, web/packages/studio/src/components/IntakeDetail/SpanTemplates/EvaluatorSpanTemplate.ts, web/packages/studio/src/components/IntakeDetail/SpanTemplates/GuardrailSpanTemplate.ts, web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.tsx, web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.test.tsx
Defers large payload rendering, removes span-template header badges, and retries session list requests without mode when unsupported.

Possibly related PRs

Suggested reviewers: nakolean, shanaiabuggy

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: lowering payload size for Nemo Studio trace views.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch brnewsom/ase-447-client-performance-issues-for-large-traces

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.test.tsx (1)

132-145: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing coverage for the actual parent_span_id change.

This new test asserts on trace_id, but the segment that changed in this cohort is parent_span_id's resolve logic (spanKeyValues.tsx Lines 200-209), including the new raw-text fallback when trace_id is absent. No test here exercises that branch.

🤖 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/spanKeyValues.test.tsx`
around lines 132 - 145, The new test is covering the wrong field: it checks
trace_id instead of the updated parent_span_id resolution in spanKeyValues.tsx.
Add or बदल the test in spanKeyValues.test.tsx to exercise the parent_span_id
branch in buildSpanSummaryEntries, including the new raw-text fallback when
trace_id is missing, and assert the rendered value/route for that specific
behavior.
web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.tsx (1)

200-209: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant !parent_span_id guard.

include: (span) => isMeaningfulValue(span.parent_span_id) (Line 210) already filters out entries where parent_span_id is falsy, so the if (!span.parent_span_id) return EMPTY_VALUE; branch in resolve (Line 201) is effectively unreachable. Harmless, but dead code.

🤖 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/spanKeyValues.tsx`
around lines 200 - 209, The resolve logic in spanKeyValues has a redundant
parent_span_id null check because include already filters those entries via
isMeaningfulValue(span.parent_span_id). Remove the dead if
(!span.parent_span_id) return EMPTY_VALUE; branch from the resolve callback and
keep the existing Link/span.parent_span_id rendering behavior unchanged.
services/intake/src/nmp/intake/api/v2/experiments/endpoints.py (1)

659-665: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded "1000" in query description will drift from the constant.

EXPERIMENT_SESSION_SUMMARY_INPUT_CHAR_LIMIT is imported here but the description text hardcodes the value instead of interpolating it, unlike schemas.py's input field description which uses an f-string.

♻️ Proposed fix
     mode: ExperimentSessionMode = Query(
         default="detailed",
         description=(
-            "Response payload mode. summary keeps the same session row fields but truncates root-span input "
-            "to 1000 characters; detailed returns the full root-span input."
+            "Response payload mode. summary keeps the same session row fields but truncates root-span input "
+            f"to {EXPERIMENT_SESSION_SUMMARY_INPUT_CHAR_LIMIT} characters; detailed returns the full root-span input."
         ),
     ),
🤖 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/src/nmp/intake/api/v2/experiments/endpoints.py` around lines
659 - 665, The Query description for the experiment session mode hardcodes the
summary input truncation length, which can drift from the imported constant.
Update the description in the endpoint definition that uses Query for mode to
interpolate EXPERIMENT_SESSION_SUMMARY_INPUT_CHAR_LIMIT instead of embedding a
literal, matching the f-string approach used in schemas.py for the input field
description. Keep the wording the same otherwise and ensure the constant remains
the single source of truth.
web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.tsx (1)

48-53: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Brittle exact-string match for backend error detection.

Fallback only triggers on an exact match of 'Unsupported query parameter(s): mode'. Any backend wording/formatting change (different layer in this PR stack) silently breaks the fallback, turning a graceful degradation into a hard failure during rollout skew.

♻️ Loosen the match
-  const detail = (error.response.data as { detail?: unknown } | undefined)?.detail;
-  return typeof detail === 'string' && detail === 'Unsupported query parameter(s): mode';
+  const detail = (error.response.data as { detail?: unknown } | undefined)?.detail;
+  return typeof detail === 'string' && detail.includes('mode');
🤖 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/dataViews/ExperimentSessionsDataView/index.tsx`
around lines 48 - 53, The unsupported-mode detection in isUnsupportedModeError
is too brittle because it depends on an exact backend error string. Loosen the
check so it still recognizes the same fallback case when the message wording
varies slightly, while keeping the axios status and detail-based guard in place;
update the matching logic inside isUnsupportedModeError in
ExperimentSessionsDataView accordingly.
🤖 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/studio/src/components/IntakeDetail/TraceSpanAccordions.tsx`:
- Around line 264-277: The deep-link fallback state in linkedSpanEmptyContent is
only shown by SpanTreeView, so SpanListView still hides loading/error/mismatch
feedback for linked spans outside the loaded page. Update the list-view path in
TraceSpanAccordions to render the same linked-span status UI (spinner,
ErrorMessage, or mismatch notice) in whatever top-of-list/banner slot
SpanListView supports, using linkedSpanEmptyContent and the existing linked span
state variables so deep links remain visible in both view modes.

In `@web/packages/studio/src/components/IntakeLists/IntakeSpansTable.tsx`:
- Around line 140-144: The row click logic in IntakeSpansTable is now a silent
no-op when span.trace_id is missing, while the row still appears clickable.
Update the table row behavior in IntakeSpansTable so rows without trace_id are
either not registered with an onRowClick handler (or otherwise marked
non-clickable) or fall back to getIntakeSpanRoute instead of doing nothing. Use
the existing navigate and getIntakeTraceSpanRoute path for trace-backed rows,
and ensure the clickable affordance matches the actual behavior for each
SpanTableRow.

---

Nitpick comments:
In `@services/intake/src/nmp/intake/api/v2/experiments/endpoints.py`:
- Around line 659-665: The Query description for the experiment session mode
hardcodes the summary input truncation length, which can drift from the imported
constant. Update the description in the endpoint definition that uses Query for
mode to interpolate EXPERIMENT_SESSION_SUMMARY_INPUT_CHAR_LIMIT instead of
embedding a literal, matching the f-string approach used in schemas.py for the
input field description. Keep the wording the same otherwise and ensure the
constant remains the single source of truth.

In
`@web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.tsx`:
- Around line 48-53: The unsupported-mode detection in isUnsupportedModeError is
too brittle because it depends on an exact backend error string. Loosen the
check so it still recognizes the same fallback case when the message wording
varies slightly, while keeping the axios status and detail-based guard in place;
update the matching logic inside isUnsupportedModeError in
ExperimentSessionsDataView accordingly.

In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.test.tsx`:
- Around line 132-145: The new test is covering the wrong field: it checks
trace_id instead of the updated parent_span_id resolution in spanKeyValues.tsx.
Add or बदल the test in spanKeyValues.test.tsx to exercise the parent_span_id
branch in buildSpanSummaryEntries, including the new raw-text fallback when
trace_id is missing, and assert the rendered value/route for that specific
behavior.

In
`@web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.tsx`:
- Around line 200-209: The resolve logic in spanKeyValues has a redundant
parent_span_id null check because include already filters those entries via
isMeaningfulValue(span.parent_span_id). Remove the dead if
(!span.parent_span_id) return EMPTY_VALUE; branch from the resolve callback and
keep the existing Link/span.parent_span_id rendering behavior unchanged.
🪄 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: 89dc0808-6e8e-4850-9e93-11ff67b9208f

📥 Commits

Reviewing files that changed from the base of the PR and between c0474e2 and ed794a5.

⛔ Files ignored due to path filters (7)
  • sdk/python/nemo-platform/.nmpcontext/openapi.yaml is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/resources/experiments/sessions.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/types/experiments/experiment_session_response.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/types/experiments/session_list_params.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/types/intake/span.py is excluded by !sdk/**
  • sdk/python/nemo-platform/tests/api_resources/experiments/test_sessions.py is excluded by !sdk/**
  • web/packages/sdk/generated/agents/schema/DeploymentLogsResponse.ts is excluded by !**/generated/**
📒 Files selected for processing (40)
  • openapi/ga/individual/platform.openapi.yaml
  • openapi/ga/openapi.yaml
  • openapi/openapi.yaml
  • services/intake/src/nmp/intake/api/v2/experiments/endpoints.py
  • services/intake/src/nmp/intake/api/v2/experiments/schemas.py
  • services/intake/src/nmp/intake/spans/api/spans_schemas.py
  • services/intake/src/nmp/intake/spans/experiment_session_repository.py
  • services/intake/tests/test_experiment_session_schemas.py
  • services/intake/tests/test_spans_schemas.py
  • services/studio/src/nmp/studio/studio_links.py
  • services/studio/tests/unit/test_coding_agents.py
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/AnnotationsPanel.test.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.test.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanPayloadBlock.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.test.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/spanKeyValues.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/traceKeyValues.tsx
  • web/packages/studio/src/components/IntakeDetail/README.md
  • web/packages/studio/src/components/IntakeDetail/SpanDetailView.tsx
  • web/packages/studio/src/components/IntakeDetail/SpanTemplates/EvaluatorSpanTemplate.ts
  • web/packages/studio/src/components/IntakeDetail/SpanTemplates/GuardrailSpanTemplate.ts
  • web/packages/studio/src/components/IntakeDetail/TraceSpanAccordionContent.tsx
  • web/packages/studio/src/components/IntakeDetail/TraceSpanAccordions.tsx
  • web/packages/studio/src/components/IntakeDetail/TraceSpanTreeView.tsx
  • web/packages/studio/src/components/IntakeLists/IntakeSpansTable.test.tsx
  • web/packages/studio/src/components/IntakeLists/IntakeSpansTable.tsx
  • web/packages/studio/src/components/IntakeLists/IntakeTracesTable.test.tsx
  • web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.test.tsx
  • web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.tsx
  • web/packages/studio/src/constants/routes.ts
  • web/packages/studio/src/routes/IntakeSpanDetailRoute/index.tsx
  • web/packages/studio/src/routes/IntakeTraceDetailRoute/index.test.tsx
  • web/packages/studio/src/routes/agents/ClaudeCodeChatRoute/artifacts.test.ts
  • web/packages/studio/src/routes/agents/ClaudeCodeChatRoute/artifacts.ts
  • web/packages/studio/src/routes/constants.ts
  • web/packages/studio/src/routes/groups/intakeRoutes.tsx
  • web/packages/studio/src/routes/index.test.tsx
  • web/packages/studio/src/routes/utils.test.ts
  • web/packages/studio/src/routes/utils.ts
  • web/packages/studio/src/tests/title-change.test.tsx
💤 Files with no reviewable changes (6)
  • web/packages/studio/src/routes/IntakeSpanDetailRoute/index.tsx
  • web/packages/studio/src/components/IntakeDetail/SpanDetailView.tsx
  • web/packages/studio/src/tests/title-change.test.tsx
  • web/packages/studio/src/constants/routes.ts
  • web/packages/studio/src/routes/groups/intakeRoutes.tsx
  • web/packages/studio/src/routes/index.test.tsx

Comment thread web/packages/studio/src/components/IntakeDetail/TraceSpanAccordions.tsx Outdated
Comment thread web/packages/studio/src/components/IntakeLists/IntakeSpansTable.tsx
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 22524/29649 76.0% 60.8%
Integration Tests 13010/28329 45.9% 19.4%

Signed-off-by: Brian Newsom <[email protected]>
Signed-off-by: Brian Newsom <[email protected]>
@BrianNewsom
BrianNewsom enabled auto-merge July 2, 2026 22:05
@BrianNewsom
BrianNewsom added this pull request to the merge queue Jul 2, 2026
Merged via the queue into main with commit e0e6920 Jul 2, 2026
53 checks passed
@BrianNewsom
BrianNewsom deleted the brnewsom/ase-447-client-performance-issues-for-large-traces branch July 2, 2026 22:19
arpitsardhana pushed a commit that referenced this pull request Jul 9, 2026
* feat(intake): reduce data loaded for nemo studio trace views

Signed-off-by: Brian Newsom <[email protected]>

* fix(intake): cleanup and coderabbit fixes

Signed-off-by: Brian Newsom <[email protected]>

* chore(intake): lint

Signed-off-by: Brian Newsom <[email protected]>

* chore(intake): lint

Signed-off-by: Brian Newsom <[email protected]>

---------

Signed-off-by: Brian Newsom <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants