Skip to content

feat(studio): Studio copilot reasoning trace - #1106

Merged
htolentino-nvidia merged 2 commits into
mainfrom
studio-copilot-reasoning-trace/htolentino
Aug 7, 2026
Merged

feat(studio): Studio copilot reasoning trace#1106
htolentino-nvidia merged 2 commits into
mainfrom
studio-copilot-reasoning-trace/htolentino

Conversation

@htolentino-nvidia

@htolentino-nvidia htolentino-nvidia commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
image

Nemotron and other vLLM/NIM-served models stream their chain of thought in a reasoning_content delta, but it never reached the UI. Each layer dropped it:

  • langchain-openai 1.4.x only understands OpenAI's o-series reasoning block, so it discards reasoning_content on both the streaming and the non-streaming path. _preserve_reasoning_content re-attaches it to the message.
  • NAT's ChatResponseChunk carries only content, so the trace rides the same intermediate_data: channel the tool-call trace already uses. It is published per LLM run rather than per token, since one step per token would be thousands of frames for a single answer. NAT's StepAdaptor forwards only LLM, TOOL and FUNCTION categories and drops an end step whose start carries no input, hence the paired LLM steps.
  • Studio relays it as a message part. It deliberately bypasses the tool dedup: the pair shares one id, so the start would claim it and the end -- which carries the trace -- would be dropped.
  • The UI renders it as ordinary assistant text, so it reads as narration between tool calls rather than hiding in a collapsed block.

Also fix tool-call ordering, which the same rendering path exposed: answering a blocking picker appends a user message mid-run, and a tool step arriving before the answer re-attached the run to the assistant message above it, so later tool calls rendered before the answer that triggered them.

Summary by CodeRabbit

  • New Features

    • Added support for capturing and displaying Copilot reasoning during and after responses.
    • Reasoning content is streamed and rendered as assistant text in the chat interface.
  • Bug Fixes

    • Ensured tool calls and returned results after picker answers appear in a new assistant message.
    • Prevented empty reasoning from creating blank messages.
    • Avoided duplicate displays of completed reasoning traces.
  • Tests

    • Added coverage for reasoning parsing, streaming, rendering, and message placement.

@htolentino-nvidia
htolentino-nvidia requested review from a team as code owners August 5, 2026 20:49
@github-actions github-actions Bot added the feat label Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Reasoning streaming and chat sequencing

Layer / File(s) Summary
Model reasoning capture
agents/nemo-studio-copilot/src/nemo_studio_copilot/register.py, agents/nemo-studio-copilot/src/nemo_studio_copilot/wrapper.py
Model wrappers preserve streamed and non-streamed reasoning_content. ReasoningStreamHandler publishes buffered reasoning as NAT intermediate steps.
Studio reasoning event translation
services/studio/src/nmp/studio/copilot.py, services/studio/tests/unit/test_copilot.py
Studio parses completed reasoning output, emits reasoning assistant events, deduplicates reasoning steps, and excludes them from tool-use deduplication.
Copilot reasoning rendering
web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts, web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
Nonempty reasoning content becomes assistant text. Empty reasoning content is discarded.
Assistant message boundary handling
web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.ts, web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.test.ts
Picker responses close the active assistant message before later tool calls or returned results stream into a new assistant message.

Sequence Diagram(s)

sequenceDiagram
  participant Model
  participant ReasoningStreamHandler
  participant StudioCopilot
  participant CopilotChat
  Model->>ReasoningStreamHandler: reasoning_content
  ReasoningStreamHandler->>StudioCopilot: NAT reasoning intermediate step
  StudioCopilot->>CopilotChat: reasoning assistant event
  CopilotChat->>CopilotChat: render reasoning as assistant text
Loading

Possibly related PRs

Suggested reviewers: steramae-nvidia

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: adding Studio Copilot reasoning-trace support.
✨ 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 studio-copilot-reasoning-trace/htolentino

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.

🧹 Nitpick comments (1)
services/studio/src/nmp/studio/copilot.py (1)

1559-1588: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the duplicate tool-input definitions.

_parse_tool_step_input is already defined at lines 1493-1517. This second definition replaces it at import time. Keep one parser and one _TOOL_INPUT_INTERNAL_KEYS declaration.

