Skip to content

[FIX] Resolve Prompt Studio default LLM profile and unblock deploy when LLMChallenge is off#2203

Open
hari-kuriakose wants to merge 2 commits into
mainfrom
fix/prompt-studio-profile-fallback-challenge-llm
Open

[FIX] Resolve Prompt Studio default LLM profile and unblock deploy when LLMChallenge is off#2203
hari-kuriakose wants to merge 2 commits into
mainfrom
fix/prompt-studio-profile-fallback-challenge-llm

Conversation

@hari-kuriakose

@hari-kuriakose hari-kuriakose commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What

Two server-side failures hit during a full Prompt Studio run (extract → Prompt Studio → export tool → deploy API → run). Both were traced in the backend source; the second was reproduced rather than inferred, because the obvious hypothesis turned out to be wrong.

Anchored at 24d08728.


1. fetch_response ignored the project default LLM profile — and the error blamed it

build_fetch_response_payload (and the synchronous _fetch_response) resolved the profile from the prompt's own FK and raised DefaultProfileError when it was null. Both sibling paths already fall back:

Path Profile resolution
index_document ProfileManager.get_default_llm_profile(tool)
single_pass ProfileManager.get_default_llm_profile(tool)
fetch_response prompt.profile_manager only

The helper already existed and was already used twice — fetch_response was the lone omission.

Why it cost so much time: DefaultProfileError read "Default LLM profile is not configured. Please set an LLM profile as default to continue." So you set the project default — set-default correctly writes is_default=True, profile get confirms it — and the call still failed. The message pointed at a setting the code never read.

Both call sites now fall back, and the message names both places a profile can come from.

2. An exported tool failed deployment validation when LLMChallenge was off

Symptom: deployment run ends in pipeline status ERROR; execution logs show 422 Unprocessable Entity: Tool validation failed. It surfaces only at the final step, after everything else has succeeded.

The obvious hypothesis is wrong. required=[challenge_llm] being hardcoded is not what breaks it — a present-but-empty key satisfies required. Running the real validator shows the failure is an enum violation.

The chain:

  1. Export resolves challenge_llm correctly, falling back to the default profile's LLM.
  2. Tool-instance creation throws it away — get_default_settings seeds a "type": "string" property with no spec default as "".
  3. Because challenge_llm declared adapterType: "LLM", _update_schema_for_adapter_type injects enum: [<real adapter ids>].
  4. DefaultsGeneratingValidator.validate(tool_meta) rejects "" — not in the enum.

This fired regardless of enable_challenge, and validate_adapter_access did not catch it first: it filters AdapterInstance.objects.filter(id__in=adapter_ids), so "" matches no row and passes silently.

Fix: frame_spec declares challenge_llm as a plain string with a "" default when enable_challenge is off, and only marks it required/adapter-typed when the feature is on. Since dropping required alone does not help (the instance stores "", not a missing key), the adapterType declaration is what has to be conditional.

Deliberately scoped to the Prompt Studio spec rather than changing _update_schema_for_adapter_type, which runs for LLM/EMBEDDING/VECTOR_DB/X2TEXT/OCR on every tool — broadening it there would make "" valid for every optional adapter property on every tool, risking a runtime failure on AdapterInstance.objects.get(id=""). That is the exact silent-"" class this fixes.


Verification

Composing the real frame_spec with the real _update_schema_for_adapter_type:

enable_challenge=False   llm_keys=[]                  required=[]
  {'challenge_llm': ''}        -> VALID          (before: RAISED enum)
  {'challenge_llm': <uuid>}    -> VALID

enable_challenge=True    llm_keys=['challenge_llm']   required=['challenge_llm']
  {'challenge_llm': ''}        -> RAISED enum    (correctly still enforced)
  {'challenge_llm': <uuid>}    -> VALID

With challenge enabled the enum is still injected and "" is still rejected — an enabled challenge cannot silently run without an LLM.

Scope, stated plainly: this fixes the challenge-off deploy failure, which was the reported surprise (a tool that never touched LLMChallenge failing at the last step). It does not change the challenge-on case: get_default_settings still seeds challenge_llm="" for those instances, so a challenge-enabled tool whose project never set a challenge LLM still fails the same enum check it did before. That is unchanged behaviour, not a regression — fixing it properly means seeding instance metadata from the exported tool's already-resolved settings (SERVER.md's "preferred" option), which is a cross-module change in tool_instance_v2 and deliberately not taken here. Happy to follow up with it separately.

