Skip to content

UN-3479 [FEAT] Carry per-prompt table/agentic settings in Prompt Studio project transfer#2075

Merged
chandrasekharan-zipstack merged 3 commits into
mainfrom
UN-3479-ps-export-blob-prompt-settings
Jun 18, 2026
Merged

UN-3479 [FEAT] Carry per-prompt table/agentic settings in Prompt Studio project transfer#2075
chandrasekharan-zipstack merged 3 commits into
mainfrom
UN-3479-ps-export-blob-prompt-settings

Conversation

@chandrasekharan-zipstack

@chandrasekharan-zipstack chandrasekharan-zipstack commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What

Enrich the Prompt Studio project-transfer export/import blob with an optional per-prompt settings block carrying cloud-only table/record/agentic-table settings, materialised via the existing payload_modifier plugin.

Why

Project transfer (export → import, also the path the org-clone tool rides) dropped cloud-only per-prompt settings: table/record column schema and agentic-table settings. Transferred or cloned projects landed with the prompt typed (table / record / agentic_table) but the settings empty — a silent data-loss on every export/import of such a project.

How

  • _export_single_prompt: after building the prompt dict, call payload_modifier.export_prompt_settings(prompt); attach the returned block as settings when non-empty.
  • import_prompts: capture the created ToolStudioPrompt and, when the blob entry carries settings, call payload_modifier.import_prompt_settings(created, settings). sync_prompts routes through import_prompts, so adopt-resync is covered by the same hook.
  • Both call sites are plugin-guarded and try/except-wrapped: pure OSS (no plugin) and old blobs without the settings key are a complete no-op; a settings error never fails the export/import.

Cloud-side hook implementation: Zipstack/unstract-cloud#1567.

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 only runs when the payload_modifier plugin is installed (cloud builds) and a prompt actually has settings; the settings blob key is additive and optional, so existing blobs deserialize unchanged. Both call sites swallow and log errors, so they cannot regress export/import.

Database Migrations

None.

Env Config

None.

Relevant Docs

Related Issues or PRs

  • Cloud counterpart: Zipstack/unstract-cloud#1567
  • Org-clone tool (consumer): UN-3479

Dependencies Versions

Notes on Testing

Round-trip a Prompt Studio project containing a table/record prompt and (on a cloud build) an agentic_table prompt: export, import into another org, confirm settings (column schema / agentic config) are restored. AST/lint pass via pre-commit.

Screenshots

Checklist

I have read and understood the Contribution Guidelines.

…transfer

Prompt Studio project-transfer export/import dropped cloud-only per-prompt
settings (table/record column schema, agentic-table settings), so transferred
or cloned projects landed typed but empty. Enrich each exported prompt with an
optional `settings` block materialised via the payload_modifier plugin; pure
OSS (no plugin) and old blobs without the key are a no-op.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CsGrHbs5SWmQkKqiimg6CF
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 495b3463-85d5-495f-8b60-97195b60f8d0

📥 Commits

Reviewing files that changed from the base of the PR and between ab70039 and 07ff07f.

📒 Files selected for processing (1)
  • backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py

Summary by CodeRabbit

  • New Features
    • Prompts now preserve cloud-only per-prompt settings when exporting and importing.
  • Bug Fixes
    • Improved resilience during export/import: prompt settings plugin errors are handled gracefully without interrupting the overall operation.

Walkthrough

_export_single_prompt and import_prompts in prompt_studio_helper.py are updated to round-trip per-prompt settings through the payload_modifier plugin. Export enriches the prompt dict with a settings key; import restores those settings onto newly created ToolStudioPrompt objects. Plugin failures in both paths are caught and logged as warnings.

Changes

Per-prompt plugin settings export/import

Layer / File(s) Summary
Export per-prompt settings via plugin
backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py
_export_prompts resolves payload_modifier plugin once and passes it to _export_single_prompt for each prompt; _export_single_prompt builds the prompt dict into a variable d, calls export_prompt_settings(prompt) on the plugin when available, and stores the result under a settings key; plugin errors are caught and logged as warnings.
Import per-prompt settings via plugin
backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py
import_prompts resolves payload_modifier plugin once before the loop; after each ToolStudioPrompt is created, it calls import_prompt_settings(created, settings) when settings is present in the imported JSON and the plugin is available; plugin errors are caught and logged as warnings.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: carrying per-prompt table/agentic settings in Prompt Studio project transfer via the payload_modifier plugin.
Description check ✅ Passed The PR description comprehensively covers all required template sections with detailed context about what changed, why it was needed, implementation details, and testing approach.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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-3479-ps-export-blob-prompt-settings

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

greptile-apps Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes silent data loss during Prompt Studio project export/import by carrying per-prompt cloud-only settings (table/record column schema, agentic-table configuration) through the transfer blob using a payload_modifier plugin hook.

  • Export: _export_prompts now resolves the plugin once and passes it to _export_single_prompt, which calls export_prompt_settings(prompt) and attaches the result as an optional settings key in the prompt dict.
  • Import: import_prompts resolves the plugin once before the loop, calls import_prompt_settings(created, settings) after each ToolStudioPrompt.objects.create, and is fully backward-compatible — blobs without a settings key and OSS builds (no plugin) are no-ops.
  • Both call sites are guarded by plugin presence and wrapped in try/except, so they cannot regress existing export/import behaviour.

Confidence Score: 5/5

Safe to merge — changes are additive and fully isolated behind a plugin guard and try/except on both export and import paths.

The change is narrow: two new call sites that only run when the payload_modifier plugin is installed, each wrapped in try/except so a plugin failure cannot break the surrounding export or import. The settings key in the blob is optional, so all existing blobs and OSS builds remain unaffected. The plugin is resolved once per operation rather than per prompt, consistent with other call sites in the file. No schema migrations, no new dependencies, no altered control flow for the non-plugin path.

