Skip to content

UN-3386 [FEAT] Add Prompt Studio HITL change indicator plugin slot#1930

Open
vishnuszipstack wants to merge 3 commits intomainfrom
UN-3386-prompt-studio-hitl-feedback
Open

UN-3386 [FEAT] Add Prompt Studio HITL change indicator plugin slot#1930
vishnuszipstack wants to merge 3 commits intomainfrom
UN-3386-prompt-studio-hitl-feedback

Conversation

@vishnuszipstack
Copy link
Copy Markdown
Contributor

@vishnuszipstack vishnuszipstack commented Apr 27, 2026

What

  • Adds a dynamic-import slot in the Prompt Studio prompt-card Header for a new cloud-only PromptChangeIndicator plugin button.
  • Registers a new route :orgName/review/readonly/:documentId gated on a cloud-only ReadOnlyReviewPage plugin.
  • Both gates fall through silently when the plugin is absent (OSS builds remain untouched).

Why

  • Closes the loop between HITL reviewers and prompt authors: when a reviewer corrects a field in HITL, the prompt author should be able to see that signal back in Prompt Studio.
  • The feature lives in the cloud plugin, but the host (OSS) needs to expose the integration points so the indicator and the read-only audit page can be wired up.

How

  • frontend/src/components/custom-tools/prompt-card/Header.jsx: adds a try/catch dynamic import for plugins/prompt-change-indicator/PromptChangeIndicator, renders it (with promptDetails and toolDetails) between ExpandCardBtn and PromptRunBtnSps when present.
  • frontend/src/routes/useMainAppRoutes.js: adds a parallel try/catch dynamic import for plugins/prompt-change-indicator/ReadOnlyReviewPage, registers review/readonly/:documentId inside the existing ReviewLayout group when present.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. The new code paths are guarded by if (PluginName) { ... } and the imports are inside try/catch. When the cloud plugin is absent (OSS), both blocks short-circuit and the UI is identical to before. The route addition lives inside the existing ReviewLayout && ManualReviewPage block so it can never override an existing route.

Database Migrations

  • None.

Env Config

  • None.

Relevant Docs

  • N/A

Related Issues or PRs

  • UN-3386
  • Companion (plugin implementation): Zipstack/unstract-cloud#1464 — merge this OSS PR first or together so the cloud plugin has its host hooks.
  • Depends on (server-side, separate work): UN-2128 for per-field tool/prompt attribution on HITLChangeLog rows.

Dependencies Versions

  • None.

Notes on Testing

  • OSS-only build (no cloud plugins): start npm start, open Prompt Studio — no indicator button, no console errors, no broken routes.
  • Hit /<orgName>/review/readonly/anything in OSS — should fall through (route only registers when plugin loads).
  • With cloud plugin synced into frontend/src/plugins/prompt-change-indicator/: indicator renders next to each prompt header and the readonly route works.

Screenshots

N/A

Checklist

I have read and understood the Contribution Guidelines.

🤖 Generated with Claude Code

Wires up the host-side hooks for the prompt-change-indicator plugin
(implementation lives in unstract-cloud): a dynamic-import slot in
the prompt card Header for the indicator button, and a route at
:orgName/review/readonly/:documentId for the read-only audit view.
Both gates fall through gracefully when the plugin is absent (OSS).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

Summary by CodeRabbit

  • New Features

    • Added a read-only review page for prompts accessible via a new dedicated route.
    • Integrated a prompt change indicator component with dynamic loading.
  • Improvements

    • Enhanced error handling for optional plugin components to prevent build failures.

Walkthrough

Header and routing now optionally load a prompt-change plugin via cloud-only dynamic imports: Header conditionally renders a PromptChangeIndicator, and the route tree conditionally registers a read-only review page under the ReviewLayout when the plugin is available.

Changes

Cohort / File(s) Summary
Optional Plugin UI Integration
frontend/src/components/custom-tools/prompt-card/Header.jsx
Performs a cloud-only dynamic import of PromptChangeIndicator, swallows missing-plugin errors so build continues, and conditionally renders the indicator passing promptDetails and details (as toolDetails) alongside the expand card button.
Dynamic Route Registration
frontend/src/routes/useMainAppRoutes.js
Adds lazy/dynamic import for a prompt-change-indicator ReadOnlyReviewPage. Handles import failures by distinguishing expected "module missing" vs unexpected errors, warns if the readonly component exists without ReviewLayout, and conditionally registers review/readonly/:documentId under the ReviewLayout subtree when present.

Sequence Diagram(s)