ruff and ruff-format pass at the version pinned in .pre-commit-config.yaml (v0.3.4).

Note on tests: the Django-backed suites in these apps currently error with AppRegistryNotReady in a plain checkout, and the existing prompt_studio_core_v2 tests skip without test.env. A regression test written in that style would silently skip and read as coverage that isn't there, so I verified against the real functions instead. Happy to add one if there's a documented way to run those suites in CI.

Impact

  • Prompts with no profile FK become runnable when a project default exists.
  • Tools exported with LLMChallenge off now deploy instead of 422-ing at the last step.
  • Existing tool instances already storing challenge_llm: "" are fixed on re-export; no migration.

🤖 Generated with Claude Code

…en LLMChallenge is off

Two failures hit during a full Prompt Studio run (extract -> export tool ->
deploy API -> run).

1. fetch_response ignored the project default LLM profile

`build_fetch_response_payload` and `_fetch_response` resolved the profile from
the prompt's own FK only, and raised `DefaultProfileError` when it was null.
Both sibling paths already fall back to the project default:

  index_document  -> ProfileManager.get_default_llm_profile(tool)
  single_pass     -> ProfileManager.get_default_llm_profile(tool)
  fetch_response  -> prompt.profile_manager only

The error text ("Default LLM profile is not configured. Please set an LLM
profile as default to continue.") named the project default, so setting it
looked correct and the call still failed - the message pointed at a setting the
code never read. Both sites now fall back, and the message names both places a
profile can come from.

2. An exported tool failed deployment validation with LLMChallenge off

`deployment run` ended in pipeline status ERROR with
"422 Unprocessable Entity: Tool validation failed".

`get_default_settings` seeds a string property with no spec default as "", so a
tool instance stores `challenge_llm: ""`. Because the property declared
`adapterType: "LLM"`, `_update_schema_for_adapter_type` injected an enum of real
adapter IDs, which "" can never satisfy - and this fired regardless of
`enable_challenge`. `validate_adapter_access` did not catch it first: it filters
`id__in=adapter_ids`, so "" matches no row and passes silently.

The failure is an enum violation, not a required violation - a present-but-empty
key satisfies `required`. So dropping `required` alone is not sufficient.

`frame_spec` now declares `challenge_llm` as a plain string with a "" default
when `enable_challenge` is off, and only marks it required/adapter-typed when
the feature is on. With challenge enabled the enum is still injected and "" is
still rejected, so an enabled challenge cannot silently run without an LLM.
Scoped to the Prompt Studio spec, so no other tool or adapter type changes.

Verified by composing the real `frame_spec` with the real
`_update_schema_for_adapter_type`:

  enable_challenge=False  {'challenge_llm': ''}     -> VALID    (was: RAISED enum)
  enable_challenge=True   {'challenge_llm': ''}     -> RAISED enum
  enable_challenge=True   {'challenge_llm': <uuid>} -> VALID

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • Bug Fixes

    • Prompts now fall back to the project’s default LLM profile when no profile is explicitly attached.
    • Improved error guidance explains how to resolve missing LLM profiles.
    • Tools with LLM challenges disabled no longer require or validate an unused challenge LLM setting.
    • LLM challenge validation remains enforced when the feature is enabled.
  • Tests

    • Added coverage for enabled and disabled LLM challenge configurations and adapter validation.

Walkthrough

Prompt Studio now falls back to a project-default LLM profile when prompt-specific resolution is unavailable. Registry schemas conditionally validate and require challenge_llm based on whether LLMChallenge is enabled, with regression tests covering both modes.

Changes

Prompt Studio profile resolution

Layer / File(s) Summary
Project-default profile resolution
backend/prompt_studio/prompt_studio_core_v2/exceptions.py, backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py
Response payload construction and response fetching use the tool’s default LLM profile when no profile manager is resolved; the error message now describes prompt-level and project-default resolution options.

Conditional challenge schema

Layer / File(s) Summary
Challenge schema construction
backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py
challenge_llm is optional with an empty default when challenge support is disabled and remains adapter-backed and required when enabled.
Schema regression coverage
backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py
Tests validate empty defaults, requiredness, adapter IDs, and isolation of adapter enum injection across enabled and disabled challenge configurations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed, but it misses several required template sections and the breakage analysis is not filled in as a standalone required section. Add the missing template sections, especially the breakage impact section, migrations, env config, related issues, versions, screenshots, and checklist.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the two main fixes in the PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/prompt-studio-profile-fallback-challenge-llm

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.

@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes two Prompt Studio backend paths.

  • Falls back to the project’s default LLM profile when a prompt has no attached profile.
  • Makes the challenge LLM schema conditional so challenge-disabled tools can pass deployment validation.
  • Adds regression coverage for challenge-enabled and challenge-disabled schema behavior.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failures remain.

Important Files Changed

Filename Overview
backend/prompt_studio/prompt_studio_core_v2/exceptions.py Clarifies that profile resolution can use either a prompt attachment or the project default.
backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py Adds project-default profile fallback to both fetch-response implementations while preserving existing validation.
backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py Makes challenge LLM requirements and adapter constraints conditional on whether LLMChallenge is enabled.
backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py Exercises the exported schema and adapter-enum injection for enabled, disabled, empty, and populated challenge LLM states.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Prompt response requested] --> B{Prompt has LLM profile?}
  B -->|Yes| C[Use prompt profile]
  B -->|No| D[Resolve project default profile]
  C --> E[Validate adapters and fetch response]
  D --> E

  F[Export Prompt Studio tool] --> G{LLMChallenge enabled?}
  G -->|Yes| H[Require challenge_llm and constrain to LLM adapter IDs]
  G -->|No| I[Allow empty challenge_llm without adapter enum]
  H --> J[Create and validate tool instance]
  I --> J