🤖 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/studio/src/nmp/studio/copilot.py` around lines 1559 - 1588, Remove
the duplicate _parse_tool_step_input definition and duplicate
_TOOL_INPUT_INTERNAL_KEYS declaration shown in this section, retaining the
existing earlier definitions. Ensure the module has only one parser
implementation and one internal-key constant without changing their behavior.
🤖 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.

Nitpick comments:
In `@services/studio/src/nmp/studio/copilot.py`:
- Around line 1559-1588: Remove the duplicate _parse_tool_step_input definition
and duplicate _TOOL_INPUT_INTERNAL_KEYS declaration shown in this section,
retaining the existing earlier definitions. Ensure the module has only one
parser implementation and one internal-key constant without changing their
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3167a490-30f8-4698-ba9c-4301a718e842

📥 Commits

Reviewing files that changed from the base of the PR and between 73670d7 and a481b10.

📒 Files selected for processing (8)
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/register.py
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/wrapper.py
  • services/studio/src/nmp/studio/copilot.py
  • services/studio/tests/unit/test_copilot.py
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.ts

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 31258/39870 78.4% 62.8%
Integration Tests 18207/37822 48.1% 20.6%

@htolentino-nvidia
htolentino-nvidia force-pushed the studio-copilot-reasoning-trace/htolentino branch from a481b10 to e4fd9aa Compare August 6, 2026 13:31
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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 (1)
services/studio/src/nmp/studio/copilot.py (1)

1559-1588: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the duplicate tool-input definitions.

Lines 1559-1588 redefine _parse_tool_step_input and _TOOL_INPUT_INTERNAL_KEYS. Retain the earlier definitions. Duplicate implementations can diverge.

🤖 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/studio/src/nmp/studio/copilot.py` around lines 1559 - 1588, Remove
the later duplicate definitions of _parse_tool_step_input and
_TOOL_INPUT_INTERNAL_KEYS, retaining the earlier implementations as the single
source of truth. Leave surrounding tool-input handling 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.

Inline comments:
In `@services/studio/src/nmp/studio/copilot.py`:
- Around line 1667-1675: Update the reasoning branch in the step-processing flow
around _parse_reasoning_step_output and _reasoning_stream_event to track
completed reasoning step["id"] values and skip duplicate completed events. Only
record an ID after parsing returns nonempty text, and do not mark paired start
events as seen. Add coverage that submits the same completed reasoning event
twice and verifies only one reasoning block is emitted.

In
`@web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.ts`:
- Around line 235-244: Update the final returned-result path around
completeActiveAssistantMessage to call ensureAssistantMessage() before
completing result.text or result.content, preserving the result under a newly
created assistant message when prepareForUserInput cleared the ID and avoiding
reuse of an old message above the picker answer. Add a regression test covering
a returned result after appendUserMessage.

---

Nitpick comments:
In `@services/studio/src/nmp/studio/copilot.py`:
- Around line 1559-1588: Remove the later duplicate definitions of
_parse_tool_step_input and _TOOL_INPUT_INTERNAL_KEYS, retaining the earlier
implementations as the single source of truth. Leave surrounding tool-input
handling unchanged.
🪄 Autofix

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: 9192f5a8-9510-4b2a-8fb6-c793c20917a5

📥 Commits

Reviewing files that changed from the base of the PR and between a1b7051 and e4fd9aa.

📒 Files selected for processing (8)
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/register.py
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/wrapper.py
  • services/studio/src/nmp/studio/copilot.py
  • services/studio/tests/unit/test_copilot.py
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/register.py
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.test.ts
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/wrapper.py
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts

Comment thread services/studio/src/nmp/studio/copilot.py
Nemotron and other vLLM/NIM-served models stream their chain of thought in a
``reasoning_content`` delta, but it never reached the UI. Each layer dropped it:

- langchain-openai 1.4.x only understands OpenAI's o-series ``reasoning`` block,
  so it discards ``reasoning_content`` on both the streaming and the non-streaming
  path. ``_preserve_reasoning_content`` re-attaches it to the message.
- NAT's ChatResponseChunk carries only ``content``, so the trace rides the same
  ``intermediate_data:`` channel the tool-call trace already uses. It is published
  per LLM run rather than per token, since one step per token would be thousands
  of frames for a single answer. NAT's StepAdaptor forwards only LLM, TOOL and
  FUNCTION categories and drops an end step whose start carries no input, hence
  the paired LLM steps.