sequenceDiagram
  participant AppRouter as App Router
  participant Importer as Dynamic Importer
  participant Plugin as ReadOnlyReviewPlugin
  participant ReviewLayout as ReviewLayout
  AppRouter->>Importer: attempt import "prompt-change-indicator"
  alt import succeeds
    Importer->>Plugin: load module
    Plugin-->>Importer: module exported
    Importer-->>AppRouter: register route `review/readonly/:documentId`
    AppRouter->>ReviewLayout: mount nested route when visited
    ReviewLayout->>Plugin: render ReadOnlyReviewPage
  else module missing
    Importer-->>AppRouter: swallow missing-plugin error (no route registered)
  else unexpected error
    Importer-->>AppRouter: console.error and do not register route
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a plugin slot for a HITL change indicator in Prompt Studio, which directly aligns with the primary changes in both modified files.
Description check ✅ Passed The description comprehensively follows the template with all required sections filled out: What, Why, How, feature impact assessment, database/config/docs, related issues, testing notes, and the contribution guidelines checklist.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 UN-3386-prompt-studio-hitl-feedback

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

This PR adds two plugin integration points for a cloud-only HITL change-indicator feature: a dynamic-import slot in the prompt-card Header for PromptChangeIndicator, and a review/readonly/:documentId route registered inside the existing ReviewLayout group for ReadOnlyReviewPage. Both paths fall through silently in OSS builds via try/catch guards, leaving existing behaviour untouched.

Confidence Score: 5/5

Safe to merge — all new code paths are fully guarded by plugin-presence checks and existing routes are unaffected.

No P0 or P1 findings. The two P2 comments are minor style/design questions. The previously flagged cross-plugin dependency warning is already addressed in this PR.

No files require special attention.

Important Files Changed

Filename Overview
frontend/src/components/custom-tools/prompt-card/Header.jsx Adds dynamic-import slot for PromptChangeIndicator plugin; bare catch is inconsistent with the routes file, and indicator is not gated on !isSimplePromptStudio.
frontend/src/routes/useMainAppRoutes.js Registers ReadOnlyReviewPage route inside existing ReviewLayout group; well-handled with discriminated catch and explicit console.warn for missing-layout misconfiguration.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Module load] --> B{import PromptChangeIndicator}
    B -- found --> C[PromptChangeIndicator set]
    B -- missing/error --> D[stays undefined]

    A --> E{import ReadOnlyReviewPage}
    E -- found --> F[ReadOnlyReviewPage set]
    E -- module missing --> G[stays undefined, silent]
    E -- unexpected error --> H[console.error + stays undefined]

    F --> I{ReviewLayout present?}
    I -- No --> J[console.warn + route skipped]
    I -- Yes --> K[Route registered: review/readonly/:documentId]

    C --> L{Render Header}
    L -- PromptChangeIndicator defined --> M[Render indicator button]
    L -- undefined --> N[No indicator rendered]

    style J fill:#ffe0b2
    style H fill:#ffe0b2
Loading

Fix All in Claude Code

Prompt To Fix All With AI
This is a comment left during a code review.
Path: frontend/src/components/custom-tools/prompt-card/Header.jsx
Line: 44-52

Comment:
**Bare catch silently swallows non-missing-module errors**

The `PromptRunBtnSps` import above uses the same bare-catch pattern, but the sibling `ReadOnlyReviewPage` import in `useMainAppRoutes.js` (introduced in this same PR) correctly discriminates between "module not found" and unexpected errors (syntax/runtime). If the cloud plugin ships with a JS syntax error, the indicator silently disappears with no console signal. Consider applying the same discriminated-catch there for consistency and debuggability:

```js
} catch (err) {
  const msg = err?.message || "";
  const isModuleMissing =
    msg.includes("Failed to fetch dynamically imported module") ||
    msg.includes("Cannot find module");
  if (!isModuleMissing) {
    console.error("[prompt-change-indicator] PromptChangeIndicator import failed unexpectedly", err);
  }
}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: frontend/src/components/custom-tools/prompt-card/Header.jsx
Line: 407-412

Comment:
**`PromptChangeIndicator` renders in Simple Prompt Studio mode too**

The indicator is placed outside any `isSimplePromptStudio` gate, so it will render in both standard and Simple Prompt Studio modes. The existing run buttons are each carefully gated (`!isSimplePromptStudio` for regular buttons, `isSimplePromptStudio` for `PromptRunBtnSps`). If HITL review doesn't apply to SPS workflows, you'd want:

```suggestion
        {PromptChangeIndicator && !isSimplePromptStudio && (
          <PromptChangeIndicator
            promptDetails={promptDetails}
            toolDetails={details}
          />
        )}