Loading

Reviews (2): Last reviewed commit: "[TEST] Pin challenge_llm schema behaviou..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py (1)

50-68: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add regression tests for the complete validation matrix.

required only rejects a missing key; it does not reject challenge_llm="" when challenges are enabled. Test the actual deployment validator to confirm that:

  • Disabled: omitted, empty, and arbitrary string values are accepted, with no adapter constraint.
  • Enabled: the field is required, valid LLM profiles are accepted, and "" is rejected.

This also verifies that leaving adapterIdKey present does not retain adapter-specific validation when adapterType is removed.

Also applies to: 101-109

🤖 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
`@backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py`
around lines 50 - 68, Add regression tests covering the deployment validator’s
full challenge_llm matrix, using the existing helper and validator test symbols:
when challenges are disabled, verify omitted, empty, and arbitrary values are
accepted without adapter validation; when enabled, verify the field is required,
valid LLM profiles pass, and an empty string fails. Explicitly confirm removing
adapterType while retaining adapterIdKey does not impose adapter-specific
validation.
🤖 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 `@backend/prompt_studio/prompt_studio_core_v2/exceptions.py`:
- Around line 47-49: Update the DefaultProfileError message and its callers so
it accurately reflects tool-level failures from monitor_llm or challenge_llm
when the prompt already has a valid profile. Use context-specific guidance for
unresolved tool profiles, or ensure those fallbacks reuse the already-resolved
prompt profile; retain the existing guidance for genuinely missing prompt and
project profiles.

In `@backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py`:
- Around line 724-728: Update the fallback branch around
ProfileManager.get_default_llm_profile so callback metadata records the resolved
profile rather than the original argument: after resolving the default, set
cb_kwargs["profile_manager_id"] to profile_manager.profile_id. Preserve the
existing profile selection behavior for explicitly provided profile managers.

---

Nitpick comments:
In
`@backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py`:
- Around line 50-68: Add regression tests covering the deployment validator’s
full challenge_llm matrix, using the existing helper and validator test symbols:
when challenges are disabled, verify omitted, empty, and arbitrary values are
accepted without adapter validation; when enabled, verify the field is required,
valid LLM profiles pass, and an empty string fails. Explicitly confirm removing
adapterType while retaining adapterIdKey does not impose adapter-specific
validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2dc89667-a25a-40aa-a931-6116ba38103f

📥 Commits

Reviewing files that changed from the base of the PR and between 023b140 and a52feae.