- Studio relays it as a message part. It deliberately bypasses the tool dedup:
  the pair shares one id, so the start would claim it and the end -- which carries
  the trace -- would be dropped.
- The UI renders it as ordinary assistant text, so it reads as narration between
  tool calls rather than hiding in a collapsed block.

Also fix tool-call ordering, which the same rendering path exposed: answering a
blocking picker appends a user message mid-run, and a tool step arriving before
the answer re-attached the run to the assistant message above it, so later tool
calls rendered before the answer that triggered them.

Signed-off-by: Henrique Tolentino <htolentino@nvidia.com>
@htolentino-nvidia
htolentino-nvidia force-pushed the studio-copilot-reasoning-trace/htolentino branch from e4fd9aa to 89dd457 Compare August 6, 2026 14:08
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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.

🧹 Nitpick comments (1)
services/studio/src/nmp/studio/copilot.py (1)

1559-1590: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the duplicate _parse_tool_step_input definition. Keep one implementation to prevent future definitions from diverging.

🤖 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/studio/src/nmp/studio/copilot.py` around lines 1559 - 1590, Remove
the duplicate _parse_tool_step_input definition, retaining the existing single
implementation and its current parsing behavior. Ensure callers continue
resolving to that one function and do not alter the nearby
_TOOL_INPUT_INTERNAL_KEYS declaration.
🤖 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.

Nitpick comments:
In `@services/studio/src/nmp/studio/copilot.py`:
- Around line 1559-1590: Remove the duplicate _parse_tool_step_input definition,
retaining the existing single implementation and its current parsing behavior.
Ensure callers continue resolving to that one function and do not alter the
nearby _TOOL_INPUT_INTERNAL_KEYS declaration.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1bf01763-89c4-4085-9fac-e015b59c927c

📥 Commits

Reviewing files that changed from the base of the PR and between a1b7051 and 89dd457.

📒 Files selected for processing (8)
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/register.py
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/wrapper.py
  • services/studio/src/nmp/studio/copilot.py
  • services/studio/tests/unit/test_copilot.py
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/register.py
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.ts
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/wrapper.py

@dmariali dmariali 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.

amaze amaze amaze

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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.

🧹 Nitpick comments (1)
services/studio/src/nmp/studio/copilot.py (1)

1559-1588: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep one tool-input parser definition.

Remove or reconcile the earlier definitions of _parse_tool_step_input and _TOOL_INPUT_INTERNAL_KEYS. Python uses the later definitions.

🤖 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/studio/src/nmp/studio/copilot.py` around lines 1559 - 1588,
Consolidate `_parse_tool_step_input` and `_TOOL_INPUT_INTERNAL_KEYS` into single
definitions, removing or reconciling any earlier duplicates so the intended
parser and internal-key set are unambiguous. Preserve the existing parsing
behavior and filtering of `studio_session_id`.
🤖 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.

Nitpick comments:
In `@services/studio/src/nmp/studio/copilot.py`:
- Around line 1559-1588: Consolidate `_parse_tool_step_input` and
`_TOOL_INPUT_INTERNAL_KEYS` into single definitions, removing or reconciling any
earlier duplicates so the intended parser and internal-key set are unambiguous.
Preserve the existing parsing behavior and filtering of `studio_session_id`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: dda7beac-0084-4a77-86e0-f947d408d1d3

📥 Commits

Reviewing files that changed from the base of the PR and between c71ca67 and 01d669f.

📒 Files selected for processing (8)
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/register.py
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/wrapper.py
  • services/studio/src/nmp/studio/copilot.py
  • services/studio/tests/unit/test_copilot.py
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • agents/nemo-studio-copilot/src/nemo_studio_copilot/register.py
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/useCustomAssistantChatRuntime.test.ts

@htolentino-nvidia
htolentino-nvidia marked this pull request as draft August 6, 2026 20:18
@htolentino-nvidia
htolentino-nvidia marked this pull request as ready for review August 6, 2026 20:18
@htolentino-nvidia
htolentino-nvidia added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit 9ded2d6 Aug 7, 2026
89 of 98 checks passed
@htolentino-nvidia
htolentino-nvidia deleted the studio-copilot-reasoning-trace/htolentino branch August 7, 2026 00:14
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