No files require special attention.

Important Files Changed

Filename Overview
backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py Adds optional per-prompt settings export/import via plugin hook; plugin resolved once per operation, changes are backward-compatible and error-isolated.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client
    participant PSHelper as PromptStudioHelper
    participant Plugin as payload_modifier plugin
    participant DB as ToolStudioPrompt DB

    Note over Client,DB: Export Flow
    Client->>PSHelper: _export_prompts(tool)
    PSHelper->>Plugin: get_plugin("payload_modifier") [once]
    loop for each prompt
        PSHelper->>PSHelper: _export_single_prompt(prompt, plugin)
        alt plugin present
            PSHelper->>Plugin: service_class().export_prompt_settings(prompt)
            Plugin-->>PSHelper: settings dict (or empty)
            PSHelper->>PSHelper: "attach d["settings"] = settings"
        end
        PSHelper-->>Client: prompt dict (with optional "settings")
    end

    Note over Client,DB: Import Flow
    Client->>PSHelper: import_prompts(prompts_data, new_tool, user)
    PSHelper->>Plugin: get_plugin("payload_modifier") [once]
    loop for each prompt_data
        PSHelper->>DB: ToolStudioPrompt.objects.create(...)
        DB-->>PSHelper: created prompt
        alt plugin present AND settings in blob
            PSHelper->>Plugin: service_class().import_prompt_settings(created, settings)
            Plugin-->>DB: restore table/agentic settings
        end
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client
    participant PSHelper as PromptStudioHelper
    participant Plugin as payload_modifier plugin
    participant DB as ToolStudioPrompt DB

    Note over Client,DB: Export Flow
    Client->>PSHelper: _export_prompts(tool)
    PSHelper->>Plugin: get_plugin("payload_modifier") [once]
    loop for each prompt
        PSHelper->>PSHelper: _export_single_prompt(prompt, plugin)
        alt plugin present
            PSHelper->>Plugin: service_class().export_prompt_settings(prompt)
            Plugin-->>PSHelper: settings dict (or empty)
            PSHelper->>PSHelper: "attach d["settings"] = settings"
        end
        PSHelper-->>Client: prompt dict (with optional "settings")
    end

    Note over Client,DB: Import Flow
    Client->>PSHelper: import_prompts(prompts_data, new_tool, user)
    PSHelper->>Plugin: get_plugin("payload_modifier") [once]
    loop for each prompt_data
        PSHelper->>DB: ToolStudioPrompt.objects.create(...)
        DB-->>PSHelper: created prompt
        alt plugin present AND settings in blob
            PSHelper->>Plugin: service_class().import_prompt_settings(created, settings)
            Plugin-->>DB: restore table/agentic settings
        end
    end
Loading

Reviews (3): Last reviewed commit: "Merge branch 'main' into UN-3479-ps-expo..." | Re-trigger Greptile

…r export

Hoist get_plugin("payload_modifier") out of the per-prompt loop into
_export_prompts and pass it into _export_single_prompt, matching the import
path which already resolves it once.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CsGrHbs5SWmQkKqiimg6CF
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
unit-connectors unit 64 12 0 3 16.7
unit-core unit 0 0 4 0 1.2
unit-platform-service unit 9 0 1 0 1.3
unit-prompt-service unit 15 0 0 0 20.0
unit-rig unit 53 0 0 0 3.2
unit-runner unit 11 0 0 0 3.2
unit-sdk1 unit 390 0 0 0 21.0
unit-tool-registry unit 0 0 1 0 1.3
unit-workers unit 0 0 0 0 17.4
TOTAL 542 12 6 3 85.4

Critical paths

⚠️ Critical paths not yet covered

  • auth-login — User can log in and obtain a session cookie. (entry: POST /api/v1/auth/login; declared coverage: no groups declared)
  • adapter-register-llm — Register and validate an LLM adapter. (entry: POST /api/v1/adapter/; declared coverage: no groups declared)
  • workflow-create-execute — Create a workflow, configure source+destination, execute, poll, fetch result. (entry: POST /api/v1/workflow/{id}/execute/; declared coverage: e2e-workflow)
  • api-deployment-run — Deploy a workflow as an API, POST a document, receive structured JSON. (entry: POST /deployment/api/{org}/{name}/; declared coverage: e2e-api-deployment)
  • prompt-studio-fetch-response — Prompt Studio: create project, add prompt, run single-pass, get response. (entry: POST /api/v1/prompt-studio/prompt-studio-tool/{id}/fetch_response/; declared coverage: e2e-prompt-studio)
  • pipeline-etl-execute — Run an ETL pipeline from source connector to destination. (entry: POST /api/v1/pipeline/{id}/execute/; declared coverage: no groups declared)
  • usage-token-tracking — Per-execution token usage is recorded and retrievable. (entry: GET /api/v1/usage/get_token_usage/; declared coverage: no groups declared)
  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (entry: internal: backend → rabbitmq → workers/file_processing; declared coverage: no groups declared)
  • callback-result-delivery — Async results are posted back via the callback worker. (entry: internal: workers/callback → backend /internal endpoints; declared coverage: no groups declared)
✅ Covered critical paths
  • tool-sandbox-exec — covered by unit-runner

@chandrasekharan-zipstack chandrasekharan-zipstack merged commit 8e8a78e into main Jun 18, 2026
9 checks passed
@chandrasekharan-zipstack chandrasekharan-zipstack deleted the UN-3479-ps-export-blob-prompt-settings branch June 18, 2026 14:43
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.

2 participants