```

If showing it in both modes is intentional, a brief comment here would clarify the design choice.

```suggestion
        {PromptChangeIndicator && !isSimplePromptStudio && (
          <PromptChangeIndicator
            promptDetails={promptDetails}
            toolDetails={details}
          />
        )}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "UN-3386 [FIX] Surface real plugin import..." | Re-trigger Greptile

Comment thread frontend/src/routes/useMainAppRoutes.js
@vishnuszipstack vishnuszipstack marked this pull request as draft April 27, 2026 09:00
vishnuszipstack and others added 2 commits April 27, 2026 14:34
Addresses review feedback: the readonly route nests inside ReviewLayout
(manual-review plugin), so a deployment that ships prompt-change-indicator
without manual-review would silently fail to register the route. Log a
console.warn in that case to make the misconfiguration discoverable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bare catch in the prompt-change-indicator dynamic import was swallowing
syntax/runtime errors in the plugin file alongside the expected
"plugin missing in OSS" case. Detect the missing-module messages
explicitly and console.error anything else so a broken cloud plugin
no longer disables the readonly route silently.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

@vishnuszipstack vishnuszipstack marked this pull request as ready for review April 27, 2026 09:26
@github-actions
Copy link
Copy Markdown
Contributor

Frontend Lint Report (Biome)

All checks passed! No linting or formatting issues found.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
frontend/src/routes/useMainAppRoutes.js (1)

115-136: Module-missing heuristic risks false positives and Header.jsx has inconsistent error handling.

The "Failed to fetch dynamically imported module" message is emitted by Vite for both genuinely missing modules and transitive dependency failures (e.g., chunk 404, network blips, sub-import typos). This means the current check silently swallows errors that should be surfaced — the exact failure mode the improved error handling was meant to prevent. Consider tightening the check to include the plugin path substring, or rely solely on err?.code === "MODULE_NOT_FOUND".

Additionally, frontend/src/components/custom-tools/prompt-card/Header.jsx (lines 42–49) uses a bare catch {} for the same prompt-change-indicator plugin. This creates an inconsistency: a broken cloud build surfaces an error here but silently disappears in the header, contradicting the PR goal of failing loudly for broken plugins.

🔧 Optional: tighten the missing-module check
   const msg = err?.message || "";
   const isModuleMissing =
     err?.code === "MODULE_NOT_FOUND" ||
-    msg.includes("Failed to fetch dynamically imported module") ||
-    msg.includes("Cannot find module");
+    msg.includes("Cannot find module") ||
+    (msg.includes("Failed to fetch dynamically imported module") &&
+      msg.includes("prompt-change-indicator/ReadOnlyReviewPage"));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/useMainAppRoutes.js` around lines 115 - 136, The
dynamic-import error handling in useMainAppRoutes.js around the
ReadOnlyReviewPage import is too permissive and can hide runtime or transitive
dependency failures; tighten the missing-module heuristic by checking err?.code
=== "MODULE_NOT_FOUND" or by additionally verifying the error message contains
the plugin path substring ("prompt-change-indicator/ReadOnlyReviewPage") before
treating it as a harmless missing-module case, and log/throw all other errors;
also make Header.jsx's bare catch (in the prompt-change-indicator import there)
consistent by replacing the empty catch with the same tightened heuristic and
error-logging behavior so unexpected plugin failures are surfaced uniformly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/src/routes/useMainAppRoutes.js`:
- Around line 115-136: The dynamic-import error handling in useMainAppRoutes.js
around the ReadOnlyReviewPage import is too permissive and can hide runtime or
transitive dependency failures; tighten the missing-module heuristic by checking
err?.code === "MODULE_NOT_FOUND" or by additionally verifying the error message
contains the plugin path substring
("prompt-change-indicator/ReadOnlyReviewPage") before treating it as a harmless
missing-module case, and log/throw all other errors; also make Header.jsx's bare
catch (in the prompt-change-indicator import there) consistent by replacing the
empty catch with the same tightened heuristic and error-logging behavior so
unexpected plugin failures are surfaced uniformly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2f482928-5b1e-48a0-a0d5-a2d4b16c27b8

📥 Commits

Reviewing files that changed from the base of the PR and between 200b2b5 and 3d02972.

📒 Files selected for processing (1)
  • frontend/src/routes/useMainAppRoutes.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants