Skip to content

refactor(studio): move shared UI components into @nemo/common - #1192

Merged
marcusds merged 9 commits into
mainfrom
promote-studio-ui-to-shared/mschwab
Aug 11, 2026
Merged

refactor(studio): move shared UI components into @nemo/common#1192
marcusds merged 9 commits into
mainfrom
promote-studio-ui-to-shared/mschwab

Conversation

@marcusds

@marcusds marcusds commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Plugin bundles reach Studio's shared UI through the curated barrel in common/src/plugin.ts (#1180), but most of the components Iron Swarm needs lived in web/packages/studio and were unreachable. This moves them into @nemo/common, adds host.breadcrumbs to the plugin contract, and keeps the shared vendor bundle free of the SDK.

Follow-up to #1180; prerequisite for moving the Iron Swarm UI out of Studio (#1037).

Related Issue

None.

Changes

Moved to @nemo/common (via git mv, so history follows) with their tests — AccessibleTitle, AccordionSection, ExpandableMessage, FileTag, InputErrorText, FileUpload, QuickActionsMenuRoot, ConfirmationModal, DeleteConfirmationModal, ErrorPanel, CancelJobButton, plus api/common/utils, util/forms/error and util/logger. Studio's ~150 importers point at @nemo/common directly; no re-export shims.

host.breadcrumbs — Studio's breadcrumb bar renders in GlobalNav, in the layout's navbar grid area, while a plugin renders in the content area several route levels below. A plugin cannot render it itself and can only write into the context GlobalNav consumes, so it's exposed on the host handle like notifications. Studio clears the trail on plugin unmount and on :pluginName change.

Three severs, so a shared library doesn't inherit Studio app config:

what why
logger takes its service name via configureLogger(), called from App.tsx avoids dragging constants/environmentfeatureFlags into common; logVersion stays in Studio since it needs VERSION_SHA
CancelJobButton takes workspace as a prop it read the router via useWorkspaceFromPath; both call sites already had the value
getErrorMessage moved out of NewDataDesignerJobForm/utils seven dependency-free lines, nothing to do with Data Designer — importing it dragged a 206-line module and the logger chain behind it

What is deliberately not plugin API

Exporting CreateSecretModal, fetchAgentsForSelect, getErrorMessage (the axios-aware one), CancelJobButton or ErrorPanel pulls the generated SDK client into the shared vendor bundle:

barrel contents vendor/common.js axios oidc-client-ts
baseline (#1180) 241 kB absent absent
everything exported 553 kB present present
as merged here 339 kB absent absent

Not just weight: plugins receive the SDK on host.sdk so there is exactly one axios instance carrying Studio's OIDC interceptor. A second copy inside common.js would issue unauthenticated requests against a differently-configured client. Those components still live in common for Studio's use; a plugin composes equivalents from the primitives the barrel does export, wired to host.sdk.

Barrel is 42 exports.

Type of Change

  • Code change with documentation updates

Quality Gates

  • Tests added or updated for changed behavior — two new tests cover the breadcrumbs contract (write-through + cleanup, and the plugin-switch reset); the latter was verified to fail without its fix.
  • Documentation updated for user-visible behavior — plugins/example-plugin/web/AGENTS.md.

Verification

  • Pull request title follows the repository's Conventional Commit format
  • Every commit includes an appropriate Signed-off-by: trailer
  • uv run pre-commit run passes, or any blocked checks are identified below
  • Targeted tests pass, or tests are marked not applicable above
  • No secrets, API keys, or credentials are included
Command Result
pnpm --filter @nemo/common typecheck / lint pass
pnpm --filter @nemo/common test pass — 1429 tests
pnpm --filter nemo-studio-ui typecheck / lint pass
pnpm --filter nemo-studio-ui test pass — 2799 tests
pnpm --filter nemo-studio-ui build pass — vendor/common.js 339 kB, 42 exports, axios/oidc/zod absent
example plugin typecheck / build pass
uv run pre-commit run pass

Also verified: @nemo/common contains zero @studio/* imports, and no stale references to removed paths.

Not verified in a browser. Green typecheck/lint/tests, but the promoted components have not been exercised in a running Studio.

Request NVSkills CI is failing for two reasons, one of which is not this PR: the gate requires a /nvskills-ci comment because plugins/ changed, and the reusable workflow itself crashes with jq: Argument list too long (exit 2) on this PR's 216-file list — a bug in NVIDIA/skills/.github/workflows/team-request.yml@e0cd22d that will hit any large PR touching a watched path.

Follow-up

  • Studio still deep-imports @nemo/common/src/... (its documented convention, ~144 pre-existing call sites). If a Studio-facing public barrel is wanted, it should be separate from plugin.ts, which is plugin API with bundle consequences.
  • host.sdk.agents — needed by the Iron Swarm move, since fetchAgentsForSelect is not plugin API.

Summary by CodeRabbit

  • New Features
    • Plugins can set workspace breadcrumbs that update and clear automatically as navigation changes.
    • Plugin navigation items merge into matching menus, with unmatched groups added in order.
    • Notifications support custom durations and consistent delivery across shared UI components.
    • Added reusable accordions, expandable messages, file status tags, quick actions, accessible page titles, and input errors.
  • Bug Fixes
    • Improved error messages for validation, network, HTTP, and version-conflict failures.
    • Job cancellation now consistently targets the active workspace.
    • File upload errors now provide clearer feedback for invalid types and excess files.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 32000/40622 78.8% 63.5%
Integration Tests 18551/38548 48.1% 20.8%

@marcusds
marcusds marked this pull request as ready for review August 7, 2026 22:50
@marcusds
marcusds requested review from a team as code owners August 7, 2026 22:50
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR centralizes shared Studio components and utilities in @nemo/common. It updates Studio consumers, adds configurable notifications, and adds plugin breadcrumb synchronization and navigation-group merging.

Changes

Shared common package and plugin integration

Layer / File(s) Summary
Shared components, utilities, and notification routing
web/packages/common/...
Adds reusable components, API utilities, file-upload helpers, logging configuration, notification routing, exports, and dependencies.
Studio migration and application wiring
web/packages/studio/...
Updates Studio imports to shared modules. Logger configuration uses OTEL_SERVICE_NAME. CancelJobButton receives workspace.
Plugin contracts and breadcrumbs
web/packages/studio/src/plugins/..., plugins/example-plugin/web/...
Adds notification options and breadcrumb contracts. PluginRenderer maps and clears plugin breadcrumbs. The example plugin sets workspace breadcrumbs.
Plugin navigation merging
web/packages/studio/src/routes/WorkspaceLayout/WorkspaceSideNav.tsx, web/packages/studio/src/routes/WorkspaceLayout/WorkspaceSideNav.test.tsx
Merges plugin groups with matching built-in groups and appends unmatched groups. Tests cover duplicate IDs and multi-plugin merging.

Possibly related PRs

🚥 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 clearly summarizes the PR's primary change: moving shared Studio UI components into @nemo/common.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch promote-studio-ui-to-shared/mschwab
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch promote-studio-ui-to-shared/mschwab

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: 13

🧹 Nitpick comments (5)
web/packages/common/src/components/AccessibleTitle/index.tsx (1)

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

Use type-only imports.

  • web/packages/common/src/components/AccessibleTitle/index.tsx#L4-L4: move FC and PropsWithChildren to import type.
  • web/packages/common/src/components/AccordionSection/index.tsx#L10-L10: move FC, PropsWithChildren, and ReactNode to import type.
🤖 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/common/src/components/AccessibleTitle/index.tsx` at line 4,
Convert FC and PropsWithChildren to type-only imports in AccessibleTitle, and
convert FC, PropsWithChildren, and ReactNode to type-only imports in
AccordionSection; leave runtime React imports unchanged.

Source: Coding guidelines

web/packages/common/src/components/ExpandableMessage/index.tsx (1)

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

Use type-only imports for type-only symbols.

  • Mark the listed type-only symbols as type.
  • In FileUpload/index.tsx, also mark FC, MouseEvent, MouseEventHandler, ReactNode, DropEvent, DropzoneOptions, and FileRejection as type-only.
  • Keep runtime imports such as FileTag, ErrorCode, React, and useDropzone as value imports.
🤖 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/common/src/components/ExpandableMessage/index.tsx` at line 5,
Update imports at
web/packages/common/src/components/ExpandableMessage/index.tsx:5-5,
web/packages/common/src/components/FileTag/index.tsx:4-6,
web/packages/common/src/components/FileUpload/index.tsx:4-4,
web/packages/common/src/components/FileUpload/util.ts:4-4,
web/packages/common/src/components/InputErrorText/index.tsx:5-5, and
web/packages/common/src/components/QuickActionsMenu/QuickActionsMenuRoot/index.tsx:15-15
to mark all type-only symbols with the type modifier. In FileUpload/index.tsx,
apply this to FC, MouseEvent, MouseEventHandler, ReactNode, DropEvent,
DropzoneOptions, and FileRejection, while retaining FileTag, ErrorCode, React,
and useDropzone as value imports.

Source: Coding guidelines

web/packages/studio/src/components/CustomizationFileTag/index.tsx (1)

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

Use explicit type-only imports.

  • web/packages/studio/src/components/CustomizationFileTag/index.tsx#L4-L4: keep FileTag as a value import and import FileTagProps with import type.
  • web/packages/studio/src/components/CustomizationFileUpload/index.tsx#L4-L4: change the RenderFileTagFn import to import type.

As per coding guidelines, use import type for type-only imports.

🤖 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/CustomizationFileTag/index.tsx` at line 4,
Update the import in
web/packages/studio/src/components/CustomizationFileTag/index.tsx:4 so FileTag
remains a value import while FileTagProps uses import type; update the
RenderFileTagFn import in
web/packages/studio/src/components/CustomizationFileUpload/index.tsx:4 to use
import type.

Source: Coding guidelines

web/packages/studio/src/components/DatasetFileUpload/index.tsx (1)

4-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mark type-only imports with import type.

FileTagStatus and RenderFileTagFn are type exports. Split them into import type declarations.

As per coding guidelines, use import type for type-only imports.

🤖 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/DatasetFileUpload/index.tsx` around lines
4 - 5, Update the imports in the DatasetFileUpload module so the type-only
symbols FileTagStatus and RenderFileTagFn use separate import type declarations,
while retaining FileTag and FileUpload as regular runtime imports.

Source: Coding guidelines

web/packages/studio/src/util/logVersion.ts (1)

7-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Declare the public return type.

Add the explicit return type to the exported function:

-export const logVersion = async () => {
+export const logVersion = async (): Promise<void> => {

As per coding guidelines, public APIs should declare explicit return types.

🤖 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/logVersion.ts` around lines 7 - 11, Update the
exported logVersion function to declare its explicit Promise-based return type,
matching its async implementation and existing behavior.

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 `@plugins/example-plugin/web/AGENTS.md`:
- Around line 38-41: Add host.breadcrumbs to the injected host capability list
near the existing navigation entry, keeping it consistent with the capability
contract defined in SharedUiPage.tsx.

In `@plugins/example-plugin/web/src/SharedUiPage.tsx`:
- Line 13: Update the import of pluginPath in SharedUiPage.tsx to use the
project’s configured absolute alias instead of the relative "./paths" path,
while preserving the same imported symbol.
- Around line 26-34: Update the breadcrumb effect in SharedUiPage to return a
cleanup function that clears the page trail through setBreadcrumbs when the page
unmounts. Preserve the existing breadcrumb setup on mount and ensure cleanup
also runs when its dependencies change.

In `@web/packages/common/src/api/common/utils.ts`:
- Around line 4-8: Update the import of GenericSortField, PaginationData, and
ValidationError to use a type-only import, since these SDK symbols are
referenced only in type positions.
- Around line 99-105: Update the request-context formatting in the error
handling logic around error.config so user-visible messages never include raw
URLs with query parameters or fragments. Sanitize url by removing its query
string and fragment before appending it to parts, while preserving the existing
method and URL context when available.
- Around line 37-43: Update the item validation predicate in the API error
utility to require that item.loc is an array before accepting the object.
Preserve the existing msg and type checks so downstream filtering can safely
call filter on loc.

In `@web/packages/common/src/components/ExpandableMessage/index.tsx`:
- Around line 55-58: The fixed danger styling is currently overwritten by caller
className props. In
web/packages/common/src/components/ExpandableMessage/index.tsx#L55-L58, update
the Text className handling to merge attributes.Text.className while always
retaining text-feedback-danger; apply the same merge in
web/packages/common/src/components/InputErrorText/index.tsx#L18-L18 for
props.className.

In `@web/packages/studio/src/components/DataDesignerJobActionsMenu/index.tsx`:
- Around line 4-7: Replace the deep internal `@nemo/common/src/`... imports with
public `@nemo/common` barrel imports: in
web/packages/studio/src/components/DataDesignerJobActionsMenu/index.tsx (lines
4-7), import QuickActionsMenuRoot and QuickActionItem; in
web/packages/studio/src/components/DatasetFileUpload/index.tsx (lines 4-5),
import FileTag and FileUpload; in
web/packages/studio/src/routes/InferenceProvidersListRoute/index.tsx (line 13)
and web/packages/studio/src/routes/IntakeLayout/index.tsx (line 4), import
AccessibleTitle; and in web/packages/studio/src/routes/JobDetailRoute/index.tsx
(lines 4-5), import AccessibleTitle and CancelJobButton. Ensure none of these
migrated shared UI imports use `@nemo/common/src/` paths.

In `@web/packages/studio/src/components/promoted/ErrorPanel.test.tsx`:
- Around line 4-5: Update the import containing ErrorPanelProps to use a
type-only import while keeping the runtime ErrorPanel import unchanged.

In
`@web/packages/studio/src/components/PromptTuningForm/InContextLearningSection/index.tsx`:
- Line 5: Update the shared UI imports to use the public `@nemo/common` entry
point: in
web/packages/studio/src/components/PromptTuningForm/InContextLearningSection/index.tsx:5,
web/packages/studio/src/routes/agents/AgentSuggestionsRoute/index.tsx:4, and
web/packages/studio/src/routes/agents/AgentsListRoute/index.tsx:4, import
AccordionSection or AccessibleTitle from `@nemo/common` instead of deep-linking
into src. Export either component through web/packages/common/src/plugin.ts if
the barrel does not already expose it.

In
`@web/packages/studio/src/components/PromptTuningForm/InferenceParametersSection/index.tsx`:
- Line 4: Update Studio’s module resolver and TypeScript path mapping to resolve
shared UI through the curated `@nemo/common` entry point exported by plugin.ts,
then replace the seven deep imports in
web/packages/studio/src/components/PromptTuningForm/InferenceParametersSection/index.tsx
(anchor), PromptTemplateSection/index.tsx, ToolsSection/index.tsx,
QuickActionsMenu/QuickActionsMenuDefault/index.tsx,
routes/agents/CopilotChatRoute/historyPanel/HistoryPanelContents.tsx,
routes/agents/CopilotChatRoute/index.tsx, and
routes/evaluation/EvaluationLayout/index.tsx with imports from that entry point.

In `@web/packages/studio/src/plugins/PluginRenderer.tsx`:
- Around line 56-57: Update the cleanup useEffect in PluginRenderer to include
pluginName in its dependency array so setBreadcrumbs([]) runs when the routed
plugin changes, then add a test covering a retained PluginRenderer switching
pluginName and clearing the previous breadcrumbs.

In `@web/packages/studio/src/routes/optimizer/OptimizerRoute/index.tsx`:
- Around line 5-10: Replace all listed deep shared-UI imports with the bare
`@nemo/common` barrel, and add any missing symbols to plugin.ts exports:
web/packages/studio/src/routes/optimizer/OptimizerRoute/index.tsx (lines 5-10)
for AccessibleTitle, StudioDataView, and ErrorPanel;
web/packages/studio/src/routes/optimizer/OptimizerInsightRoute/index.tsx (lines
4-6) for AccessibleTitle, ErrorMessage, and ExpandableMessage;
web/packages/studio/src/routes/index.tsx (line 5) for ErrorPanel;
web/packages/studio/src/routes/guardrails/GuardrailDetailRoute/index.tsx (line
6) for AccessibleTitle;
web/packages/studio/src/routes/guardrails/GuardrailDetailRoute/GuardrailDetailActions.tsx
(lines 4-8) for DeleteConfirmationModal and QuickActionsMenuRoot;
web/packages/studio/src/components/promoted/DeleteConfirmationModal.test.tsx
(line 4) for DeleteConfirmationModal; and
web/packages/studio/src/components/promoted/CancelJobButton.test.tsx (line 4)
for CancelJobButton.

---

Nitpick comments:
In `@web/packages/common/src/components/AccessibleTitle/index.tsx`:
- Line 4: Convert FC and PropsWithChildren to type-only imports in
AccessibleTitle, and convert FC, PropsWithChildren, and ReactNode to type-only
imports in AccordionSection; leave runtime React imports unchanged.

In `@web/packages/common/src/components/ExpandableMessage/index.tsx`:
- Line 5: Update imports at
web/packages/common/src/components/ExpandableMessage/index.tsx:5-5,
web/packages/common/src/components/FileTag/index.tsx:4-6,
web/packages/common/src/components/FileUpload/index.tsx:4-4,
web/packages/common/src/components/FileUpload/util.ts:4-4,
web/packages/common/src/components/InputErrorText/index.tsx:5-5, and
web/packages/common/src/components/QuickActionsMenu/QuickActionsMenuRoot/index.tsx:15-15
to mark all type-only symbols with the type modifier. In FileUpload/index.tsx,
apply this to FC, MouseEvent, MouseEventHandler, ReactNode, DropEvent,
DropzoneOptions, and FileRejection, while retaining FileTag, ErrorCode, React,
and useDropzone as value imports.

In `@web/packages/studio/src/components/CustomizationFileTag/index.tsx`:
- Line 4: Update the import in
web/packages/studio/src/components/CustomizationFileTag/index.tsx:4 so FileTag
remains a value import while FileTagProps uses import type; update the
RenderFileTagFn import in
web/packages/studio/src/components/CustomizationFileUpload/index.tsx:4 to use
import type.

In `@web/packages/studio/src/components/DatasetFileUpload/index.tsx`:
- Around line 4-5: Update the imports in the DatasetFileUpload module so the
type-only symbols FileTagStatus and RenderFileTagFn use separate import type
declarations, while retaining FileTag and FileUpload as regular runtime imports.

In `@web/packages/studio/src/util/logVersion.ts`:
- Around line 7-11: Update the exported logVersion function to declare its
explicit Promise-based return type, matching its async implementation and
existing behavior.
🪄 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: bb6b888f-fa73-4f91-99cc-42e77e521843

📥 Commits

Reviewing files that changed from the base of the PR and between 25ab603 and eb5737f.

⛔ Files ignored due to path filters (2)
  • plugins/example-plugin/src/nemo_example_plugin/web/dist/index.js is excluded by !**/dist/**
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (214)
  • plugins/example-plugin/web/AGENTS.md
  • plugins/example-plugin/web/src/SharedUiPage.tsx
  • plugins/example-plugin/web/src/types.ts
  • web/packages/common/package.json
  • web/packages/common/src/api/common/utils.test.ts
  • web/packages/common/src/api/common/utils.ts
  • web/packages/common/src/components/AccessibleTitle/index.test.tsx
  • web/packages/common/src/components/AccessibleTitle/index.tsx
  • web/packages/common/src/components/AccordionSection/index.tsx
  • web/packages/common/src/components/CancelJobButton/index.tsx
  • web/packages/common/src/components/ConfirmationModal/index.tsx
  • web/packages/common/src/components/DeleteConfirmationModal/index.tsx
  • web/packages/common/src/components/ErrorPanel/index.tsx
  • web/packages/common/src/components/ExpandableMessage/index.test.tsx
  • web/packages/common/src/components/ExpandableMessage/index.tsx
  • web/packages/common/src/components/FileTag/index.tsx
  • web/packages/common/src/components/FileUpload/index.tsx
  • web/packages/common/src/components/FileUpload/util.ts
  • web/packages/common/src/components/InputErrorText/index.tsx
  • web/packages/common/src/components/QuickActionsMenu/QuickActionsMenuRoot/index.test.tsx
  • web/packages/common/src/components/QuickActionsMenu/QuickActionsMenuRoot/index.tsx
  • web/packages/common/src/plugin.ts
  • web/packages/common/src/utils/error.ts
  • web/packages/common/src/utils/forms/error.test.ts
  • web/packages/common/src/utils/forms/error.ts
  • web/packages/common/src/utils/logger.ts
  • web/packages/studio/src/App.tsx
  • web/packages/studio/src/api/datasets/useDatasetFileContent.ts
  • web/packages/studio/src/api/guardrail-checks/guardrailChecks.ts
  • web/packages/studio/src/components/AnonymizerJobActionsMenu/index.tsx
  • web/packages/studio/src/components/BulkDeleteModal/index.tsx
  • web/packages/studio/src/components/CreateFilesetStart/useDescribeWithAi.ts
  • web/packages/studio/src/components/CustomizationFileTag/index.tsx
  • web/packages/studio/src/components/CustomizationFileUpload/index.tsx
  • web/packages/studio/src/components/CustomizationFilesetCreateModal/index.tsx
  • web/packages/studio/src/components/DataDesignerJobActionsMenu/index.tsx
  • web/packages/studio/src/components/DatasetCreateModal/index.tsx
  • web/packages/studio/src/components/DatasetFileUpload/index.tsx
  • web/packages/studio/src/components/DatasetInputFile/index.tsx
  • web/packages/studio/src/components/DatasetsTable/index.test.tsx
  • web/packages/studio/src/components/DatasetsTable/index.tsx
  • web/packages/studio/src/components/ExperimentCreateModal/index.tsx
  • web/packages/studio/src/components/FilesTable/CreateFileSplitsModal/index.tsx
  • web/packages/studio/src/components/FilesTable/DirectoryQuickActions/index.tsx
  • web/packages/studio/src/components/FilesTable/FileQuickActions/index.tsx
  • web/packages/studio/src/components/FilesTable/RenameFileModal/index.tsx
  • web/packages/studio/src/components/FilesTable/TransformFileModal/index.tsx
  • web/packages/studio/src/components/FilesetActionMenu/index.tsx
  • web/packages/studio/src/components/FilesetCreateModal/index.tsx
  • web/packages/studio/src/components/FilesetFilePreviewPanel/components/FileActions/index.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/AnnotationsPanel.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/useSpanAnnotationActions.ts
  • web/packages/studio/src/components/IntakeDetail/SessionDetailView.tsx
  • web/packages/studio/src/components/IntakeDetail/TraceSpanAccordions.tsx
  • web/packages/studio/src/components/IntakeLists/IntakeSpansTable.tsx
  • web/packages/studio/src/components/IntakeLists/IntakeTracesTable.tsx
  • web/packages/studio/src/components/ModelActionsMenu/index.tsx
  • web/packages/studio/src/components/ModelChat/index.tsx
  • web/packages/studio/src/components/ModelComparePrompts/useModelComparePrompts.ts
  • web/packages/studio/src/components/NewCustomizationForm/index.tsx
  • web/packages/studio/src/components/NewDataDesignerJobForm/JobRequestGenerator.tsx
  • web/packages/studio/src/components/NewDataDesignerJobForm/usePreview.ts
  • web/packages/studio/src/components/NewDataDesignerJobForm/utils.test.ts
  • web/packages/studio/src/components/NewDataDesignerJobForm/utils.ts
  • web/packages/studio/src/components/PromptTuningForm/ImportFromDatasetModal/index.tsx
  • web/packages/studio/src/components/PromptTuningForm/InContextLearningSection/index.tsx
  • web/packages/studio/src/components/PromptTuningForm/InferenceParametersSection/index.tsx
  • web/packages/studio/src/components/PromptTuningForm/PromptTemplateSection/index.tsx
  • web/packages/studio/src/components/PromptTuningForm/ToolsSection/index.tsx
  • web/packages/studio/src/components/QuickActionsMenu/QuickActionsMenuDefault/index.tsx
  • web/packages/studio/src/components/WorkspaceCreateModal/index.tsx
  • web/packages/studio/src/components/WorkspaceDropdown/index.tsx
  • web/packages/studio/src/components/common/SearchBar/index.tsx
  • web/packages/studio/src/components/dataViews/AgentEvaluationsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/AgentsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/CustomModelsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/DeploymentsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/ExperimentDataView/index.tsx
  • web/packages/studio/src/components/dataViews/GuardrailsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/InferenceProvidersDataView/index.tsx
  • web/packages/studio/src/components/dataViews/JobsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/SafeSynthesizerJobsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/SecretsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/VirtualModelsDataView/index.tsx
  • web/packages/studio/src/components/evaluation/Configurations/form/InputFile/useInputFile.ts
  • web/packages/studio/src/components/evaluation/Jobs/ActionMenu.tsx
  • web/packages/studio/src/components/evaluation/Jobs/DetailsPanel.tsx
  • web/packages/studio/src/components/evaluation/Jobs/EvaluationJobBulkDeleteModal.tsx
  • web/packages/studio/src/components/evaluation/Jobs/form/ScoreDefinitions.tsx
  • web/packages/studio/src/components/filesets/AddToFolderModal/index.tsx
  • web/packages/studio/src/components/filesets/FilesetFileExplorer/DatasetFileDropzone/index.tsx
  • web/packages/studio/src/components/filesets/FilesetFileExplorer/NewDirectoryModal/index.tsx
  • web/packages/studio/src/components/filesets/hooks/useBulkDownload.ts
  • web/packages/studio/src/components/filesets/hooks/useBulkDuplicate.ts
  • web/packages/studio/src/components/promoted/CancelJobButton.test.tsx
  • web/packages/studio/src/components/promoted/DeleteConfirmationModal.test.tsx
  • web/packages/studio/src/components/promoted/ErrorPanel.test.tsx
  • web/packages/studio/src/components/sidePanels/MetricRunSidePanel/index.tsx
  • web/packages/studio/src/components/sidePanels/ModelPanels/ModelPanel/components.tsx
  • web/packages/studio/src/components/sidePanels/ModelPanels/ModelPanel/index.tsx
  • web/packages/studio/src/main.tsx
  • web/packages/studio/src/plugins/PluginErrorBoundary.tsx
  • web/packages/studio/src/plugins/PluginRenderer.test.tsx
  • web/packages/studio/src/plugins/PluginRenderer.tsx
  • web/packages/studio/src/plugins/types.ts
  • web/packages/studio/src/plugins/utils.ts
  • web/packages/studio/src/routes/AnonymizerBuilderRoute/components/AnonymizerBuilderForm.tsx
  • web/packages/studio/src/routes/AnonymizerBuilderRoute/index.tsx
  • web/packages/studio/src/routes/AnonymizerJobDetailRoute/index.tsx
  • web/packages/studio/src/routes/AnonymizerListRoute/index.tsx
  • web/packages/studio/src/routes/AuthSuccessRoute/index.tsx
  • web/packages/studio/src/routes/CustomizationJobDetailsRoute/DetailActions.tsx
  • web/packages/studio/src/routes/CustomizationJobDetailsRoute/index.tsx
  • web/packages/studio/src/routes/CustomizationJobListRoute/index.tsx
  • web/packages/studio/src/routes/DashboardLandingRoute/index.tsx
  • web/packages/studio/src/routes/DataDesignerJobBuildRoute/index.tsx
  • web/packages/studio/src/routes/DataDesignerJobDetailsRoute/index.tsx
  • web/packages/studio/src/routes/DataDesignerJobListRoute/index.tsx
  • web/packages/studio/src/routes/DeploymentsListRoute/CreateDeploymentSidePanel/useCreateDeploymentBySource.ts
  • web/packages/studio/src/routes/DeploymentsListRoute/index.tsx
  • web/packages/studio/src/routes/DeploymentsListRoute/useDeleteDeploymentAndConfig.ts
  • web/packages/studio/src/routes/EvaluationDetailRoute/index.tsx
  • web/packages/studio/src/routes/EvaluationSessionDetailRoute/SessionCompareColumn.tsx
  • web/packages/studio/src/routes/EvaluationSessionDetailRoute/TestCaseCompare.tsx
  • web/packages/studio/src/routes/ExperimentDetailRoute/index.tsx
  • web/packages/studio/src/routes/ExperimentRoute/index.tsx
  • web/packages/studio/src/routes/FilesetDetailRoute/index.tsx
  • web/packages/studio/src/routes/FilesetListRoute/ActionMenu/index.test.tsx
  • web/packages/studio/src/routes/FilesetListRoute/ActionMenu/index.tsx
  • web/packages/studio/src/routes/FilesetListRoute/index.tsx
  • web/packages/studio/src/routes/FilesetNewRoute/helpers.ts
  • web/packages/studio/src/routes/FilesetNewRoute/index.tsx
  • web/packages/studio/src/routes/FilesetNewRoute/useCreateFileset.ts
  • web/packages/studio/src/routes/InferenceProvidersListRoute/CreateInferenceProviderSidePanel/index.tsx
  • web/packages/studio/src/routes/InferenceProvidersListRoute/index.tsx
  • web/packages/studio/src/routes/IntakeLayout/index.tsx
  • web/packages/studio/src/routes/JobDetailRoute/index.tsx
  • web/packages/studio/src/routes/JobsRoute/index.tsx
  • web/packages/studio/src/routes/LegacyNewDataDesignerJobRoute/index.tsx
  • web/packages/studio/src/routes/NewDataDesignerJobRoute/index.tsx
  • web/packages/studio/src/routes/PromptTuningFormRoute/index.tsx
  • web/packages/studio/src/routes/SafeSynthesizerJobDetailsRoute/index.tsx
  • web/packages/studio/src/routes/SafeSynthesizerJobReportRoute/index.tsx
  • web/packages/studio/src/routes/SafeSynthesizerListRoute/index.tsx
  • web/packages/studio/src/routes/SafeSynthesizerNewRoute/index.test.tsx
  • web/packages/studio/src/routes/SafeSynthesizerNewRoute/index.tsx
  • web/packages/studio/src/routes/SecretsListRoute/CreateSecretModal/index.tsx
  • web/packages/studio/src/routes/SecretsListRoute/EditSecretModal/index.tsx
  • web/packages/studio/src/routes/SecretsListRoute/index.tsx
  • web/packages/studio/src/routes/VirtualModelsListRoute/index.tsx
  • web/packages/studio/src/routes/WorkspaceBaseModelsRoute/index.tsx
  • web/packages/studio/src/routes/WorkspaceDashboardRoute/index.tsx
  • web/packages/studio/src/routes/WorkspaceLayout/WorkspaceSideNav.tsx
  • web/packages/studio/src/routes/WorkspaceMembersRoute/WorkspaceMemberModal.tsx
  • web/packages/studio/src/routes/WorkspaceMembersRoute/index.tsx
  • web/packages/studio/src/routes/WorkspaceSettingsRoute/DeleteWorkspaceModal/index.tsx
  • web/packages/studio/src/routes/WorkspaceSettingsRoute/EditDescriptionModal/index.tsx
  • web/packages/studio/src/routes/WorkspaceSettingsRoute/index.tsx
  • web/packages/studio/src/routes/agents/AgentDetailRoute/DeploymentLogsView.tsx
  • web/packages/studio/src/routes/agents/AgentDetailRoute/index.tsx
  • web/packages/studio/src/routes/agents/AgentEvaluationsRoute/AgentEvaluationDetailRoute.tsx
  • web/packages/studio/src/routes/agents/AgentEvaluationsRoute/AgentEvaluationsListRoute.tsx
  • web/packages/studio/src/routes/agents/AgentMonitorRoute/index.tsx
  • web/packages/studio/src/routes/agents/AgentSuggestionsRoute/api.ts
  • web/packages/studio/src/routes/agents/AgentSuggestionsRoute/index.tsx
  • web/packages/studio/src/routes/agents/AgentSuggestionsRoute/useOptimizerSuggestions.ts
  • web/packages/studio/src/routes/agents/AgentSuggestionsRoute/utils.ts
  • web/packages/studio/src/routes/agents/AgentsListRoute/CloneAgentModal/index.tsx
  • web/packages/studio/src/routes/agents/AgentsListRoute/CreateExampleAgentModal/index.tsx
  • web/packages/studio/src/routes/agents/AgentsListRoute/index.tsx
  • web/packages/studio/src/routes/agents/CopilotChatRoute/ChatThreadErrorBoundary.tsx
  • web/packages/studio/src/routes/agents/CopilotChatRoute/historyPanel/HistoryPanelContents.tsx
  • web/packages/studio/src/routes/agents/CopilotChatRoute/index.tsx
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts
  • web/packages/studio/src/routes/evaluation/EvaluationLayout/index.tsx
  • web/packages/studio/src/routes/evaluation/EvaluationResultDetailsRoute/index.tsx
  • web/packages/studio/src/routes/evaluation/EvaluationResultsLayout/index.tsx
  • web/packages/studio/src/routes/groups/agentRoutes.tsx
  • web/packages/studio/src/routes/groups/anonymizerRoutes.tsx
  • web/packages/studio/src/routes/groups/customizationRoutes.tsx
  • web/packages/studio/src/routes/groups/dashboardRoutes.tsx
  • web/packages/studio/src/routes/groups/dataDesignerRoutes.tsx
  • web/packages/studio/src/routes/groups/deploymentRoutes.tsx
  • web/packages/studio/src/routes/groups/evaluationRoutes.tsx
  • web/packages/studio/src/routes/groups/experimentRoutes.tsx
  • web/packages/studio/src/routes/groups/filesetRoutes.tsx
  • web/packages/studio/src/routes/groups/guardrailsRoutes.tsx
  • web/packages/studio/src/routes/groups/inferenceProviderRoutes.tsx
  • web/packages/studio/src/routes/groups/intakeRoutes.tsx
  • web/packages/studio/src/routes/groups/jobRoutes.tsx
  • web/packages/studio/src/routes/groups/memberRoutes.tsx
  • web/packages/studio/src/routes/groups/modelCompareRoutes.tsx
  • web/packages/studio/src/routes/groups/optimizerRoutes.tsx
  • web/packages/studio/src/routes/groups/safeSynthesizerRoutes.tsx
  • web/packages/studio/src/routes/groups/secretsRoutes.tsx
  • web/packages/studio/src/routes/groups/settingsRoutes.tsx
  • web/packages/studio/src/routes/groups/virtualModelsRoutes.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailChecksTab/GuardrailTestCard.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailChecksTab/GuardrailTestCasesEditor.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailDetailRoute/GuardrailDetailActions.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailDetailRoute/index.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/index.tsx
  • web/packages/studio/src/routes/index.tsx
  • web/packages/studio/src/routes/optimizer/InsightTracesTable/index.tsx
  • web/packages/studio/src/routes/optimizer/OptimizerInsightRoute/index.tsx
  • web/packages/studio/src/routes/optimizer/OptimizerRoute/index.tsx
  • web/packages/studio/src/util/files.ts
  • web/packages/studio/src/util/llm.ts
  • web/packages/studio/src/util/logVersion.ts
  • web/packages/studio/src/util/logger.test.ts
  • web/packages/studio/src/util/strings.ts
  • web/packages/studio/src/workers/LargeFileWorker.ts
💤 Files with no reviewable changes (1)
  • web/packages/studio/src/components/NewDataDesignerJobForm/utils.ts

Comment thread plugins/example-plugin/web/AGENTS.md Outdated
Comment thread plugins/example-plugin/web/src/SharedUiPage.tsx
Comment thread plugins/example-plugin/web/src/SharedUiPage.tsx Outdated
Comment thread web/packages/studio/src/components/promoted/ErrorPanel.test.tsx
Comment thread web/packages/studio/src/plugins/PluginRenderer.tsx Outdated
Comment thread web/packages/studio/src/routes/optimizer/OptimizerRoute/index.tsx

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 13

🧹 Nitpick comments (5)
web/packages/common/src/components/AccessibleTitle/index.tsx (1)

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

Use type-only imports.

  • web/packages/common/src/components/AccessibleTitle/index.tsx#L4-L4: move FC and PropsWithChildren to import type.
  • web/packages/common/src/components/AccordionSection/index.tsx#L10-L10: move FC, PropsWithChildren, and ReactNode to import type.
🤖 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/common/src/components/AccessibleTitle/index.tsx` at line 4,
Convert FC and PropsWithChildren to type-only imports in AccessibleTitle, and
convert FC, PropsWithChildren, and ReactNode to type-only imports in
AccordionSection; leave runtime React imports unchanged.

Source: Coding guidelines

web/packages/common/src/components/ExpandableMessage/index.tsx (1)

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

Use type-only imports for type-only symbols.

  • Mark the listed type-only symbols as type.
  • In FileUpload/index.tsx, also mark FC, MouseEvent, MouseEventHandler, ReactNode, DropEvent, DropzoneOptions, and FileRejection as type-only.
  • Keep runtime imports such as FileTag, ErrorCode, React, and useDropzone as value imports.
🤖 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/common/src/components/ExpandableMessage/index.tsx` at line 5,
Update imports at
web/packages/common/src/components/ExpandableMessage/index.tsx:5-5,
web/packages/common/src/components/FileTag/index.tsx:4-6,
web/packages/common/src/components/FileUpload/index.tsx:4-4,
web/packages/common/src/components/FileUpload/util.ts:4-4,
web/packages/common/src/components/InputErrorText/index.tsx:5-5, and
web/packages/common/src/components/QuickActionsMenu/QuickActionsMenuRoot/index.tsx:15-15
to mark all type-only symbols with the type modifier. In FileUpload/index.tsx,
apply this to FC, MouseEvent, MouseEventHandler, ReactNode, DropEvent,
DropzoneOptions, and FileRejection, while retaining FileTag, ErrorCode, React,
and useDropzone as value imports.

Source: Coding guidelines

web/packages/studio/src/components/CustomizationFileTag/index.tsx (1)

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

Use explicit type-only imports.

  • web/packages/studio/src/components/CustomizationFileTag/index.tsx#L4-L4: keep FileTag as a value import and import FileTagProps with import type.
  • web/packages/studio/src/components/CustomizationFileUpload/index.tsx#L4-L4: change the RenderFileTagFn import to import type.

As per coding guidelines, use import type for type-only imports.

🤖 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/CustomizationFileTag/index.tsx` at line 4,
Update the import in
web/packages/studio/src/components/CustomizationFileTag/index.tsx:4 so FileTag
remains a value import while FileTagProps uses import type; update the
RenderFileTagFn import in
web/packages/studio/src/components/CustomizationFileUpload/index.tsx:4 to use
import type.

Source: Coding guidelines

web/packages/studio/src/components/DatasetFileUpload/index.tsx (1)

4-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mark type-only imports with import type.

FileTagStatus and RenderFileTagFn are type exports. Split them into import type declarations.

As per coding guidelines, use import type for type-only imports.

🤖 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/DatasetFileUpload/index.tsx` around lines
4 - 5, Update the imports in the DatasetFileUpload module so the type-only
symbols FileTagStatus and RenderFileTagFn use separate import type declarations,
while retaining FileTag and FileUpload as regular runtime imports.

Source: Coding guidelines

web/packages/studio/src/util/logVersion.ts (1)

7-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Declare the public return type.

Add the explicit return type to the exported function:

-export const logVersion = async () => {
+export const logVersion = async (): Promise<void> => {

As per coding guidelines, public APIs should declare explicit return types.

🤖 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/logVersion.ts` around lines 7 - 11, Update the
exported logVersion function to declare its explicit Promise-based return type,
matching its async implementation and existing behavior.

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 `@plugins/example-plugin/web/AGENTS.md`:
- Around line 38-41: Add host.breadcrumbs to the injected host capability list
near the existing navigation entry, keeping it consistent with the capability
contract defined in SharedUiPage.tsx.

In `@plugins/example-plugin/web/src/SharedUiPage.tsx`:
- Line 13: Update the import of pluginPath in SharedUiPage.tsx to use the
project’s configured absolute alias instead of the relative "./paths" path,
while preserving the same imported symbol.
- Around line 26-34: Update the breadcrumb effect in SharedUiPage to return a
cleanup function that clears the page trail through setBreadcrumbs when the page
unmounts. Preserve the existing breadcrumb setup on mount and ensure cleanup
also runs when its dependencies change.

In `@web/packages/common/src/api/common/utils.ts`:
- Around line 4-8: Update the import of GenericSortField, PaginationData, and
ValidationError to use a type-only import, since these SDK symbols are
referenced only in type positions.
- Around line 99-105: Update the request-context formatting in the error
handling logic around error.config so user-visible messages never include raw
URLs with query parameters or fragments. Sanitize url by removing its query
string and fragment before appending it to parts, while preserving the existing
method and URL context when available.
- Around line 37-43: Update the item validation predicate in the API error
utility to require that item.loc is an array before accepting the object.
Preserve the existing msg and type checks so downstream filtering can safely
call filter on loc.

In `@web/packages/common/src/components/ExpandableMessage/index.tsx`:
- Around line 55-58: The fixed danger styling is currently overwritten by caller
className props. In
web/packages/common/src/components/ExpandableMessage/index.tsx#L55-L58, update
the Text className handling to merge attributes.Text.className while always
retaining text-feedback-danger; apply the same merge in
web/packages/common/src/components/InputErrorText/index.tsx#L18-L18 for
props.className.

In `@web/packages/studio/src/components/DataDesignerJobActionsMenu/index.tsx`:
- Around line 4-7: Replace the deep internal `@nemo/common/src/`... imports with
public `@nemo/common` barrel imports: in
web/packages/studio/src/components/DataDesignerJobActionsMenu/index.tsx (lines
4-7), import QuickActionsMenuRoot and QuickActionItem; in
web/packages/studio/src/components/DatasetFileUpload/index.tsx (lines 4-5),
import FileTag and FileUpload; in
web/packages/studio/src/routes/InferenceProvidersListRoute/index.tsx (line 13)
and web/packages/studio/src/routes/IntakeLayout/index.tsx (line 4), import
AccessibleTitle; and in web/packages/studio/src/routes/JobDetailRoute/index.tsx
(lines 4-5), import AccessibleTitle and CancelJobButton. Ensure none of these
migrated shared UI imports use `@nemo/common/src/` paths.

In `@web/packages/studio/src/components/promoted/ErrorPanel.test.tsx`:
- Around line 4-5: Update the import containing ErrorPanelProps to use a
type-only import while keeping the runtime ErrorPanel import unchanged.

In
`@web/packages/studio/src/components/PromptTuningForm/InContextLearningSection/index.tsx`:
- Line 5: Update the shared UI imports to use the public `@nemo/common` entry
point: in
web/packages/studio/src/components/PromptTuningForm/InContextLearningSection/index.tsx:5,
web/packages/studio/src/routes/agents/AgentSuggestionsRoute/index.tsx:4, and
web/packages/studio/src/routes/agents/AgentsListRoute/index.tsx:4, import
AccordionSection or AccessibleTitle from `@nemo/common` instead of deep-linking
into src. Export either component through web/packages/common/src/plugin.ts if
the barrel does not already expose it.

In
`@web/packages/studio/src/components/PromptTuningForm/InferenceParametersSection/index.tsx`:
- Line 4: Update Studio’s module resolver and TypeScript path mapping to resolve
shared UI through the curated `@nemo/common` entry point exported by plugin.ts,
then replace the seven deep imports in
web/packages/studio/src/components/PromptTuningForm/InferenceParametersSection/index.tsx
(anchor), PromptTemplateSection/index.tsx, ToolsSection/index.tsx,
QuickActionsMenu/QuickActionsMenuDefault/index.tsx,
routes/agents/CopilotChatRoute/historyPanel/HistoryPanelContents.tsx,
routes/agents/CopilotChatRoute/index.tsx, and
routes/evaluation/EvaluationLayout/index.tsx with imports from that entry point.

In `@web/packages/studio/src/plugins/PluginRenderer.tsx`:
- Around line 56-57: Update the cleanup useEffect in PluginRenderer to include
pluginName in its dependency array so setBreadcrumbs([]) runs when the routed
plugin changes, then add a test covering a retained PluginRenderer switching
pluginName and clearing the previous breadcrumbs.

In `@web/packages/studio/src/routes/optimizer/OptimizerRoute/index.tsx`:
- Around line 5-10: Replace all listed deep shared-UI imports with the bare
`@nemo/common` barrel, and add any missing symbols to plugin.ts exports:
web/packages/studio/src/routes/optimizer/OptimizerRoute/index.tsx (lines 5-10)
for AccessibleTitle, StudioDataView, and ErrorPanel;
web/packages/studio/src/routes/optimizer/OptimizerInsightRoute/index.tsx (lines
4-6) for AccessibleTitle, ErrorMessage, and ExpandableMessage;
web/packages/studio/src/routes/index.tsx (line 5) for ErrorPanel;
web/packages/studio/src/routes/guardrails/GuardrailDetailRoute/index.tsx (line
6) for AccessibleTitle;
web/packages/studio/src/routes/guardrails/GuardrailDetailRoute/GuardrailDetailActions.tsx
(lines 4-8) for DeleteConfirmationModal and QuickActionsMenuRoot;
web/packages/studio/src/components/promoted/DeleteConfirmationModal.test.tsx
(line 4) for DeleteConfirmationModal; and
web/packages/studio/src/components/promoted/CancelJobButton.test.tsx (line 4)
for CancelJobButton.

---

Nitpick comments:
In `@web/packages/common/src/components/AccessibleTitle/index.tsx`:
- Line 4: Convert FC and PropsWithChildren to type-only imports in
AccessibleTitle, and convert FC, PropsWithChildren, and ReactNode to type-only
imports in AccordionSection; leave runtime React imports unchanged.

In `@web/packages/common/src/components/ExpandableMessage/index.tsx`:
- Line 5: Update imports at
web/packages/common/src/components/ExpandableMessage/index.tsx:5-5,
web/packages/common/src/components/FileTag/index.tsx:4-6,
web/packages/common/src/components/FileUpload/index.tsx:4-4,
web/packages/common/src/components/FileUpload/util.ts:4-4,
web/packages/common/src/components/InputErrorText/index.tsx:5-5, and
web/packages/common/src/components/QuickActionsMenu/QuickActionsMenuRoot/index.tsx:15-15
to mark all type-only symbols with the type modifier. In FileUpload/index.tsx,
apply this to FC, MouseEvent, MouseEventHandler, ReactNode, DropEvent,
DropzoneOptions, and FileRejection, while retaining FileTag, ErrorCode, React,
and useDropzone as value imports.

In `@web/packages/studio/src/components/CustomizationFileTag/index.tsx`:
- Line 4: Update the import in
web/packages/studio/src/components/CustomizationFileTag/index.tsx:4 so FileTag
remains a value import while FileTagProps uses import type; update the
RenderFileTagFn import in
web/packages/studio/src/components/CustomizationFileUpload/index.tsx:4 to use
import type.

In `@web/packages/studio/src/components/DatasetFileUpload/index.tsx`:
- Around line 4-5: Update the imports in the DatasetFileUpload module so the
type-only symbols FileTagStatus and RenderFileTagFn use separate import type
declarations, while retaining FileTag and FileUpload as regular runtime imports.

In `@web/packages/studio/src/util/logVersion.ts`:
- Around line 7-11: Update the exported logVersion function to declare its
explicit Promise-based return type, matching its async implementation and
existing behavior.
🪄 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: bb6b888f-fa73-4f91-99cc-42e77e521843

📥 Commits

Reviewing files that changed from the base of the PR and between 25ab603 and eb5737f.

⛔ Files ignored due to path filters (2)
  • plugins/example-plugin/src/nemo_example_plugin/web/dist/index.js is excluded by !**/dist/**
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (214)
  • plugins/example-plugin/web/AGENTS.md
  • plugins/example-plugin/web/src/SharedUiPage.tsx
  • plugins/example-plugin/web/src/types.ts
  • web/packages/common/package.json
  • web/packages/common/src/api/common/utils.test.ts
  • web/packages/common/src/api/common/utils.ts
  • web/packages/common/src/components/AccessibleTitle/index.test.tsx
  • web/packages/common/src/components/AccessibleTitle/index.tsx
  • web/packages/common/src/components/AccordionSection/index.tsx
  • web/packages/common/src/components/CancelJobButton/index.tsx
  • web/packages/common/src/components/ConfirmationModal/index.tsx
  • web/packages/common/src/components/DeleteConfirmationModal/index.tsx
  • web/packages/common/src/components/ErrorPanel/index.tsx
  • web/packages/common/src/components/ExpandableMessage/index.test.tsx
  • web/packages/common/src/components/ExpandableMessage/index.tsx
  • web/packages/common/src/components/FileTag/index.tsx
  • web/packages/common/src/components/FileUpload/index.tsx
  • web/packages/common/src/components/FileUpload/util.ts
  • web/packages/common/src/components/InputErrorText/index.tsx
  • web/packages/common/src/components/QuickActionsMenu/QuickActionsMenuRoot/index.test.tsx
  • web/packages/common/src/components/QuickActionsMenu/QuickActionsMenuRoot/index.tsx
  • web/packages/common/src/plugin.ts
  • web/packages/common/src/utils/error.ts
  • web/packages/common/src/utils/forms/error.test.ts
  • web/packages/common/src/utils/forms/error.ts
  • web/packages/common/src/utils/logger.ts
  • web/packages/studio/src/App.tsx
  • web/packages/studio/src/api/datasets/useDatasetFileContent.ts
  • web/packages/studio/src/api/guardrail-checks/guardrailChecks.ts
  • web/packages/studio/src/components/AnonymizerJobActionsMenu/index.tsx
  • web/packages/studio/src/components/BulkDeleteModal/index.tsx
  • web/packages/studio/src/components/CreateFilesetStart/useDescribeWithAi.ts
  • web/packages/studio/src/components/CustomizationFileTag/index.tsx
  • web/packages/studio/src/components/CustomizationFileUpload/index.tsx
  • web/packages/studio/src/components/CustomizationFilesetCreateModal/index.tsx
  • web/packages/studio/src/components/DataDesignerJobActionsMenu/index.tsx
  • web/packages/studio/src/components/DatasetCreateModal/index.tsx
  • web/packages/studio/src/components/DatasetFileUpload/index.tsx
  • web/packages/studio/src/components/DatasetInputFile/index.tsx
  • web/packages/studio/src/components/DatasetsTable/index.test.tsx
  • web/packages/studio/src/components/DatasetsTable/index.tsx
  • web/packages/studio/src/components/ExperimentCreateModal/index.tsx
  • web/packages/studio/src/components/FilesTable/CreateFileSplitsModal/index.tsx
  • web/packages/studio/src/components/FilesTable/DirectoryQuickActions/index.tsx
  • web/packages/studio/src/components/FilesTable/FileQuickActions/index.tsx
  • web/packages/studio/src/components/FilesTable/RenameFileModal/index.tsx
  • web/packages/studio/src/components/FilesTable/TransformFileModal/index.tsx
  • web/packages/studio/src/components/FilesetActionMenu/index.tsx
  • web/packages/studio/src/components/FilesetCreateModal/index.tsx
  • web/packages/studio/src/components/FilesetFilePreviewPanel/components/FileActions/index.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/AnnotationsPanel.tsx
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/useSpanAnnotationActions.ts
  • web/packages/studio/src/components/IntakeDetail/SessionDetailView.tsx
  • web/packages/studio/src/components/IntakeDetail/TraceSpanAccordions.tsx
  • web/packages/studio/src/components/IntakeLists/IntakeSpansTable.tsx
  • web/packages/studio/src/components/IntakeLists/IntakeTracesTable.tsx
  • web/packages/studio/src/components/ModelActionsMenu/index.tsx
  • web/packages/studio/src/components/ModelChat/index.tsx
  • web/packages/studio/src/components/ModelComparePrompts/useModelComparePrompts.ts
  • web/packages/studio/src/components/NewCustomizationForm/index.tsx
  • web/packages/studio/src/components/NewDataDesignerJobForm/JobRequestGenerator.tsx
  • web/packages/studio/src/components/NewDataDesignerJobForm/usePreview.ts
  • web/packages/studio/src/components/NewDataDesignerJobForm/utils.test.ts
  • web/packages/studio/src/components/NewDataDesignerJobForm/utils.ts
  • web/packages/studio/src/components/PromptTuningForm/ImportFromDatasetModal/index.tsx
  • web/packages/studio/src/components/PromptTuningForm/InContextLearningSection/index.tsx
  • web/packages/studio/src/components/PromptTuningForm/InferenceParametersSection/index.tsx
  • web/packages/studio/src/components/PromptTuningForm/PromptTemplateSection/index.tsx
  • web/packages/studio/src/components/PromptTuningForm/ToolsSection/index.tsx
  • web/packages/studio/src/components/QuickActionsMenu/QuickActionsMenuDefault/index.tsx
  • web/packages/studio/src/components/WorkspaceCreateModal/index.tsx
  • web/packages/studio/src/components/WorkspaceDropdown/index.tsx
  • web/packages/studio/src/components/common/SearchBar/index.tsx
  • web/packages/studio/src/components/dataViews/AgentEvaluationsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/AgentsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/CustomModelsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/DeploymentsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/ExperimentDataView/index.tsx
  • web/packages/studio/src/components/dataViews/GuardrailsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/InferenceProvidersDataView/index.tsx
  • web/packages/studio/src/components/dataViews/JobsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/SafeSynthesizerJobsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/SecretsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/VirtualModelsDataView/index.tsx
  • web/packages/studio/src/components/evaluation/Configurations/form/InputFile/useInputFile.ts
  • web/packages/studio/src/components/evaluation/Jobs/ActionMenu.tsx
  • web/packages/studio/src/components/evaluation/Jobs/DetailsPanel.tsx
  • web/packages/studio/src/components/evaluation/Jobs/EvaluationJobBulkDeleteModal.tsx
  • web/packages/studio/src/components/evaluation/Jobs/form/ScoreDefinitions.tsx
  • web/packages/studio/src/components/filesets/AddToFolderModal/index.tsx
  • web/packages/studio/src/components/filesets/FilesetFileExplorer/DatasetFileDropzone/index.tsx
  • web/packages/studio/src/components/filesets/FilesetFileExplorer/NewDirectoryModal/index.tsx
  • web/packages/studio/src/components/filesets/hooks/useBulkDownload.ts
  • web/packages/studio/src/components/filesets/hooks/useBulkDuplicate.ts
  • web/packages/studio/src/components/promoted/CancelJobButton.test.tsx
  • web/packages/studio/src/components/promoted/DeleteConfirmationModal.test.tsx
  • web/packages/studio/src/components/promoted/ErrorPanel.test.tsx
  • web/packages/studio/src/components/sidePanels/MetricRunSidePanel/index.tsx
  • web/packages/studio/src/components/sidePanels/ModelPanels/ModelPanel/components.tsx
  • web/packages/studio/src/components/sidePanels/ModelPanels/ModelPanel/index.tsx
  • web/packages/studio/src/main.tsx
  • web/packages/studio/src/plugins/PluginErrorBoundary.tsx
  • web/packages/studio/src/plugins/PluginRenderer.test.tsx
  • web/packages/studio/src/plugins/PluginRenderer.tsx
  • web/packages/studio/src/plugins/types.ts
  • web/packages/studio/src/plugins/utils.ts
  • web/packages/studio/src/routes/AnonymizerBuilderRoute/components/AnonymizerBuilderForm.tsx
  • web/packages/studio/src/routes/AnonymizerBuilderRoute/index.tsx
  • web/packages/studio/src/routes/AnonymizerJobDetailRoute/index.tsx
  • web/packages/studio/src/routes/AnonymizerListRoute/index.tsx
  • web/packages/studio/src/routes/AuthSuccessRoute/index.tsx
  • web/packages/studio/src/routes/CustomizationJobDetailsRoute/DetailActions.tsx
  • web/packages/studio/src/routes/CustomizationJobDetailsRoute/index.tsx
  • web/packages/studio/src/routes/CustomizationJobListRoute/index.tsx
  • web/packages/studio/src/routes/DashboardLandingRoute/index.tsx
  • web/packages/studio/src/routes/DataDesignerJobBuildRoute/index.tsx
  • web/packages/studio/src/routes/DataDesignerJobDetailsRoute/index.tsx
  • web/packages/studio/src/routes/DataDesignerJobListRoute/index.tsx
  • web/packages/studio/src/routes/DeploymentsListRoute/CreateDeploymentSidePanel/useCreateDeploymentBySource.ts
  • web/packages/studio/src/routes/DeploymentsListRoute/index.tsx
  • web/packages/studio/src/routes/DeploymentsListRoute/useDeleteDeploymentAndConfig.ts
  • web/packages/studio/src/routes/EvaluationDetailRoute/index.tsx
  • web/packages/studio/src/routes/EvaluationSessionDetailRoute/SessionCompareColumn.tsx
  • web/packages/studio/src/routes/EvaluationSessionDetailRoute/TestCaseCompare.tsx
  • web/packages/studio/src/routes/ExperimentDetailRoute/index.tsx
  • web/packages/studio/src/routes/ExperimentRoute/index.tsx
  • web/packages/studio/src/routes/FilesetDetailRoute/index.tsx
  • web/packages/studio/src/routes/FilesetListRoute/ActionMenu/index.test.tsx
  • web/packages/studio/src/routes/FilesetListRoute/ActionMenu/index.tsx
  • web/packages/studio/src/routes/FilesetListRoute/index.tsx
  • web/packages/studio/src/routes/FilesetNewRoute/helpers.ts
  • web/packages/studio/src/routes/FilesetNewRoute/index.tsx
  • web/packages/studio/src/routes/FilesetNewRoute/useCreateFileset.ts
  • web/packages/studio/src/routes/InferenceProvidersListRoute/CreateInferenceProviderSidePanel/index.tsx
  • web/packages/studio/src/routes/InferenceProvidersListRoute/index.tsx
  • web/packages/studio/src/routes/IntakeLayout/index.tsx
  • web/packages/studio/src/routes/JobDetailRoute/index.tsx
  • web/packages/studio/src/routes/JobsRoute/index.tsx
  • web/packages/studio/src/routes/LegacyNewDataDesignerJobRoute/index.tsx
  • web/packages/studio/src/routes/NewDataDesignerJobRoute/index.tsx
  • web/packages/studio/src/routes/PromptTuningFormRoute/index.tsx
  • web/packages/studio/src/routes/SafeSynthesizerJobDetailsRoute/index.tsx
  • web/packages/studio/src/routes/SafeSynthesizerJobReportRoute/index.tsx
  • web/packages/studio/src/routes/SafeSynthesizerListRoute/index.tsx
  • web/packages/studio/src/routes/SafeSynthesizerNewRoute/index.test.tsx
  • web/packages/studio/src/routes/SafeSynthesizerNewRoute/index.tsx
  • web/packages/studio/src/routes/SecretsListRoute/CreateSecretModal/index.tsx
  • web/packages/studio/src/routes/SecretsListRoute/EditSecretModal/index.tsx
  • web/packages/studio/src/routes/SecretsListRoute/index.tsx
  • web/packages/studio/src/routes/VirtualModelsListRoute/index.tsx
  • web/packages/studio/src/routes/WorkspaceBaseModelsRoute/index.tsx
  • web/packages/studio/src/routes/WorkspaceDashboardRoute/index.tsx
  • web/packages/studio/src/routes/WorkspaceLayout/WorkspaceSideNav.tsx
  • web/packages/studio/src/routes/WorkspaceMembersRoute/WorkspaceMemberModal.tsx
  • web/packages/studio/src/routes/WorkspaceMembersRoute/index.tsx
  • web/packages/studio/src/routes/WorkspaceSettingsRoute/DeleteWorkspaceModal/index.tsx
  • web/packages/studio/src/routes/WorkspaceSettingsRoute/EditDescriptionModal/index.tsx
  • web/packages/studio/src/routes/WorkspaceSettingsRoute/index.tsx
  • web/packages/studio/src/routes/agents/AgentDetailRoute/DeploymentLogsView.tsx
  • web/packages/studio/src/routes/agents/AgentDetailRoute/index.tsx
  • web/packages/studio/src/routes/agents/AgentEvaluationsRoute/AgentEvaluationDetailRoute.tsx
  • web/packages/studio/src/routes/agents/AgentEvaluationsRoute/AgentEvaluationsListRoute.tsx
  • web/packages/studio/src/routes/agents/AgentMonitorRoute/index.tsx
  • web/packages/studio/src/routes/agents/AgentSuggestionsRoute/api.ts
  • web/packages/studio/src/routes/agents/AgentSuggestionsRoute/index.tsx
  • web/packages/studio/src/routes/agents/AgentSuggestionsRoute/useOptimizerSuggestions.ts
  • web/packages/studio/src/routes/agents/AgentSuggestionsRoute/utils.ts
  • web/packages/studio/src/routes/agents/AgentsListRoute/CloneAgentModal/index.tsx
  • web/packages/studio/src/routes/agents/AgentsListRoute/CreateExampleAgentModal/index.tsx
  • web/packages/studio/src/routes/agents/AgentsListRoute/index.tsx
  • web/packages/studio/src/routes/agents/CopilotChatRoute/ChatThreadErrorBoundary.tsx
  • web/packages/studio/src/routes/agents/CopilotChatRoute/historyPanel/HistoryPanelContents.tsx
  • web/packages/studio/src/routes/agents/CopilotChatRoute/index.tsx
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.test.ts
  • web/packages/studio/src/routes/agents/CopilotChatRoute/stream.ts
  • web/packages/studio/src/routes/evaluation/EvaluationLayout/index.tsx
  • web/packages/studio/src/routes/evaluation/EvaluationResultDetailsRoute/index.tsx
  • web/packages/studio/src/routes/evaluation/EvaluationResultsLayout/index.tsx
  • web/packages/studio/src/routes/groups/agentRoutes.tsx
  • web/packages/studio/src/routes/groups/anonymizerRoutes.tsx
  • web/packages/studio/src/routes/groups/customizationRoutes.tsx
  • web/packages/studio/src/routes/groups/dashboardRoutes.tsx
  • web/packages/studio/src/routes/groups/dataDesignerRoutes.tsx
  • web/packages/studio/src/routes/groups/deploymentRoutes.tsx
  • web/packages/studio/src/routes/groups/evaluationRoutes.tsx
  • web/packages/studio/src/routes/groups/experimentRoutes.tsx
  • web/packages/studio/src/routes/groups/filesetRoutes.tsx
  • web/packages/studio/src/routes/groups/guardrailsRoutes.tsx
  • web/packages/studio/src/routes/groups/inferenceProviderRoutes.tsx
  • web/packages/studio/src/routes/groups/intakeRoutes.tsx
  • web/packages/studio/src/routes/groups/jobRoutes.tsx
  • web/packages/studio/src/routes/groups/memberRoutes.tsx
  • web/packages/studio/src/routes/groups/modelCompareRoutes.tsx
  • web/packages/studio/src/routes/groups/optimizerRoutes.tsx
  • web/packages/studio/src/routes/groups/safeSynthesizerRoutes.tsx
  • web/packages/studio/src/routes/groups/secretsRoutes.tsx
  • web/packages/studio/src/routes/groups/settingsRoutes.tsx
  • web/packages/studio/src/routes/groups/virtualModelsRoutes.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailChecksTab/GuardrailTestCard.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailChecksTab/GuardrailTestCasesEditor.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailDetailRoute/GuardrailDetailActions.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailDetailRoute/index.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/index.tsx
  • web/packages/studio/src/routes/index.tsx
  • web/packages/studio/src/routes/optimizer/InsightTracesTable/index.tsx
  • web/packages/studio/src/routes/optimizer/OptimizerInsightRoute/index.tsx
  • web/packages/studio/src/routes/optimizer/OptimizerRoute/index.tsx
  • web/packages/studio/src/util/files.ts
  • web/packages/studio/src/util/llm.ts
  • web/packages/studio/src/util/logVersion.ts
  • web/packages/studio/src/util/logger.test.ts
  • web/packages/studio/src/util/strings.ts
  • web/packages/studio/src/workers/LargeFileWorker.ts
💤 Files with no reviewable changes (1)
  • web/packages/studio/src/components/NewDataDesignerJobForm/utils.ts
🛑 Comments failed to post (4)
web/packages/common/src/api/common/utils.ts (3)

4-8: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use a type-only import.

These SDK symbols are used only as types. Use import type for this import.

🤖 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/common/src/api/common/utils.ts` around lines 4 - 8, Update the
import of GenericSortField, PaginationData, and ValidationError to use a
type-only import, since these SDK symbols are referenced only in type positions.

Source: Coding guidelines


37-43: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate loc as an array.

The guard accepts loc: null or another non-array value. Line 76 then calls filter and throws while handling an API error. Require an array before returning true.

Proposed fix
         'type' in item &&
-        'loc' in item
+        'loc' in item &&
+        Array.isArray(item.loc) &&
+        item.loc.every((part) => typeof part === 'string' || typeof part === 'number')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      (item) =>
        typeof item === 'object' &&
        item !== null &&
        'msg' in item &&
        typeof item.msg === 'string' &&
        'type' in item &&
        'loc' in item &&
        Array.isArray(item.loc) &&
        item.loc.every((part) => typeof part === 'string' || typeof part === 'number')
🤖 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/common/src/api/common/utils.ts` around lines 37 - 43, Update the
item validation predicate in the API error utility to require that item.loc is
an array before accepting the object. Preserve the existing msg and type checks
so downstream filtering can safely call filter on loc.

99-105: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not return raw request URLs.

Line 104 can expose query parameters in a user-visible error message. Query parameters can contain identifiers or credentials. Omit the URL, or remove its query string and fragment before returning the message.

🤖 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/common/src/api/common/utils.ts` around lines 99 - 105, Update
the request-context formatting in the error handling logic around error.config
so user-visible messages never include raw URLs with query parameters or
fragments. Sanitize url by removing its query string and fragment before
appending it to parts, while preserving the existing method and URL context when
available.
web/packages/common/src/components/ExpandableMessage/index.tsx (1)

55-58: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve required error styling.

Later prop spreads replace the fixed danger class. A caller can remove text-feedback-danger.

  • web/packages/common/src/components/ExpandableMessage/index.tsx#L55-L58: Merge attributes.Text.className and keep text-feedback-danger.
  • web/packages/common/src/components/InputErrorText/index.tsx#L18-L18: Merge props.className and keep text-feedback-danger.
📍 Affects 2 files
  • web/packages/common/src/components/ExpandableMessage/index.tsx#L55-L58 (this comment)
  • web/packages/common/src/components/InputErrorText/index.tsx#L18-L18
🤖 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/common/src/components/ExpandableMessage/index.tsx` around lines
55 - 58, The fixed danger styling is currently overwritten by caller className
props. In
web/packages/common/src/components/ExpandableMessage/index.tsx#L55-L58, update
the Text className handling to merge attributes.Text.className while always
retaining text-feedback-danger; apply the same merge in
web/packages/common/src/components/InputErrorText/index.tsx#L18-L18 for
props.className.

marcusds added a commit that referenced this pull request Aug 7, 2026
Review on #1192 caught two gaps in the breadcrumbs wiring.

PluginRenderer cleared the trail only on unmount, but the router reuses
the component across a :pluginName change, so the outgoing plugin's
breadcrumbs stayed visible until the incoming one set its own. Key the
cleanup on pluginName. The new test fails without that dep.

SharedUiPage set a trail and never cleared it. Studio only clears when
the whole plugin unmounts, so navigating between pages inside a plugin
left the previous page's crumb behind. The example is the template other
plugins copy, and AGENTS.md told authors not to hand-roll cleanup — true
for plugin unmount, wrong for page unmount. Fixed both, and listed
breadcrumbs in the host capability enumeration it was missing from.

Signed-off-by: mschwab <mschwab@nvidia.com>
@marcusds

marcusds commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

/nvskills-ci

@koralchapnik

Copy link
Copy Markdown

Moved the Iron Swarm UI onto this branch for #1037 — the barrel made it straightforward, thanks :)
Two gaps surfaced once it ran in a browser, both plugin-API rather than Iron Swarm:

ToastProvider doesn't cross the boundary. ConfirmationModal, DeleteConfirmationModal and LogViewer are plugin API but call useToast internally. Studio mounts the provider by deep import (RootLayout/index.tsx:25) while a plugin gets the vendor/common.js copy, so the contexts differ and rendering any of them throws useToast must be used within a ToastProvider. Mounting the provider from the shared copy, or giving those components an optional onNotify that can point at host.notifications, would both close it. Iron Swarm carries a local copy of the modals meanwhile.

Plugin nav groups don't merge with core ones. navItems() returning group: 'Safety' renders a second "Safety" header beneath Studio's rather than joining it.

Flagging both since they'll affect any plugin that follows.

@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: 1

🧹 Nitpick comments (3)
web/packages/common/src/providers/toast/useNotify.ts (1)

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

Use import type for type-only imports.

  • web/packages/common/src/providers/toast/useNotify.ts#L4-L4: Change NotifyFn to a type-only import.
  • web/packages/common/src/providers/toast/useNotify.test.tsx#L5-L10: Change MessageFnOptions, NotifyFn, and FC to type-only imports.
  • web/packages/common/src/components/ConfirmationModal/index.tsx#L7-L7: Change NotifyFn to a type-only import.
  • web/packages/common/src/components/DeleteConfirmationModal/index.tsx#L6-L6: Change NotifyFn to a type-only import.
  • web/packages/common/src/components/LogViewer/index.tsx#L5-L5: Change NotifyFn to a type-only import.

As per coding guidelines, “Use import type for type-only imports.”

🤖 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/common/src/providers/toast/useNotify.ts` at line 4, Convert the
type-only imports to use import type in useNotify.ts (NotifyFn),
useNotify.test.tsx (MessageFnOptions, NotifyFn, and FC),
ConfirmationModal/index.tsx (NotifyFn), DeleteConfirmationModal/index.tsx
(NotifyFn), and LogViewer/index.tsx (NotifyFn); preserve any runtime imports
separately where needed.

Source: Coding guidelines

web/packages/common/src/providers/toast/useNotify.test.tsx (1)

12-18: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Declare NotifierProps.

Notifier uses an inline props shape. Define an explicit props interface.

As per coding guidelines, “Define explicit props interfaces for all React components.”

🤖 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/common/src/providers/toast/useNotify.test.tsx` around lines 12 -
18, Define a named NotifierProps interface for the onNotify and options props,
then update the Notifier component to use that interface instead of the inline
props shape. Preserve the existing optional types and notification behavior.

Source: Coding guidelines

plugins/example-plugin/web/AGENTS.md (1)

88-117: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Split this mixed documentation page.

This page combines explanation, how-to steps, and contract reference. Move this notification guidance to a cross-linked reference or how-to page.

As per coding guidelines, “Each documentation page should fit ONE Diataxis quadrant.”

🤖 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 `@plugins/example-plugin/web/AGENTS.md` around lines 88 - 117, Split the mixed
AGENTS.md content so the notification explanation and usage example move to an
appropriate cross-linked how-to or reference page, while keeping the contract
reference in its own documentation page. Update links between the pages and
ensure each page follows a single Diataxis quadrant.

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/studio/src/routes/WorkspaceLayout/WorkspaceSideNav.tsx`:
- Around line 337-350: Update the plugin navigation items before the merge in
mergedItems so every plugin item.id is prefixed with its plugin name, while
preserving group matching and item order. Use the plugin identity available in
pluginNavGroups, ensure nested plugin navigation IDs are handled consistently if
applicable, and add a regression test proving plugin IDs cannot collide with
core NavigationDrawer keys.

---

Nitpick comments:
In `@plugins/example-plugin/web/AGENTS.md`:
- Around line 88-117: Split the mixed AGENTS.md content so the notification
explanation and usage example move to an appropriate cross-linked how-to or
reference page, while keeping the contract reference in its own documentation
page. Update links between the pages and ensure each page follows a single
Diataxis quadrant.

In `@web/packages/common/src/providers/toast/useNotify.test.tsx`:
- Around line 12-18: Define a named NotifierProps interface for the onNotify and
options props, then update the Notifier component to use that interface instead
of the inline props shape. Preserve the existing optional types and notification
behavior.

In `@web/packages/common/src/providers/toast/useNotify.ts`:
- Line 4: Convert the type-only imports to use import type in useNotify.ts
(NotifyFn), useNotify.test.tsx (MessageFnOptions, NotifyFn, and FC),
ConfirmationModal/index.tsx (NotifyFn), DeleteConfirmationModal/index.tsx
(NotifyFn), and LogViewer/index.tsx (NotifyFn); preserve any runtime imports
separately where needed.
🪄 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: 58cd014a-5c71-4c51-8b72-911451721d2f

📥 Commits

Reviewing files that changed from the base of the PR and between ab4ff73 and 1e73baf.

📒 Files selected for processing (13)
  • plugins/example-plugin/web/AGENTS.md
  • plugins/example-plugin/web/src/types.ts
  • web/packages/common/src/components/ConfirmationModal/index.tsx
  • web/packages/common/src/components/DeleteConfirmationModal/index.tsx
  • web/packages/common/src/components/LogViewer/index.tsx
  • web/packages/common/src/plugin.ts
  • web/packages/common/src/providers/toast/types.ts
  • web/packages/common/src/providers/toast/useNotify.test.tsx
  • web/packages/common/src/providers/toast/useNotify.ts
  • web/packages/studio/src/plugins/PluginRenderer.tsx
  • web/packages/studio/src/plugins/types.ts
  • web/packages/studio/src/routes/WorkspaceLayout/WorkspaceSideNav.test.tsx
  • web/packages/studio/src/routes/WorkspaceLayout/WorkspaceSideNav.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/packages/studio/src/plugins/PluginRenderer.tsx
  • web/packages/common/src/plugin.ts

Comment thread web/packages/studio/src/routes/WorkspaceLayout/WorkspaceSideNav.tsx
@coderabbitai coderabbitai Bot mentioned this pull request Aug 10, 2026
15 tasks
Plugin bundles reach Studio's shared UI through the curated barrel in
common/src/plugin.ts, but seven of the components Iron Swarm needs lived
in web/packages/studio and were therefore unreachable. Move them into
@nemo/common and export them, so the next plugin gets them for free
rather than reimplementing a table, an accordion, or a file picker.

Moved with git mv so history follows: AccessibleTitle, AccordionSection,
ExpandableMessage, FileTag, InputErrorText, FileUpload (+util),
QuickActionsMenuRoot, and api/common/utils, along with their tests.
Studio's ~100 importers now point at @nemo/common directly; no shims are
left behind. common gains react-dropzone, which came with FileUpload.

Also adds JOB_POLLING_INTERVAL_MS to the barrel — the one name the audit
of Iron Swarm's usage found missing.

Three candidates were deliberately left out of the barrel, and the
measurement is why. Exporting CreateSecretModal, fetchAgentsForSelect,
and getErrorMessage pulled the generated SDK client into the shared
vendor bundle, taking it from 241 kB to 553 kB and dragging in axios and
oidc-client-ts. That is not just weight: plugins are meant to receive the
SDK on host.sdk precisely so there is one axios instance carrying
Studio's OIDC interceptor, and a second copy in common.js would have
issued unauthenticated requests. The bundle is back to 314 kB with axios,
oidc-client-ts and zod absent; the remainder is react-dropzone, which
FileUpload genuinely needs.

A plugin that wants those three composes them from the primitives the
barrel does export, wired to host.sdk.

Signed-off-by: mschwab <mschwab@nvidia.com>
Studio's breadcrumb bar renders in GlobalNav, which sits in the layout's
navbar grid area while a plugin renders in the content area several route
levels below. A plugin therefore cannot render breadcrumbs itself; it can
only write into the context GlobalNav consumes. That is the same shape as
notifications writing to Studio's shared toaster, so expose it the same
way, on the host handle.

Studio clears the trail when the plugin unmounts rather than trusting each
plugin to clean up, and the setter is a plain function instead of copying
useBreadcrumbs' mount-only semantics — plugin detail routes need to update
the trail as data arrives.

Iron Swarm's routes import useBreadcrumbs directly today; this is what
they move to.

Signed-off-by: mschwab <mschwab@nvidia.com>
… and the logger to @nemo/common

Completes the shared-UI promotion. These four were blocked on Studio's
OTEL logger, which imports constants/environment and pulls in the whole
feature-flag chain, so move the logger too — but sever it from that
config rather than dragging it along. The service name arrives via
configureLogger(), which App.tsx calls at bootstrap; logVersion stays in
Studio because it needs VERSION_SHA.

CancelJobButton read the workspace off the URL via useWorkspaceFromPath.
It now takes it as a prop, which is what let it move and is better
regardless — a component that reads the router is harder to reuse. Both
call sites already had the workspace in scope.

Also relocates getErrorMessage out of NewDataDesignerJobForm/utils. It is
seven dependency-free lines with nothing to do with Data Designer, and
importing it was what dragged that 206-line module — and the logger chain
behind it — into anything that wanted a formatted error string.

Two of the four are deliberately not exported to plugins. CancelJobButton
calls the jobs API through the generated SDK, and ErrorPanel formats
errors through the axios-aware helper; exporting either put axios and
oidc-client-ts back into the shared vendor bundle, which is the same
correctness problem as before — plugins get their SDK on host.sdk so
there is exactly one authenticated client. Both still live in common for
Studio's own use. The bundle lands at 339 kB with axios absent.

Signed-off-by: mschwab <mschwab@nvidia.com>
Review on #1192 caught two gaps in the breadcrumbs wiring.

PluginRenderer cleared the trail only on unmount, but the router reuses
the component across a :pluginName change, so the outgoing plugin's
breadcrumbs stayed visible until the incoming one set its own. Key the
cleanup on pluginName. The new test fails without that dep.

SharedUiPage set a trail and never cleared it. Studio only clears when
the whole plugin unmounts, so navigating between pages inside a plugin
left the previous page's crumb behind. The example is the template other
plugins copy, and AGENTS.md told authors not to hand-roll cleanup — true
for plugin unmount, wrong for page unmount. Fixed both, and listed
breadcrumbs in the host capability enumeration it was missing from.

Signed-off-by: mschwab <mschwab@nvidia.com>
ToastProvider does not cross the plugin boundary. Studio mounts it by deep
import, so it lands in Studio's own module graph, while a plugin resolves the
bare `@nemo/common` specifier to public/vendor/common.js — a second copy with
its own ToastContext. ConfirmationModal, DeleteConfirmationModal and LogViewer
are all plugin API and all called useToast internally, so rendering any of them
from a plugin threw "useToast must be used within a ToastProvider".

Mounting the provider from the shared copy is not reachable: Studio's tsconfig
maps only `@nemo/common/*`, and `@nemo/common` is in VENDOR_IMPORT_MAP but not
VENDOR_EXTERNALS, so Studio never emits a bare import to externalize. Adding it
would split Studio against itself — the provider in vendor, every deep-import
useToast caller still bundled.

Instead the three components take an optional onNotify. A new useNotify hook
resolves the sink: onNotify first, then the surrounding ToastProvider, then a
logger.warn and drop. It reads ToastContext with useContext rather than
useToast, so an absent context is a supported state instead of a throw.

PluginNotifications.notify also gains the toast options argument so durationMs
survives the boundary rather than being silently dropped at it.

Signed-off-by: mschwab <mschwab@nvidia.com>
WorkspaceSideNav concatenated plugin groups onto the core list, so a plugin
whose navItems() returned group: 'Safety' rendered a second "Safety" header
beneath Studio's rather than joining it.

Plugin groups now accumulate by name and fold into the matching core group,
using the existing isGroup guard so ungrouped top-level items are left alone.
Groups matching nothing append in plugin order, and two plugins naming the same
group merge into one.

Signed-off-by: mschwab <mschwab@nvidia.com>
NavigationDrawer keys items by item.id and keys accordion state by it too.
Merging plugin groups into core groups of the same name puts both sets of items
in one array, so a plugin reusing a core id (say 'virtual-models') now produces
duplicate React keys where it previously only collided in accordion state.

Plugin ids are prefixed with the plugin name. Nothing else reads them — active
state matches on href — so the prefix is confined to the two key sites.

Also applies the review's import-type and explicit-props-interface nits on the
lines this branch introduced.

Signed-off-by: mschwab <mschwab@nvidia.com>
LogViewer now resolves its toast sink through useNotify, which imports
ToastContext from the same module the test replaced wholesale. The mock
returned only useToast, so every render in the file threw. The mocked
success fn was never asserted, so the mock can go: with no provider,
useNotify falls back to a logged warning instead of throwing.

Signed-off-by: mschwab <mschwab@nvidia.com>
@marcusds
marcusds force-pushed the promote-studio-ui-to-shared/mschwab branch from db5dcd8 to 441b2f8 Compare August 11, 2026 16:50
@marcusds
marcusds enabled auto-merge August 11, 2026 16:51
@marcusds
marcusds added this pull request to the merge queue Aug 11, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 11, 2026
@marcusds
marcusds added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit c28369c Aug 11, 2026
55 checks passed
@marcusds
marcusds deleted the promote-studio-ui-to-shared/mschwab branch August 11, 2026 17:48
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.

3 participants