argus-code-review 0.2.5__tar.gz → 0.2.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/CHANGELOG.md +14 -1
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/PKG-INFO +2 -2
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/pyproject.toml +1 -1
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_openai_client.py +38 -0
- argus_code_review-0.2.6/tests/test_output_models.py +188 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/.gitignore +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/LICENSE +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/README.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/__init__.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/bench.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/bench_default.toml +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/cli.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/config.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/coverage.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/dotenv_utils.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/gemini_cache.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/gemini_runner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/github_client.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/graph.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/helpers.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/llm/models.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/llm/output_models.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/llm/pricing.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/llm/usage.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/models.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/openai_client.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/openai_runner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/pipeline_models.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/__init__.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/actions_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/engine.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/eslint_bundle/.gitignore +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/eslint_bundle/README.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/eslint_bundle/eslint.config.js +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/eslint_bundle/package-lock.json +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/eslint_bundle/package.json +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/js_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/migration_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/rules/README.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/sarif.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/scanner_utils.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/secrets_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/shadow.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/terraform_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/workflow_lint_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/__init__.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-blocking-validator.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-coverage-check.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-cross-cutting.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-feedback-verifier.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-lite.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-planner.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-preflight-router.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-prior-art.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-deployment.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-frontend.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-infra.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-llm-patterns.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-observability.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-orchestration.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-security.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-slackbot.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-sql.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-subagent.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-tests-and-docs.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-writer.md +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts_runtime.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/repo_provision.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/review_tools.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/runners.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/storage/__init__.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/storage/http.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/storage/models.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/storage/precheck.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/storage/resolver.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/storage/session.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/storage/sql.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/storage/sqlite.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/008_add_code_reviews.sql +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/009_add_reviewer_version.sql +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/010_add_review_patterns.sql +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/011_add_review_progress_columns.sql +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/015_create_agent_runs.sql +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/016_add_agent_runs_failure_reason.sql +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/017_add_precheck_rules.sql +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/018_widen_agent_runs_failure_reason.sql +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/__init__.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/conftest.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/golden/review_response.schema.json +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/storage/__init__.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/storage/test_backend_contract.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/storage/test_http.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/storage/test_models.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/storage/test_resolver.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/storage/test_session.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/storage/test_sql.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/storage/test_sqlite_backend.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_actions_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_argus_review_local.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_bench.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_bench_config_guard.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_catchup_gate.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_cli_args.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_cli_output_contract.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_cli_post_review.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_cli_preflight.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_cli_prompts.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_config.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_conftest.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_gemini_cache.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_gemini_runner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_github_client_checks_signal.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_github_client_write.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_fetch_diff.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_get_llm_temperature.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_http_guards.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_precheck.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_preflight_image_bump.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_progress.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_storage_resolution.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_timeout_surfacing.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_js_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_llm_models.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_llm_models_override.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_llm_pricing.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_migration_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_models.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_multi_round.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_openai_runner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_packaging.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_plan_review.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_precheck_engine.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_precheck_engine_integration.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_precheck_sarif.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_precheck_shadow.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_precheck_shadow_integration.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_prompts.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_repo_provision.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_review_patterns_integration.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_review_tools.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_runners_context7.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_runners_context_usage.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_runners_helpers.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_runners_new.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_scanner_utils.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_secrets_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_specialist_validation.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_stage_costs.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_storage_precheck.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_terraform_scanner.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_terraform_scanner_integration.py +0 -0
- {argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_workflow_lint_scanner.py +0 -0
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.6] - 2026-09-19
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Bounded `openai` dependency to `>=1.66.0,<2` in `pyproject.toml` (TECH-6590) to
|
|
15
|
+
prevent unconstrained fresh installs from resolving to a future breaking major
|
|
16
|
+
release. The floor was also tightened from `>=1.50.0` to `>=1.66.0` where the
|
|
17
|
+
OpenAI Responses API (`client.responses.create()`) used by this codebase was
|
|
18
|
+
introduced. (Note: this is a general hygiene fix; it does not address the root
|
|
19
|
+
cause of the TECH-6590-reported crash, which was a separate shared-venv version-skew
|
|
20
|
+
issue tracked in TECH-6592.)
|
|
21
|
+
|
|
10
22
|
## [0.2.5] - 2026-09-18
|
|
11
23
|
|
|
12
24
|
### Added
|
|
@@ -326,7 +338,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
326
338
|
packaged set.
|
|
327
339
|
- `argus --version`, `argus prompts list`, and `argus prompts export`.
|
|
328
340
|
|
|
329
|
-
[Unreleased]: https://github.com/redesignhealth/argus-review/compare/v0.2.
|
|
341
|
+
[Unreleased]: https://github.com/redesignhealth/argus-review/compare/v0.2.6...HEAD
|
|
342
|
+
[0.2.6]: https://github.com/redesignhealth/argus-review/compare/v0.2.5...v0.2.6
|
|
330
343
|
[0.2.5]: https://github.com/redesignhealth/argus-review/compare/v0.2.4...v0.2.5
|
|
331
344
|
[0.2.4]: https://github.com/redesignhealth/argus-review/compare/v0.2.3...v0.2.4
|
|
332
345
|
[0.2.3]: https://github.com/redesignhealth/argus-review/compare/v0.2.2...v0.2.3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: argus-code-review
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Self-orchestrated PR review agent using LangGraph + Claude Agent SDK
|
|
5
5
|
Project-URL: Repository, https://github.com/redesignhealth/argus-review
|
|
6
6
|
Project-URL: Issues, https://github.com/redesignhealth/argus-review/issues
|
|
@@ -26,7 +26,7 @@ Requires-Dist: langgraph-checkpoint-sqlite>=2.0.0
|
|
|
26
26
|
Requires-Dist: langgraph<2,>=1.0.10
|
|
27
27
|
Requires-Dist: langsmith<1,>=0.2.0
|
|
28
28
|
Requires-Dist: litellm<2.0.0,>=1.50.0
|
|
29
|
-
Requires-Dist: openai
|
|
29
|
+
Requires-Dist: openai<2,>=1.66.0
|
|
30
30
|
Requires-Dist: psycopg-pool>=3.2.0
|
|
31
31
|
Requires-Dist: psycopg[binary]>=3.2.0
|
|
32
32
|
Requires-Dist: pydantic-settings>=2.0.0
|
|
@@ -46,7 +46,7 @@ dependencies = [
|
|
|
46
46
|
# HTTP client (GitHub API, storage HTTP shim)
|
|
47
47
|
"httpx>=0.27.0",
|
|
48
48
|
# OpenAI SDK for the plan-extraction fallback path
|
|
49
|
-
"openai>=1.
|
|
49
|
+
"openai>=1.66.0,<2",
|
|
50
50
|
# Per-token model pricing table (argus/llm/pricing.py) -- single source
|
|
51
51
|
# of truth for $/token rates, instead of a hand-maintained duplicate.
|
|
52
52
|
"litellm>=1.50.0,<2.0.0",
|
|
@@ -80,3 +80,41 @@ class TestGetAsyncOpenAIClientBaseURL:
|
|
|
80
80
|
|
|
81
81
|
mock_async_openai.assert_called_once()
|
|
82
82
|
assert mock_async_openai.call_args.kwargs["base_url"] is None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class TestOpenAIClientSyncRespond:
|
|
86
|
+
def test_respond_passes_text_format_to_responses_create(self) -> None:
|
|
87
|
+
"""text_format is wrapped in text={'format': text_format} for client.responses.create."""
|
|
88
|
+
settings = _make_settings(None)
|
|
89
|
+
mock_response = MagicMock()
|
|
90
|
+
mock_response.model = "gpt-5.4-mini"
|
|
91
|
+
mock_response.status = "completed"
|
|
92
|
+
mock_response.output = []
|
|
93
|
+
mock_response.output_text = "{}"
|
|
94
|
+
|
|
95
|
+
mock_client_instance = MagicMock()
|
|
96
|
+
mock_client_instance.responses.create.return_value = mock_response
|
|
97
|
+
|
|
98
|
+
text_format = {
|
|
99
|
+
"type": "json_schema",
|
|
100
|
+
"name": "test_schema",
|
|
101
|
+
"strict": True,
|
|
102
|
+
"schema": {"type": "object", "properties": {}},
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
with (
|
|
106
|
+
patch("argus.openai_client.get_settings", return_value=settings),
|
|
107
|
+
patch("argus.openai_client.OpenAI", return_value=mock_client_instance),
|
|
108
|
+
patch("argus.openai_client.wrap_openai", side_effect=lambda client: client),
|
|
109
|
+
):
|
|
110
|
+
client = OpenAIClientSync()
|
|
111
|
+
resp = client.respond(
|
|
112
|
+
input="test prompt",
|
|
113
|
+
text_format=text_format,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
mock_client_instance.responses.create.assert_called_once()
|
|
117
|
+
call_kwargs = mock_client_instance.responses.create.call_args.kwargs
|
|
118
|
+
assert call_kwargs["text"] == {"format": text_format}
|
|
119
|
+
assert call_kwargs["input"] == "test prompt"
|
|
120
|
+
assert resp == mock_response
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Tests for argus.llm.output_models: schema generation and Responses API format.
|
|
2
|
+
|
|
3
|
+
Verifies pydantic_to_response_format (including exclude= and strict= handling)
|
|
4
|
+
and LLMOutputModel schema generation for compatibility with OpenAI Responses API.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Literal
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
|
|
12
|
+
from argus.graph import _PIPELINE_ONLY_RESPONSE_FIELDS
|
|
13
|
+
from argus.llm.output_models import (
|
|
14
|
+
LLMOutputModel,
|
|
15
|
+
make_schema_strict,
|
|
16
|
+
pydantic_to_response_format,
|
|
17
|
+
)
|
|
18
|
+
from argus.models import ReviewResponse
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SampleModel(BaseModel):
|
|
22
|
+
name: str = Field(description="The name")
|
|
23
|
+
count: int = Field(default=0, description="The count")
|
|
24
|
+
tag: str | None = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SampleModelWithExcludedFields(BaseModel):
|
|
28
|
+
title: str
|
|
29
|
+
verdict: str
|
|
30
|
+
dropped_field_1: dict[str, float] = Field(default_factory=dict)
|
|
31
|
+
dropped_field_2: dict[str, float] = Field(default_factory=dict)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class SampleOutputModel(LLMOutputModel):
|
|
35
|
+
_schema_name = "custom_output"
|
|
36
|
+
|
|
37
|
+
summary: str = Field(description="Summary of results")
|
|
38
|
+
status: Literal["pass", "fail"] = Field(description="Pass or fail")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TestPydanticToResponseFormat:
|
|
42
|
+
def test_default_name_and_strict(self) -> None:
|
|
43
|
+
"""pydantic_to_response_format defaults name to model name in lowercase and strict=True."""
|
|
44
|
+
rf = pydantic_to_response_format(SampleModel)
|
|
45
|
+
|
|
46
|
+
assert rf["type"] == "json_schema"
|
|
47
|
+
assert rf["name"] == "samplemodel"
|
|
48
|
+
assert rf["strict"] is True
|
|
49
|
+
schema = rf["schema"]
|
|
50
|
+
assert schema["type"] == "object"
|
|
51
|
+
assert schema["additionalProperties"] is False
|
|
52
|
+
assert set(schema["required"]) == set(schema["properties"].keys())
|
|
53
|
+
|
|
54
|
+
def test_custom_name(self) -> None:
|
|
55
|
+
"""pydantic_to_response_format respects custom name."""
|
|
56
|
+
rf = pydantic_to_response_format(SampleModel, name="my_custom_schema")
|
|
57
|
+
assert rf["name"] == "my_custom_schema"
|
|
58
|
+
|
|
59
|
+
def test_strict_false(self) -> None:
|
|
60
|
+
"""pydantic_to_response_format respects strict=False."""
|
|
61
|
+
rf = pydantic_to_response_format(SampleModel, strict=False)
|
|
62
|
+
assert rf["strict"] is False
|
|
63
|
+
# strict=False does not enforce additionalProperties: false
|
|
64
|
+
assert rf["schema"].get("additionalProperties") is not False
|
|
65
|
+
|
|
66
|
+
def test_exclude_fields(self) -> None:
|
|
67
|
+
"""exclude= removes specified fields from schema properties and required."""
|
|
68
|
+
rf = pydantic_to_response_format(
|
|
69
|
+
SampleModelWithExcludedFields,
|
|
70
|
+
name="filtered_model",
|
|
71
|
+
exclude={"dropped_field_1", "dropped_field_2"},
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
properties = rf["schema"]["properties"]
|
|
75
|
+
assert "title" in properties
|
|
76
|
+
assert "verdict" in properties
|
|
77
|
+
assert "dropped_field_1" not in properties
|
|
78
|
+
assert "dropped_field_2" not in properties
|
|
79
|
+
|
|
80
|
+
required = rf["schema"]["required"]
|
|
81
|
+
assert "title" in required
|
|
82
|
+
assert "verdict" in required
|
|
83
|
+
assert "dropped_field_1" not in required
|
|
84
|
+
assert "dropped_field_2" not in required
|
|
85
|
+
|
|
86
|
+
def test_review_response_with_pipeline_only_fields_excluded(self) -> None:
|
|
87
|
+
"""ReviewResponse with _PIPELINE_ONLY_RESPONSE_FIELDS matches production graph.py usage."""
|
|
88
|
+
rf = pydantic_to_response_format(
|
|
89
|
+
ReviewResponse,
|
|
90
|
+
"review_response",
|
|
91
|
+
exclude=_PIPELINE_ONLY_RESPONSE_FIELDS,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
assert rf["type"] == "json_schema"
|
|
95
|
+
assert rf["name"] == "review_response"
|
|
96
|
+
assert rf["strict"] is True
|
|
97
|
+
|
|
98
|
+
properties = rf["schema"]["properties"]
|
|
99
|
+
required = rf["schema"]["required"]
|
|
100
|
+
|
|
101
|
+
for excluded in _PIPELINE_ONLY_RESPONSE_FIELDS:
|
|
102
|
+
assert excluded not in properties
|
|
103
|
+
assert excluded not in required
|
|
104
|
+
|
|
105
|
+
# Essential ReviewResponse fields must remain present and required
|
|
106
|
+
assert "verdict" in properties
|
|
107
|
+
assert "verdict" in required
|
|
108
|
+
assert "risk_level" in properties
|
|
109
|
+
assert "risk_level" in required
|
|
110
|
+
assert "findings" in properties
|
|
111
|
+
assert "findings" in required
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class TestLLMOutputModel:
|
|
115
|
+
def test_to_prompt_schema(self) -> None:
|
|
116
|
+
"""to_prompt_schema generates markdown with field definitions and example."""
|
|
117
|
+
schema_text = SampleOutputModel.to_prompt_schema()
|
|
118
|
+
assert "Your output MUST be valid JSON" in schema_text
|
|
119
|
+
assert "| `summary` | string |" in schema_text
|
|
120
|
+
assert "| `status` | enum |" in schema_text
|
|
121
|
+
assert (
|
|
122
|
+
"custom_output" not in schema_text
|
|
123
|
+
) # schema name is in API response_format, not prompt
|
|
124
|
+
|
|
125
|
+
def test_to_response_format(self) -> None:
|
|
126
|
+
"""to_response_format produces Chat Completions nested format."""
|
|
127
|
+
rf = SampleOutputModel.to_response_format()
|
|
128
|
+
assert rf["type"] == "json_schema"
|
|
129
|
+
assert "json_schema" in rf
|
|
130
|
+
assert rf["json_schema"]["name"] == "custom_output"
|
|
131
|
+
assert rf["json_schema"]["strict"] is True
|
|
132
|
+
|
|
133
|
+
def test_to_response_format_flat(self) -> None:
|
|
134
|
+
"""to_response_format_flat produces Responses API flat format."""
|
|
135
|
+
rf = SampleOutputModel.to_response_format_flat()
|
|
136
|
+
assert rf["type"] == "json_schema"
|
|
137
|
+
assert rf["name"] == "custom_output"
|
|
138
|
+
assert rf["strict"] is True
|
|
139
|
+
assert "schema" in rf
|
|
140
|
+
assert rf["schema"]["type"] == "object"
|
|
141
|
+
assert rf["schema"]["additionalProperties"] is False
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class TestMakeSchemaStrict:
|
|
145
|
+
def test_recursively_sets_additional_properties_false_and_required(self) -> None:
|
|
146
|
+
"""make_schema_strict sets additionalProperties=False and required on all objects."""
|
|
147
|
+
schema = {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"properties": {
|
|
150
|
+
"user": {
|
|
151
|
+
"type": "object",
|
|
152
|
+
"properties": {
|
|
153
|
+
"name": {"type": "string"},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
"items": {
|
|
157
|
+
"type": "array",
|
|
158
|
+
"items": {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"properties": {
|
|
161
|
+
"id": {"type": "integer"},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
strict_schema = make_schema_strict(schema)
|
|
169
|
+
|
|
170
|
+
assert strict_schema["additionalProperties"] is False
|
|
171
|
+
assert set(strict_schema["required"]) == {"user", "items"}
|
|
172
|
+
|
|
173
|
+
user_prop = strict_schema["properties"]["user"]
|
|
174
|
+
assert user_prop["additionalProperties"] is False
|
|
175
|
+
assert user_prop["required"] == ["name"]
|
|
176
|
+
|
|
177
|
+
item_schema = strict_schema["properties"]["items"]["items"]
|
|
178
|
+
assert item_schema["additionalProperties"] is False
|
|
179
|
+
assert item_schema["required"] == ["id"]
|
|
180
|
+
|
|
181
|
+
def test_ref_clears_sibling_keywords(self) -> None:
|
|
182
|
+
"""OpenAI strict mode requires $ref to have no sibling keywords."""
|
|
183
|
+
schema = {
|
|
184
|
+
"$ref": "#/$defs/SomeType",
|
|
185
|
+
"description": "Sibling keyword that OpenAI rejects in strict mode",
|
|
186
|
+
}
|
|
187
|
+
strict_schema = make_schema_strict(schema)
|
|
188
|
+
assert strict_schema == {"$ref": "#/$defs/SomeType"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/eslint_bundle/eslint.config.js
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/eslint_bundle/package-lock.json
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/precheck/eslint_bundle/package.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-blocking-validator.md
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-coverage-check.md
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-cross-cutting.md
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-feedback-verifier.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-preflight-router.md
RENAMED
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-deployment.md
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-frontend.md
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-infra.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-security.md
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-slackbot.md
RENAMED
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-specialist-sql.md
RENAMED
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/argus/prompts/pr-review-tests-and-docs.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/011_add_review_progress_columns.sql
RENAMED
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/016_add_agent_runs_failure_reason.sql
RENAMED
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/schema/018_widen_agent_runs_failure_reason.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/golden/review_response.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_github_client_checks_signal.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_graph_preflight_image_bump.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_precheck_engine_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_precheck_shadow_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_review_patterns_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{argus_code_review-0.2.5 → argus_code_review-0.2.6}/tests/test_terraform_scanner_integration.py
RENAMED
|
File without changes
|
|
File without changes
|