📒 Files selected for processing (3)
  • backend/prompt_studio/prompt_studio_core_v2/exceptions.py
  • backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py
  • backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py

Comment on lines +47 to +49
"No LLM profile could be resolved for this prompt. "
"Either attach an LLM profile to the prompt, or set one as the "
"project default to continue."

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the error message accurate for tool-level LLM failures.

DefaultProfileError is also raised when monitor_llm or challenge_llm is unset and the project default cannot be resolved, even when the prompt already has a valid profile. In that case, “attach an LLM profile to the prompt” does not fix the failure; use a context-specific message or make those fallbacks use the already-resolved profile.

🤖 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 `@backend/prompt_studio/prompt_studio_core_v2/exceptions.py` around lines 47 -
49, Update the DefaultProfileError message and its callers so it accurately
reflects tool-level failures from monitor_llm or challenge_llm when the prompt
already has a valid profile. Use context-specific guidance for unresolved tool
profiles, or ensure those fallbacks reuse the already-resolved prompt profile;
retain the existing guidance for genuinely missing prompt and project profiles.

Comment on lines +724 to +728
# A prompt need not carry its own profile FK - fall back to the project
# default, matching index_document and single-pass extraction.
if not profile_manager:
profile_manager = ProfileManager.get_default_llm_profile(tool)

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Propagate the selected fallback profile to callback handling.

When this path resolves a project default, cb_kwargs["profile_manager_id"] later still contains the original argument, often None. OutputManagerHelper then resolves the project default again during callback processing, so a default-profile change between execution and callback can make output bookkeeping use a different profile. Pass the resolved profile_manager.profile_id in the callback metadata.

🤖 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 `@backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py` around
lines 724 - 728, Update the fallback branch around
ProfileManager.get_default_llm_profile so callback metadata records the resolved
profile rather than the original argument: after resolving the default, set
cb_kwargs["profile_manager_id"] to profile_manager.profile_id. Preserve the
existing profile selection behavior for explicitly provided profile managers.

… boundary

Regression tests for the deploy-time 422 fixed in this PR.

Exercises the real `frame_spec` composed with the real
`_update_schema_for_adapter_type`, rather than reimplementing either - a copy of
the logic would stay green even if the shipped code broke. The two function
bodies are extracted from source and run against stubs, because Django is not
importable in a plain checkout and both helpers live in Django-coupled modules.
Mirrors the approach already used in
`prompt_studio_core_v2/tests/test_build_index_payload.py`.

Coverage, split across the enable_challenge boundary:

  challenge OFF - the reported bug
    - a value seeded by get_default_settings validates (was: RAISED enum)
    - no adapter enum is injected
    - challenge_llm is not required
    - an explicitly set adapter ID still validates

  challenge ON - guards against over-correcting
    - "" is rejected, and specifically with an `enum` violation
    - a missing key is rejected with `required`
    - a real adapter ID validates
    - the enum lists real adapter IDs

  scope
    - adapter enums outside challenge_llm are untouched, so the empty-value
      allowance cannot leak to every optional adapter on every tool

Verified by mutation: reverting the fix in frame_spec fails exactly the three
challenge-OFF assertions while the challenge-ON guards stay green.

The tests assert the enum-vs-required distinction directly, since dropping
`required` alone does not fix the bug - a present-but-empty key satisfies
`required`. A future simplification back to an unconditional `adapterType`
therefore fails loudly instead of silently restoring the 422.

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

Copy link
Copy Markdown

@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 (2)
backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py (2)

141-186: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

exec/compile static-analysis flags (S102/no-exec/no-compile) are expected here.

