Skip to content

Add blueprint generation CLI#378

Merged
txmed82 merged 1 commit into
masterfrom
codex/blueprint-cli
Jun 4, 2026
Merged

Add blueprint generation CLI#378
txmed82 merged 1 commit into
masterfrom
codex/blueprint-cli

Conversation

@txmed82

@txmed82 txmed82 commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add casecrawler generate-blueprints for model-driven BlueprintGenerationRequest workflows
  • Accept BYOK planner and blueprint-generator provider/model/temperature options plus domains/settings
  • Persist through BlueprintPipeline and print dataset, plan, and blueprint counts

Tests

  • .venv/bin/python -m pytest tests/test_cli_synthetic.py::test_generate_blueprints_command_uses_model_driven_request -q
  • .venv/bin/python -m ruff check src/casecrawler/cli.py tests/test_cli_synthetic.py
  • .venv/bin/python -m pytest tests/test_cli_synthetic.py tests/test_cli_generate.py -q
  • .venv/bin/python -m pytest -q -m "not optional_backend and not network and not slow"

Summary by CodeRabbit

  • New Features
    • Added generate-blueprints CLI command to generate clinical blueprints with customizable parameters including request text, generation count, dataset persistence, domains, settings, model providers/models/temperatures, and optional grounding control.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A new generate-blueprints CLI command accepts blueprint request parameters and model configuration, builds a BlueprintGenerationRequest, invokes BlueprintPipeline.generate() to orchestrate plan and blueprint generation, and reports the dataset/plan IDs and blueprint count. Tests validate model-driven request construction and policy selection.

Changes

Blueprint Generation CLI Feature

Layer / File(s) Summary
Blueprint generation CLI command
src/casecrawler/cli.py
uuid4 import added to support default dataset id generation. New generate-blueprints Click command accepts request text, count, optional dataset id, domains/settings, planner/blueprint provider/model/temperature options, and --no-grounding flag. Builds BlueprintGenerationRequest, resolves dataset id using uuid4 when not provided, executes BlueprintPipeline().generate(...) via asyncio.run() with a DatasetStore, maps ValueError to click.ClickException, and outputs dataset id, plan id, and blueprint count.
Test fixture and CLI validation
tests/test_cli_synthetic.py
_blueprint_cli_result(dataset_id: str) helper constructs a BlueprintPipelineResult with hardcoded cohort plan and clinical blueprint linked to the provided dataset id. test_generate_blueprints_command_uses_model_driven_request monkeypatches BlueprintPipeline with a fake that captures the request, dataset id, and store arguments, persists plan/blueprints to the store, and returns the helper result. Test invokes the CLI command with specific planner/blueprint model flags, asserts successful exit and correct output, verifies captured request fields and policy model selections match the CLI-provided model names, and confirms the store argument is a DatasetStore instance.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • txmed82/case-crawler#376: The main PR's new generate-blueprints CLI command directly invokes BlueprintPipeline.generate(...) (and its tests assert the generated request/target count and model selections), which is enabled by the retrieved PR's new BlueprintPipeline orchestration/result models.
  • txmed82/case-crawler#373: The main PR's new generate-blueprints CLI command constructs and uses the BlueprintGenerationRequest contract (including role policy/model selection), directly depending on the request model introduced in the retrieved PR.
  • txmed82/case-crawler#377: Both PRs wire blueprint generation through BlueprintPipeline().generate(...) using a BlueprintGenerationRequest (including model-driven request fields like target_count/planner/blueprint policy selection) and a shared DatasetStore, differing only in whether it's triggered via the CLI vs the new /datasets/blueprints/generate API endpoint.

Poem

🐰 A blueprint takes shape from the CLI,
With models and planner both standing nearby,
The dataset id spawns from UUID so bright,
Generation flows through—the pipeline runs right,
And tests catch each whisker of validation in flight! 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add blueprint generation CLI' accurately summarizes the main change: adding a new CLI command for blueprint generation with model-driven request workflows.
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 codex/blueprint-cli

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
tests/test_cli_synthetic.py (1)

93-122: ⚡ Quick win

Assert the full CLI-to-request mapping here.

This test only locks down the two model names. The new command also maps providers, temperatures, domains, settings, and --no-grounding, so a wiring regression in those flags would still pass.