Ruff and ast-grep flag the exec(compile(...)) calls used to run the extracted frame_spec and _update_schema_for_adapter_type bodies. Given the extensive rationale in the module docstring (testing the real function bodies rather than reimplementing them, since Django isn't importable in this checkout), this is a deliberate, non-security-sensitive use on trusted local source files rather than untrusted input — a reasonable false positive. If the project enforces these Ruff/ast-grep rules as CI-blocking, consider adding # noqa: S102 (and any equivalent ast-grep suppression) at the exec/compile call sites to avoid recurring lint failures without weakening the rule elsewhere.

🤖 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
`@backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py`
around lines 141 - 186, Add targeted lint suppressions for the intentional
exec/compile calls in _real_frame_spec and _real_update_schema, including Ruff
S102 and any configured ast-grep equivalent. Keep the suppression limited to
these trusted-source test helpers and do not weaken the rules globally.

Source: Linters/SAST tools


87-106: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

sys.modules stubs mutate global interpreter state with no teardown.

_load_spec_class() overwrites sys.modules["unstract"], "unstract.sdk1", "unstract.sdk1.constants", and "unstract.tool_registry" at module-import time (line 128, executed once at collection) and never restores them. If any other test in the same pytest session (run in the same process) subsequently does a real import unstract... on one of these exact dotted names, it will get this stub instead of the real module, since sys.modules is a process-wide cache. This is order-dependent and can cause hard-to-diagnose cross-test contamination.

Consider scoping the stubbing to a fixture using monkeypatch.setitem(sys.modules, ...) so pytest restores the original registry after the test/session, instead of mutating sys.modules at bare module scope.

Also applies to: 128-128

🤖 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
`@backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py`
around lines 87 - 106, Scope the module stubs used by _load_spec_class to
pytest-managed setup rather than mutating sys.modules during collection. Use a
fixture with monkeypatch.setitem for the unstract, sdk1, constants, and
tool_registry entries, and ensure the dynamically loaded modules are likewise
restored after use so other tests can import the real packages without
contamination.
🤖 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
`@backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py`:
- Around line 53-55: Add jsonschema to the backend test/dev dependency group in
pyproject.toml alongside pytest, using the project's existing dependency
declaration style, so test environments install it and
test_frame_spec_challenge_llm.py exercises the real validator instead of
skipping.

---

Nitpick comments:
In
`@backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py`:
- Around line 141-186: Add targeted lint suppressions for the intentional
exec/compile calls in _real_frame_spec and _real_update_schema, including Ruff
S102 and any configured ast-grep equivalent. Keep the suppression limited to
these trusted-source test helpers and do not weaken the rules globally.
- Around line 87-106: Scope the module stubs used by _load_spec_class to
pytest-managed setup rather than mutating sys.modules during collection. Use a
fixture with monkeypatch.setitem for the unstract, sdk1, constants, and
tool_registry entries, and ensure the dynamically loaded modules are likewise
restored after use so other tests can import the real packages without
contamination.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ca646d51-aad2-4f64-8b10-c2b83b4fab02

📥 Commits

Reviewing files that changed from the base of the PR and between a52feae and 5a4da0e.

📒 Files selected for processing (1)
  • backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py

Comment on lines +53 to +55
jsonschema = pytest.importorskip(
"jsonschema", reason="jsonschema is required to exercise the real validator"
)

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify jsonschema is declared as a backend dependency
fd pyproject.toml backend
rg -n 'jsonschema' backend/pyproject.toml backend/poetry.lock backend/requirements*.txt 2>/dev/null

Repository: Zipstack/unstract

Length of output: 178


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== backend pyproject files =="
fd '^pyproject\.toml$' backend -x echo "{}"

echo "== jsonschema occurrences in backend dependency/config files =="
rg -n --hidden --glob 'pyproject.toml|requirements*.txt|poetry.lock|setup.py|setup.cfg|uv.lock|pipfile.lock|Pipfile.lock' 'jsonschema' backend 2>/dev/null || true

echo "== relevant backend pyproject sections =="
sed -n '1,240p' backend/pyproject.toml | nl -ba

echo "== test file imports and jsonschema usage =="
sed -n '1,140p' backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py | nl -ba

echo "== top-level dependency declarations mentioning jsonschema =="
rg -n --hidden --glob 'pyproject.toml|requirements*.txt|poetry.lock|uv.lock|setup.py|setup.cfg|Pipfile.lock|pipfile.lock' 'jsonschema' . 2>/dev/null || true

Repository: Zipstack/unstract

Length of output: 355


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== backend pyproject files =="
fd '^pyproject\.toml$' backend

echo "== jsonschema occurrences in backend dependency/config files =="
rg -n --hidden --glob 'pyproject.toml|requirements*.txt|poetry.lock|setup.py|setup.cfg|uv.lock|Pipfile.lock|pipfile.lock' 'jsonschema' backend 2>/dev/null || true

echo "== relevant backend/pyproject.toml sections =="
awk 'NR>=1 && NR<=260 { printf "%6d\t%s\n", NR, $0 }' backend/pyproject.toml

echo "== test file imports and jsonschema usage =="
awk 'NR>=1 && NR<=140 { printf "%6d\t%s\n", NR, $0 }' backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py

echo "== top-level and frontend occurrence search for jsonschema =="
rg -n --hidden --glob 'pyproject.toml|requirements*.txt|poetry.lock|uv.lock|setup.py|setup.cfg|Pipfile.lock|pipfile.lock' 'jsonschema' . 2>/dev/null || true

Repository: Zipstack/unstract

Length of output: 11454


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== backend pyproject files =="
fd '^pyproject\.toml$' backend

echo "== jsonschema occurrences in backend dependency/config files =="
rg -n --hidden --glob 'pyproject.toml|req[urement]*s*.txt|poetry.lock|setup.py|setup.cfg|uv.lock|Pipfile.lock|pipfile.lock|pyproject_tomls.json' 'jsonschema' backend 2>/dev/null || true

echo "== relevant backend/pyproject.toml lines 1-260 =="
awk '{ printf "%6d\t%s\n", NR, $0 }' backend/pyproject.toml | sed -n '1,260p'

echo "== test file imports and jsonschema usage lines 1-140 =="
awk '{ printf "%6d\t%s\n", NR, $0 }' backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py | sed -n '1,140p'

echo "== jsonschema in all declared/lock dependency-like files in repo =="
rg -n --hidden --glob 'pyproject.toml|requirements*.txt|poetry.lock|uv.lock|setup.py|setup.cfg|Pipfile.lock|pipfile.lock' 'jsonschema' . 2>/dev/null || true

echo "== lock package lines for jsonschema =="
rg -n --hidden --glob 'poetry.lock|uv.lock|requirements*.txt' -E '^\[?Package|jsonschema|json-schema|schema' . 2>/dev/null || true

Repository: Zipstack/unstract

Length of output: 11515


Add jsonschema to the backend test/dev dependency set.

backend/pyproject.toml only declares pytest>=8.0.1 in the test group, so pytest.importorskip("jsonschema", ...) will skip these regression tests in environments without jsonschema installed instead of surface the missing test tooling. Add it to the backend dev/test dependencies to guarantee this suite runs under CI/local test installs.

🤖 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
`@backend/prompt_studio/prompt_studio_registry_v2/tests/test_frame_spec_challenge_llm.py`
around lines 53 - 55, Add jsonschema to the backend test/dev dependency group in
pyproject.toml alongside pytest, using the project's existing dependency
declaration style, so test environments install it and
test_frame_spec_challenge_llm.py exercises the real validator instead of
skipping.

@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
e2e-api-deployment e2e 3 0 0 0 16.0
e2e-coowners e2e 1 0 0 0 1.2
e2e-etl e2e 1 0 0 0 4.0
e2e-login e2e 2 0 0 0 1.0
e2e-prompt-studio e2e 1 0 0 0 4.1
e2e-smoke e2e 2 0 0 0 2.0
e2e-workflow e2e 1 0 0 0 16.0
integration-backend integration 162 0 0 26 33.4
integration-connectors integration 1 0 0 7 6.5
integration-workers integration 0 0 0 141 94.2
unit-backend unit 286 0 0 1 38.5
unit-connectors unit 63 0 0 0 10.5
unit-core unit 33 0 0 0 1.4
unit-platform-service unit 15 0 0 0 2.8
unit-rig unit 86 0 0 0 4.5
unit-sdk1 unit 480 0 0 0 27.0
unit-workers unit 1312 0 0 0 101.1
TOTAL 2449 0 0 175 364.5

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • adapter-register-llm — covered by integration-backend
  • workflow-author — covered by integration-backend
  • co-owner-manage — covered by integration-backend, e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-provision — covered by integration-backend
  • api-deployment-auth — covered by integration-backend
  • api-deployment-run — covered by e2e-api-deployment
  • prompt-studio-author — covered by integration-backend
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • connector-register-test — covered by integration-backend
  • pipeline-etl-execute — covered by e2e-etl
  • usage-aggregate-read — covered by integration-backend
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

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.

1 participant