Possible test expansion
         [
             "generate-blueprints",
             "Generate anticoagulation decision cases.",
             "--count",
             "1",
+            "--domain",
+            "cardiovascular",
+            "--setting",
+            "outpatient",
             "--planner-provider",
             "openrouter",
             "--planner-model",
             "planner-model",
+            "--planner-temperature",
+            "0.25",
             "--blueprint-provider",
             "openrouter",
             "--blueprint-model",
             "blueprint-model",
+            "--blueprint-temperature",
+            "0.4",
+            "--no-grounding",
         ],
     )
@@
     assert captured[0][0].target_count == 1
+    assert captured[0][0].domains == ["cardiovascular"]
+    assert captured[0][0].settings == ["outpatient"]
+    assert captured[0][0].required_grounding is False
+    assert captured[0][0].policy_for(GenerationRole.PLANNER).provider == "openrouter"
     assert captured[0][0].policy_for(GenerationRole.PLANNER).model == "planner-model"
+    assert captured[0][0].policy_for(GenerationRole.PLANNER).temperature == 0.25
     assert (
+        captured[0][0].policy_for(GenerationRole.BLUEPRINT_GENERATOR).provider
+        == "openrouter"
+    )
+    assert (
         captured[0][0].policy_for(GenerationRole.BLUEPRINT_GENERATOR).model
         == "blueprint-model"
     )
+    assert (
+        captured[0][0].policy_for(GenerationRole.BLUEPRINT_GENERATOR).temperature
+        == 0.4
+    )
🤖 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 `@tests/test_cli_synthetic.py` around lines 93 - 122, The test currently only
asserts planner/blueprint model names; extend the assertions on the captured
request (captured[0][0]) to verify the full CLI->request mapping: assert planner
provider and blueprint provider values, any temperature fields for planner and
blueprint, the domain/intent flag, any settings dict or options passed, and that
the no-grounding flag maps to the request.no_grounding (or equivalent) boolean;
keep the existing checks for target_count,
policy_for(GenerationRole.PLANNER).model and
policy_for(GenerationRole.BLUEPRINT_GENERATOR).model and the DatasetStore type
to ensure complete coverage of the new flags and wiring.
🤖 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 `@src/casecrawler/cli.py`:
- Around line 967-998: Move the construction of the BlueprintGenerationRequest
into the try/except block so any validation errors raised while building the
request are caught and converted to a click.ClickException; specifically, wrap
the instantiation of BlueprintGenerationRequest (the req variable) together with
DatasetStore() creation and the call to
blueprint_pipeline_module.BlueprintPipeline().generate(...) inside the existing
try, and leave the except ValueError as exc: raise
click.ClickException(str(exc)) from exc to preserve user-facing CLI error
handling.

---

Nitpick comments:
In `@tests/test_cli_synthetic.py`:
- Around line 93-122: The test currently only asserts planner/blueprint model
names; extend the assertions on the captured request (captured[0][0]) to verify
the full CLI->request mapping: assert planner provider and blueprint provider
values, any temperature fields for planner and blueprint, the domain/intent
flag, any settings dict or options passed, and that the no-grounding flag maps
to the request.no_grounding (or equivalent) boolean; keep the existing checks
for target_count, policy_for(GenerationRole.PLANNER).model and
policy_for(GenerationRole.BLUEPRINT_GENERATOR).model and the DatasetStore type
to ensure complete coverage of the new flags and wiring.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ace66915-098e-469c-b58b-74f7ad6cf847

📥 Commits

Reviewing files that changed from the base of the PR and between 1a4f903 and 02f1860.

📒 Files selected for processing (2)
  • src/casecrawler/cli.py
  • tests/test_cli_synthetic.py

Comment thread src/casecrawler/cli.py
Comment on lines +967 to +998
req = BlueprintGenerationRequest(
request=request_text,
target_count=count,
domains=list(domains),
settings=list(settings),
required_grounding=not no_grounding,
role_policies=[
GenerationRolePolicy(
role=GenerationRole.PLANNER,
provider=planner_provider,
model=planner_model,
temperature=planner_temperature,
),
GenerationRolePolicy(
role=GenerationRole.BLUEPRINT_GENERATOR,
provider=blueprint_provider,
model=blueprint_model,
temperature=blueprint_temperature,
),
],
)
try:
store = DatasetStore()
result = asyncio.run(
blueprint_pipeline_module.BlueprintPipeline().generate(
req,
dataset_id=resolved_dataset_id,
store=store,
)
)
except ValueError as exc:
raise click.ClickException(str(exc)) from exc

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Wrap request validation in the ClickException boundary.

Lines 967-987 build BlueprintGenerationRequest before the try, so any model-validation failure there escapes as a raw exception instead of the user-facing CLI error this command uses for the pipeline call.

Proposed fix
-    resolved_dataset_id = dataset_id or f"blueprint-ds-{uuid4()}"
-    req = BlueprintGenerationRequest(
-        request=request_text,
-        target_count=count,
-        domains=list(domains),
-        settings=list(settings),
-        required_grounding=not no_grounding,
-        role_policies=[
-            GenerationRolePolicy(
-                role=GenerationRole.PLANNER,
-                provider=planner_provider,
-                model=planner_model,
-                temperature=planner_temperature,
-            ),
-            GenerationRolePolicy(
-                role=GenerationRole.BLUEPRINT_GENERATOR,
-                provider=blueprint_provider,
-                model=blueprint_model,
-                temperature=blueprint_temperature,
-            ),
-        ],
-    )
+    resolved_dataset_id = dataset_id or f"blueprint-ds-{uuid4()}"
     try:
+        req = BlueprintGenerationRequest(
+            request=request_text,
+            target_count=count,
+            domains=list(domains),
+            settings=list(settings),
+            required_grounding=not no_grounding,
+            role_policies=[
+                GenerationRolePolicy(
+                    role=GenerationRole.PLANNER,
+                    provider=planner_provider,
+                    model=planner_model,
+                    temperature=planner_temperature,
+                ),
+                GenerationRolePolicy(
+                    role=GenerationRole.BLUEPRINT_GENERATOR,
+                    provider=blueprint_provider,
+                    model=blueprint_model,
+                    temperature=blueprint_temperature,
+                ),
+            ],
+        )
         store = DatasetStore()
         result = asyncio.run(
             blueprint_pipeline_module.BlueprintPipeline().generate(
📝 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.

Suggested change
req = BlueprintGenerationRequest(
request=request_text,
target_count=count,
domains=list(domains),
settings=list(settings),
required_grounding=not no_grounding,
role_policies=[
GenerationRolePolicy(
role=GenerationRole.PLANNER,
provider=planner_provider,
model=planner_model,
temperature=planner_temperature,
),
GenerationRolePolicy(
role=GenerationRole.BLUEPRINT_GENERATOR,
provider=blueprint_provider,
model=blueprint_model,
temperature=blueprint_temperature,
),
],
)
try:
store = DatasetStore()
result = asyncio.run(
blueprint_pipeline_module.BlueprintPipeline().generate(
req,
dataset_id=resolved_dataset_id,
store=store,
)
)
except ValueError as exc:
raise click.ClickException(str(exc)) from exc
try:
req = BlueprintGenerationRequest(
request=request_text,
target_count=count,
domains=list(domains),
settings=list(settings),
required_grounding=not no_grounding,
role_policies=[
GenerationRolePolicy(
role=GenerationRole.PLANNER,
provider=planner_provider,
model=planner_model,
temperature=planner_temperature,
),
GenerationRolePolicy(
role=GenerationRole.BLUEPRINT_GENERATOR,
provider=blueprint_provider,
model=blueprint_model,
temperature=blueprint_temperature,
),
],
)
store = DatasetStore()
result = asyncio.run(
blueprint_pipeline_module.BlueprintPipeline().generate(
req,
dataset_id=resolved_dataset_id,
store=store,
)
)
except ValueError as exc:
raise click.ClickException(str(exc)) from exc
🤖 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 `@src/casecrawler/cli.py` around lines 967 - 998, Move the construction of the
BlueprintGenerationRequest into the try/except block so any validation errors
raised while building the request are caught and converted to a
click.ClickException; specifically, wrap the instantiation of
BlueprintGenerationRequest (the req variable) together with DatasetStore()
creation and the call to
blueprint_pipeline_module.BlueprintPipeline().generate(...) inside the existing
try, and leave the except ValueError as exc: raise
click.ClickException(str(exc)) from exc to preserve user-facing CLI error
handling.

@txmed82 txmed82 merged commit d16d9ef into master Jun 4, 2026
4 checks passed
@txmed82 txmed82 deleted the codex/blueprint-cli branch June 4, 2026 01:06
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