agentic-dev-loop 0.15.2__tar.gz → 0.15.4__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.
- {agentic_dev_loop-0.15.2/src/agentic_dev_loop.egg-info → agentic_dev_loop-0.15.4}/PKG-INFO +8 -5
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/README.md +5 -4
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/pyproject.toml +12 -1
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/brief_coverage.py +33 -10
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/brief_prompt.md +10 -7
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/brief_prompt.py +4 -4
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/templates/dev.agent.md +24 -9
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/stages.py +8 -9
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4/src/agentic_dev_loop.egg-info}/PKG-INFO +8 -5
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop.egg-info/requires.txt +2 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_041_brief_coverage.py +45 -4
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_046_brief_prompt.py +8 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_outputs_pbt.py +6 -2
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_unit11.py +38 -1
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/LICENSE +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/setup.cfg +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/config.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/failure.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/paths.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/profiles/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/profiles/data/dotnet-node.yaml +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/profiles/data/python.yaml +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/results.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/verdict.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/actions.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/agent_error_guide.md +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/agent_error_guide.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/agents.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/allowlist.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/cli.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/completion.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/containers.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/copilot_auth.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/deps.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/dryrun.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/forbidden.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/graph.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/isolation.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/llm.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/loaders.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/mounts.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/checks.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/doctor.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/init.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/recipes/dotnet-node.yaml +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/recipes/python.yaml +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/recipes.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/templates/env.example +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/templates/qa.agent.md +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/templates/review.agent.md +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/templates.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/upgrade.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/outputs.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/presets.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/proc.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/provider_wire.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/registry.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/run_status.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/run_status_command.md +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/secrets.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/sync_back.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/py.typed +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/reporting/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/reporting/metrics.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/reporting/render.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/reporting/sources.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/viz/__init__.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/viz/layout.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/viz/page.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/viz/runs_view.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/viz/server.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop.egg-info/SOURCES.txt +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_029_merge_on_conflict.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_033_brief_step.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_035_finalize_nudge.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_036_banned_commands_and_lane_boundary.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_cli.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_doctor.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_init.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_profile_loading.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_profiles.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_recipes.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_schema_lock.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_templates.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_055_upgrade.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_actions.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_agent_error_guide.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_agents.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_aidlc.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_build_viz_page.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_cli.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_config.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_containers.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_copilot_auth.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_copilot_cli.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_deps.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_dry_run.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_e2e_fixtures.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_egress_proxy.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_graph.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_hostboundary.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_hostboundary_integration.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_isolation.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_isolation_integration.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_isolation_pbt.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_llm.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_loaders.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_module_contract.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_outputs.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_proc.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_provider_wire.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_publish.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_qa_prompt.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_registry.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_repo_ascii.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_results.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_run_status.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_runs_js_filters.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_runs_js_key_stats.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_runs_js_metrics.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_runs_layout.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_runs_layout_key_stats.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_sdk_compat.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_secrets.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_secrets_integration.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_secrets_pipeline.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_source_resolution.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_stages.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_step_workspace.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_sync_back.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_unit11_pbt.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_unit12_reporting.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_unit13_runs_viz.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_unit5_config.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_unit5_pbt.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_unit5_pure.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_verdict.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_viz.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_viz_demo.py +0 -0
- {agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/tests/test_viz_layout.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-dev-loop
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.4
|
|
4
4
|
Summary: Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.
|
|
5
5
|
Author: Luke Wilson
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,6 +29,8 @@ Requires-Dist: pydantic>=2.0
|
|
|
29
29
|
Requires-Dist: PyYAML>=6.0
|
|
30
30
|
Requires-Dist: openhands-sdk~=1.17.0
|
|
31
31
|
Requires-Dist: openhands-tools~=1.17.0
|
|
32
|
+
Requires-Dist: browser-use==0.11.13
|
|
33
|
+
Requires-Dist: pillow>=13.0.0
|
|
32
34
|
Requires-Dist: agent-client-protocol<1.0.0
|
|
33
35
|
Requires-Dist: langgraph>=1.2
|
|
34
36
|
Requires-Dist: langgraph-checkpoint-sqlite>=3.0
|
|
@@ -560,10 +562,11 @@ Conventions that make a good agent file:
|
|
|
560
562
|
- **dev enumerates its impossible set and stops at it.** List the commands
|
|
561
563
|
the sandbox cannot run (offline package fetches, browser downloads), one
|
|
562
564
|
attempt per command - keeps the productive loop and kills doomed retries.
|
|
563
|
-
- **Failure output
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
565
|
+
- **Failure output is a required fix in dev's next context.** Agent verdict
|
|
566
|
+
steps land their failing output under *Previous attempt feedback*; command
|
|
567
|
+
gates (test, restore) land it under *Mechanical gate output*, with the exit
|
|
568
|
+
code under *Verified state*. Steps route `on_fail: { goto: dev, retry: true }`,
|
|
569
|
+
and the dev prompt makes every listed failure a required fix.
|
|
567
570
|
- **No git mutations, ever.** The `commit` step is the single commit point.
|
|
568
571
|
|
|
569
572
|
### The pipeline file
|
|
@@ -515,10 +515,11 @@ Conventions that make a good agent file:
|
|
|
515
515
|
- **dev enumerates its impossible set and stops at it.** List the commands
|
|
516
516
|
the sandbox cannot run (offline package fetches, browser downloads), one
|
|
517
517
|
attempt per command - keeps the productive loop and kills doomed retries.
|
|
518
|
-
- **Failure output
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
518
|
+
- **Failure output is a required fix in dev's next context.** Agent verdict
|
|
519
|
+
steps land their failing output under *Previous attempt feedback*; command
|
|
520
|
+
gates (test, restore) land it under *Mechanical gate output*, with the exit
|
|
521
|
+
code under *Verified state*. Steps route `on_fail: { goto: dev, retry: true }`,
|
|
522
|
+
and the dev prompt makes every listed failure a required fix.
|
|
522
523
|
- **No git mutations, ever.** The `commit` step is the single commit point.
|
|
523
524
|
|
|
524
525
|
### The pipeline file
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentic-dev-loop"
|
|
7
|
-
version = "0.15.
|
|
7
|
+
version = "0.15.4"
|
|
8
8
|
description = "Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -36,6 +36,17 @@ dependencies = [
|
|
|
36
36
|
"PyYAML>=6.0",
|
|
37
37
|
"openhands-sdk ~=1.17.0",
|
|
38
38
|
"openhands-tools ~=1.17.0",
|
|
39
|
+
# browser-use is a transitive dep (openhands-tools declares
|
|
40
|
+
# browser-use>=0.8.0, unpinned). 0.12.0+ hard-pin pillow==12.x, and
|
|
41
|
+
# pillow 12.3.0 carries 39 CVEs (fixed in 13.0.0); pin the last release
|
|
42
|
+
# with an open pillow constraint (>=11.2.1) so a fresh pip resolve lands
|
|
43
|
+
# on pillow 13.0.0 and the restore step's pip-audit stays green.
|
|
44
|
+
"browser-use==0.11.13",
|
|
45
|
+
# pillow is a transitive dep (browser-use, reportlab). 12.3.0 carries 39
|
|
46
|
+
# CVEs (fixed in 13.0.0); pin a floor so the restore step's pip-audit
|
|
47
|
+
# stays green, and so a future browser-use pin back to ==12.x fails the
|
|
48
|
+
# install loudly instead of silently reintroducing the CVEs.
|
|
49
|
+
"pillow>=13.0.0",
|
|
39
50
|
# openhands-sdk declares agent-client-protocol>=0.8.1 with NO upper bound;
|
|
40
51
|
# the 1.0.0rc pre-releases drop acp.helpers (breaks sdk 1.17.0 imports).
|
|
41
52
|
# Without this cap, --pre installs resolve to the broken rc. See AGENTS.md
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/brief_coverage.py
RENAMED
|
@@ -11,11 +11,26 @@ and file-agnostic.
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
13
|
import re
|
|
14
|
+
import unicodedata
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
_GLYPH_FOLD = str.maketrans({
|
|
18
|
+
"\u2010": "-", "\u2011": "-", "\u2012": "-",
|
|
19
|
+
"\u2013": "-", "\u2014": "-", "\u2015": "-",
|
|
20
|
+
"\u2018": "'", "\u2019": "'",
|
|
21
|
+
"\u201c": '"', "\u201d": '"',
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _fold_glyphs(text: str) -> str:
|
|
26
|
+
"""Fold compatibility glyphs and collapse whitespace, preserving case."""
|
|
27
|
+
folded = unicodedata.normalize("NFKC", text).translate(_GLYPH_FOLD)
|
|
28
|
+
return " ".join(folded.split())
|
|
14
29
|
|
|
15
30
|
|
|
16
31
|
def _normalize(text: str) -> str:
|
|
17
|
-
"""Case-
|
|
18
|
-
return
|
|
32
|
+
"""Case-folded, glyph-folded, whitespace-collapsed matching form."""
|
|
33
|
+
return _fold_glyphs(text).casefold()
|
|
19
34
|
|
|
20
35
|
|
|
21
36
|
def _normalize_line(line: str) -> str:
|
|
@@ -23,7 +38,7 @@ def _normalize_line(line: str) -> str:
|
|
|
23
38
|
|
|
24
39
|
A compliant digest writes anchors as headings on their own line, wrapped
|
|
25
40
|
in ``**`` and (for the four section headings) prefixed with ``##``. List
|
|
26
|
-
bullets are tolerated; the
|
|
41
|
+
bullets are tolerated; the line-prefix comparison is what makes a mid-line
|
|
27
42
|
prose mention fail."""
|
|
28
43
|
stripped = line.strip().replace("**", "")
|
|
29
44
|
stripped = re.sub(r"^#+\s*", "", stripped)
|
|
@@ -67,19 +82,27 @@ def missing_anchors(brief_text: str, anchors: list[str],
|
|
|
67
82
|
"""Return every required item the captured brief fails to cover.
|
|
68
83
|
|
|
69
84
|
Required section headings (from the configured ``brief_inputs.sections``)
|
|
70
|
-
and anchors are matched line
|
|
71
|
-
whitespace-collapsed,
|
|
72
|
-
|
|
85
|
+
and anchors are matched as line prefixes (case-insensitive,
|
|
86
|
+
glyph-folded, whitespace-collapsed, decoration stripped): an item is
|
|
87
|
+
covered when it starts a line, so content may follow on that line. A
|
|
88
|
+
mid-line mention does not count. Env facts are matched as glyph-folded,
|
|
89
|
+
whitespace-collapsed, case-sensitive substrings. An empty list means the
|
|
73
90
|
digest passes coverage."""
|
|
74
91
|
missing: list[str] = []
|
|
75
|
-
lines =
|
|
92
|
+
lines = [_normalize_line(line) for line in brief_text.splitlines()]
|
|
93
|
+
lines = [line for line in lines if line]
|
|
94
|
+
|
|
95
|
+
def covered(item: str) -> bool:
|
|
96
|
+
return any(line.startswith(item) for line in lines)
|
|
97
|
+
|
|
76
98
|
for section in sections:
|
|
77
|
-
if _normalize(section)
|
|
99
|
+
if not covered(_normalize(section)):
|
|
78
100
|
missing.append(section)
|
|
79
101
|
for anchor in anchors:
|
|
80
|
-
if
|
|
102
|
+
if not covered(anchor):
|
|
81
103
|
missing.append(anchor)
|
|
104
|
+
folded_brief = _fold_glyphs(brief_text)
|
|
82
105
|
for fact in env_facts:
|
|
83
|
-
if fact not in
|
|
106
|
+
if _fold_glyphs(fact) not in folded_brief:
|
|
84
107
|
missing.append(fact)
|
|
85
108
|
return missing
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/brief_prompt.md
RENAMED
|
@@ -26,21 +26,24 @@ a compact brief that the dev and review agents reuse on every attempt.
|
|
|
26
26
|
attempt. Do not invent them and do not re-derive them.
|
|
27
27
|
- The repo-rules digest is structural: one line per top-level section of each
|
|
28
28
|
repo-rule input. Markdown anchors are the `##` headings: keep each heading
|
|
29
|
-
verbatim, then compress that section's rules
|
|
30
|
-
|
|
29
|
+
verbatim at the start of its own line, then compress that section's rules
|
|
30
|
+
into the text that follows on that line (after a colon) or on the next
|
|
31
|
+
line. YAML anchors are each `- name:` entry under `categories:` plus the
|
|
31
32
|
`enforcement_levels` preamble: keep each name verbatim. No top-level section
|
|
32
33
|
or category may be dropped; merging is allowed only between a section and
|
|
33
|
-
its own subsections
|
|
34
|
-
compressed rules go on the following line:
|
|
34
|
+
its own subsections:
|
|
35
35
|
|
|
36
36
|
- general_principles
|
|
37
37
|
Simplest thing that works; defer decisions to the last responsible moment.
|
|
38
38
|
|
|
39
|
-
A line like `general_principles: Simplest thing that works; ...`
|
|
40
|
-
|
|
39
|
+
A line like `general_principles: Simplest thing that works; ...` passes too:
|
|
40
|
+
the heading must start its line.
|
|
41
41
|
- Keep the environment-facts entries verbatim: each fact and the behavior it
|
|
42
42
|
implies travel together.
|
|
43
|
-
- ASCII only
|
|
43
|
+
- ASCII only, except that a required heading, env fact, or configured section
|
|
44
|
+
heading must be reproduced character-exact: when such an item contains a
|
|
45
|
+
non-ASCII character, keep that exact character, never transliterate it. Do
|
|
46
|
+
not introduce em dashes or other non-ASCII characters of your own.
|
|
44
47
|
- If the task message carries a `## Coverage retry` section, regenerate the
|
|
45
48
|
brief so every listed item appears, verbatim where the contract requires
|
|
46
49
|
verbatim. No exploration: the listed items are the only correction signal.
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/brief_prompt.py
RENAMED
|
@@ -15,7 +15,7 @@ from __future__ import annotations
|
|
|
15
15
|
from importlib.resources import files
|
|
16
16
|
|
|
17
17
|
BRIEF_PROMPT_RESOURCE = "brief_prompt.md"
|
|
18
|
-
BRIEF_PROMPT_VERSION = "
|
|
18
|
+
BRIEF_PROMPT_VERSION = "2"
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def load_template() -> str:
|
|
@@ -36,9 +36,9 @@ def _output_block(sections: list[str]) -> str:
|
|
|
36
36
|
"compressed content for that section (write `None` when a section has "
|
|
37
37
|
"nothing):\n\n"
|
|
38
38
|
f"{headings}\n\n"
|
|
39
|
-
|
|
40
|
-
"Do not shorten or rename them, and do not
|
|
41
|
-
"another section."
|
|
39
|
+
"The section headings must appear at the start of their own lines, as "
|
|
40
|
+
f"written above: {names}. Do not shorten or rename them, and do not "
|
|
41
|
+
"merge a section with another section."
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
|
|
@@ -10,10 +10,11 @@ opinionated LangGraph + OpenHands SDK pipeline engine written in Python.
|
|
|
10
10
|
## WORKFLOW
|
|
11
11
|
|
|
12
12
|
1. Read the plan documents and README.md in the context below.
|
|
13
|
-
2. If the context contains a *Previous attempt feedback* section
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
the edited file) before
|
|
13
|
+
2. If the context contains a *Previous attempt feedback* section or a
|
|
14
|
+
*Mechanical gate output* section, treat every issue listed there as a
|
|
15
|
+
required fix from the pipeline's earlier stages - address each one before
|
|
16
|
+
anything else, and verify each fix landed (re-read the edited file) before
|
|
17
|
+
moving on. A mechanical entry names the attempt that produced it.
|
|
17
18
|
3. Check for prior-attempt residue before implementing. The pipeline syncs
|
|
18
19
|
every lane's edits back into this repo's working tree after each terminal
|
|
19
20
|
action, so an earlier attempt that died at a later gate can leave the full
|
|
@@ -66,10 +67,23 @@ opinionated LangGraph + OpenHands SDK pipeline engine written in Python.
|
|
|
66
67
|
exit code alone.
|
|
67
68
|
- You do not need to prove anything here: fill in the verification matrix,
|
|
68
69
|
write your final response, and stop.
|
|
69
|
-
- If the gate fails, you are retried with the failing output
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
- If the gate fails, you are retried with the failing output under
|
|
71
|
+
*Mechanical gate output* and the exit code under *Verified state* (command
|
|
72
|
+
gates do not write *Previous attempt feedback*). Find the root cause - a
|
|
73
|
+
regression in your change, a stale test pinning old behavior, or a genuine
|
|
74
|
+
library bug - and fix it, never the symptom.
|
|
75
|
+
|
|
76
|
+
## AUDIT GATE
|
|
77
|
+
|
|
78
|
+
- The restore step re-runs the install and a dependency audit on every pass.
|
|
79
|
+
A failing audit means a pin in the dependency manifest carries known CVEs;
|
|
80
|
+
it is a required fix, never "pre-existing" or "unrelated".
|
|
81
|
+
- Fix it with a manifest edit, never a package-manager command (agent steps
|
|
82
|
+
are offline). Follow the floor-pin pattern: pin the vulnerable resolved
|
|
83
|
+
package to a CVE-free version, or pin the intermediate package to the last
|
|
84
|
+
release that admits it, so a fresh resolve lands on the fixed version.
|
|
85
|
+
- Restore re-audits the bumped pins on the next pass, so the loop
|
|
86
|
+
self-corrects; report the audit as fixed only after that gate passes.
|
|
73
87
|
|
|
74
88
|
## TEST-FIRST
|
|
75
89
|
|
|
@@ -81,7 +95,8 @@ opinionated LangGraph + OpenHands SDK pipeline engine written in Python.
|
|
|
81
95
|
|
|
82
96
|
- The moment your final response is written AND the full suite has passed
|
|
83
97
|
locally (`.venv-sandbox/bin/python -m pytest tests/ -q` exits 0) AND every
|
|
84
|
-
*Previous attempt feedback*
|
|
98
|
+
*Previous attempt feedback* and *Mechanical gate output* item is addressed,
|
|
99
|
+
the step is COMPLETE. Stop.
|
|
85
100
|
- Do not re-read files, re-run checks, or `cat`/`tail`/`grep` files you just
|
|
86
101
|
wrote to confirm what already passed. A green suite is a green suite:
|
|
87
102
|
re-running it buys nothing, since the mechanical test gate re-runs the
|
|
@@ -446,7 +446,10 @@ def build_context(runtime: Runtime, docs: dict[str, str], subject: str,
|
|
|
446
446
|
own mechanical section (process fact, never an agent claim), and only
|
|
447
447
|
engine-verified facts (command exit codes, brief coverage, commit outcome)
|
|
448
448
|
appear in the verified section. Nothing in the claims section is ever
|
|
449
|
-
routed on.
|
|
449
|
+
routed on. The mechanical heading binds every failure it carries as a
|
|
450
|
+
required fix: command gates (test, restore) never write the notes channel,
|
|
451
|
+
so without that binding a retried dev agent has no required-fix trigger
|
|
452
|
+
(plan 065)."""
|
|
450
453
|
parts = [f"You are working on {subject}.\n", guide_section()]
|
|
451
454
|
for name, content in docs.items():
|
|
452
455
|
parts.append(f"## {name}\n\n{content}")
|
|
@@ -470,7 +473,8 @@ def build_context(runtime: Runtime, docs: dict[str, str], subject: str,
|
|
|
470
473
|
parts.extend(claims)
|
|
471
474
|
if mechanical_notes:
|
|
472
475
|
parts.append("## Mechanical gate output "
|
|
473
|
-
"(pipeline-captured process output, not agent claims
|
|
476
|
+
"(pipeline-captured process output, not agent claims; "
|
|
477
|
+
"each failure here is a required fix)")
|
|
474
478
|
parts.extend(mechanical_notes)
|
|
475
479
|
verified_lines = [f"- {name}: {fact}" for name, fact in (verified or {}).items()]
|
|
476
480
|
parts.append(
|
|
@@ -678,16 +682,11 @@ def build_brief_context(runtime: Runtime, step: StepConfig,
|
|
|
678
682
|
parts.append(
|
|
679
683
|
"## Coverage retry\n\n"
|
|
680
684
|
"The captured brief is missing the following required items. "
|
|
681
|
-
"Regenerate the digest so every listed item
|
|
682
|
-
"
|
|
683
|
-
"trailing colon and no content. Put the compressed content on "
|
|
684
|
-
"the following line:\n\n"
|
|
685
|
+
"Regenerate the digest so every listed item starts its own line; "
|
|
686
|
+
"compressed content may follow on that line or the next line.\n\n"
|
|
685
687
|
"- general_principles\n"
|
|
686
688
|
" Simplest thing that works; defer decisions to the last "
|
|
687
689
|
"responsible moment.\n\n"
|
|
688
|
-
"A line like `general_principles: Simplest thing that works; "
|
|
689
|
-
"...` does not satisfy coverage; the item must be the only "
|
|
690
|
-
"text on its line:\n\n"
|
|
691
690
|
+ coverage_note)
|
|
692
691
|
return "\n\n".join(parts)
|
|
693
692
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-dev-loop
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.4
|
|
4
4
|
Summary: Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.
|
|
5
5
|
Author: Luke Wilson
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,6 +29,8 @@ Requires-Dist: pydantic>=2.0
|
|
|
29
29
|
Requires-Dist: PyYAML>=6.0
|
|
30
30
|
Requires-Dist: openhands-sdk~=1.17.0
|
|
31
31
|
Requires-Dist: openhands-tools~=1.17.0
|
|
32
|
+
Requires-Dist: browser-use==0.11.13
|
|
33
|
+
Requires-Dist: pillow>=13.0.0
|
|
32
34
|
Requires-Dist: agent-client-protocol<1.0.0
|
|
33
35
|
Requires-Dist: langgraph>=1.2
|
|
34
36
|
Requires-Dist: langgraph-checkpoint-sqlite>=3.0
|
|
@@ -560,10 +562,11 @@ Conventions that make a good agent file:
|
|
|
560
562
|
- **dev enumerates its impossible set and stops at it.** List the commands
|
|
561
563
|
the sandbox cannot run (offline package fetches, browser downloads), one
|
|
562
564
|
attempt per command - keeps the productive loop and kills doomed retries.
|
|
563
|
-
- **Failure output
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
565
|
+
- **Failure output is a required fix in dev's next context.** Agent verdict
|
|
566
|
+
steps land their failing output under *Previous attempt feedback*; command
|
|
567
|
+
gates (test, restore) land it under *Mechanical gate output*, with the exit
|
|
568
|
+
code under *Verified state*. Steps route `on_fail: { goto: dev, retry: true }`,
|
|
569
|
+
and the dev prompt makes every listed failure a required fix.
|
|
567
570
|
- **No git mutations, ever.** The `commit` step is the single commit point.
|
|
568
571
|
|
|
569
572
|
### The pipeline file
|
|
@@ -142,6 +142,46 @@ class TestMissingAnchors:
|
|
|
142
142
|
["offline; never fetch"], SECTIONS) == []
|
|
143
143
|
|
|
144
144
|
|
|
145
|
+
def test_inline_anchor_content_line_passes(self):
|
|
146
|
+
text = _brief_ok().replace(
|
|
147
|
+
"**Error handling**\nNever fall back silently.\n\n",
|
|
148
|
+
"**Error handling**: Never fall back silently.\n\n")
|
|
149
|
+
assert missing_anchors(text, ["error handling", "mock policy"],
|
|
150
|
+
["offline; never fetch"], SECTIONS) == []
|
|
151
|
+
|
|
152
|
+
def test_em_dash_heading_transliterated_line_passes(self):
|
|
153
|
+
anchors = extract_anchors(
|
|
154
|
+
"## Default development mode \u2014 ask before coding\n")
|
|
155
|
+
assert anchors == ["default development mode - ask before coding"]
|
|
156
|
+
text = _brief_ok().replace(
|
|
157
|
+
"**Error handling**\nNever fall back silently.\n\n",
|
|
158
|
+
"**Default development mode - ask before coding**\n"
|
|
159
|
+
"Ask before writing code.\n\n")
|
|
160
|
+
assert missing_anchors(text, anchors, ["offline; never fetch"],
|
|
161
|
+
SECTIONS) == []
|
|
162
|
+
|
|
163
|
+
def test_curly_quote_heading_folded(self):
|
|
164
|
+
anchors = extract_anchors("## User\u2019s rules\n")
|
|
165
|
+
assert anchors == ["user's rules"]
|
|
166
|
+
text = _brief_ok().replace(
|
|
167
|
+
"**Error handling**\nNever fall back silently.\n\n",
|
|
168
|
+
"**User's rules**\nApply them.\n\n")
|
|
169
|
+
assert missing_anchors(text, anchors, ["offline; never fetch"],
|
|
170
|
+
SECTIONS) == []
|
|
171
|
+
|
|
172
|
+
def test_env_fact_em_dash_tolerated(self):
|
|
173
|
+
text = _brief_ok().replace("offline; never fetch",
|
|
174
|
+
"offline - never fetch")
|
|
175
|
+
assert missing_anchors(text, ["error handling", "mock policy"],
|
|
176
|
+
["offline \u2014 never fetch"], SECTIONS) == []
|
|
177
|
+
|
|
178
|
+
def test_env_fact_case_still_matters(self):
|
|
179
|
+
text = _brief_ok().replace("offline; never fetch",
|
|
180
|
+
"the build is efficient")
|
|
181
|
+
assert "CI" in missing_anchors(
|
|
182
|
+
text, ["error handling", "mock policy"], ["CI"], SECTIONS)
|
|
183
|
+
|
|
184
|
+
|
|
145
185
|
class TestCoverageNoteWording:
|
|
146
186
|
"""The retry note must state the line rule unambiguously (043): a
|
|
147
187
|
correction that the model can misread as "the item starts its own line"
|
|
@@ -154,11 +194,12 @@ class TestCoverageNoteWording:
|
|
|
154
194
|
runtime, runtime.cfg.steps[0], {"plan.md": "THE PLAN"},
|
|
155
195
|
coverage_note=note)
|
|
156
196
|
assert "## Coverage retry" in message
|
|
157
|
-
assert ("the
|
|
158
|
-
"content
|
|
197
|
+
assert ("Regenerate the digest so every listed item starts its own "
|
|
198
|
+
"line; compressed content may follow on that line or the next "
|
|
199
|
+
"line.") in message
|
|
159
200
|
assert "- general_principles\n Simplest thing that works" in message
|
|
160
|
-
assert "
|
|
161
|
-
assert "the
|
|
201
|
+
assert "the item alone on the line" not in message
|
|
202
|
+
assert "the only text on its line" not in message
|
|
162
203
|
assert note in message
|
|
163
204
|
|
|
164
205
|
def test_note_keeps_missing_items_verbatim(self, runtime):
|
|
@@ -29,3 +29,11 @@ class TestRenderBriefPrompt:
|
|
|
29
29
|
assert "`## Scope`" in prompt
|
|
30
30
|
assert "`## Risks`" in prompt
|
|
31
31
|
assert "Do not shorten or rename them" in prompt
|
|
32
|
+
|
|
33
|
+
def test_relaxed_contract_is_stated(self):
|
|
34
|
+
prompt = render_brief_prompt(SECTIONS)
|
|
35
|
+
assert "at the start of its own line" in prompt
|
|
36
|
+
assert "must be reproduced character-exact" in prompt
|
|
37
|
+
assert "never transliterate it" in prompt
|
|
38
|
+
assert "must appear at the start of their own lines" in prompt
|
|
39
|
+
assert "the only text on its line" not in prompt
|
|
@@ -56,8 +56,12 @@ def text_with_single_decision(draw):
|
|
|
56
56
|
|
|
57
57
|
@st.composite
|
|
58
58
|
def text_with_conflicting_decisions(draw):
|
|
59
|
-
first = draw(verdict_line.filter(
|
|
60
|
-
|
|
59
|
+
first = draw(verdict_line.filter(
|
|
60
|
+
lambda v: "PASS" in v.split(":", 1)[1]
|
|
61
|
+
and "FAIL" not in v.split(":", 1)[1]))
|
|
62
|
+
second = draw(verdict_line.filter(
|
|
63
|
+
lambda v: "FAIL" in v.split(":", 1)[1]
|
|
64
|
+
and "PASS" not in v.split(":", 1)[1]))
|
|
61
65
|
return f"{first}\n{second}"
|
|
62
66
|
|
|
63
67
|
|
|
@@ -8,6 +8,7 @@ instead of reading as a clean pass.
|
|
|
8
8
|
|
|
9
9
|
import dataclasses
|
|
10
10
|
import json
|
|
11
|
+
from pathlib import Path
|
|
11
12
|
from types import SimpleNamespace
|
|
12
13
|
|
|
13
14
|
import pytest
|
|
@@ -30,6 +31,7 @@ from agentic_dev_loop.engine.completion import (classify_completion,
|
|
|
30
31
|
count_actions)
|
|
31
32
|
from agentic_dev_loop.engine.dryrun import _validate_agents
|
|
32
33
|
from agentic_dev_loop.engine.graph import build_graph
|
|
34
|
+
from agentic_dev_loop.engine.onboarding.templates import load_template
|
|
33
35
|
from agentic_dev_loop.engine.provider_wire import (WireShapeError,
|
|
34
36
|
merge_choices,
|
|
35
37
|
validate_finish_shape,
|
|
@@ -450,7 +452,8 @@ class TestMechanicalOutputChannel:
|
|
|
450
452
|
verified=update["verified_state"])
|
|
451
453
|
claims = "## Stage artifacts (each agent's own claims, not verified)"
|
|
452
454
|
mechanical = ("## Mechanical gate output "
|
|
453
|
-
"(pipeline-captured process output, not agent claims
|
|
455
|
+
"(pipeline-captured process output, not agent claims; "
|
|
456
|
+
"each failure here is a required fix)")
|
|
454
457
|
verified = "## Verified state (mechanically checked by the pipeline)"
|
|
455
458
|
assert claims in ctx and mechanical in ctx
|
|
456
459
|
claims_section = ctx[ctx.index(claims):ctx.index(mechanical)]
|
|
@@ -463,6 +466,40 @@ class TestMechanicalOutputChannel:
|
|
|
463
466
|
ctx = build_context(runtime, {}, "s", notes=["agent prose note"])
|
|
464
467
|
assert "## Mechanical gate output" not in ctx
|
|
465
468
|
|
|
469
|
+
def test_mechanical_heading_binds_failures_as_required_fixes(self, runtime):
|
|
470
|
+
_rt, update = self._run_failing_command(runtime)
|
|
471
|
+
ctx = build_context(runtime, {}, "s",
|
|
472
|
+
mechanical_notes=update["mechanical_notes"],
|
|
473
|
+
verified=update["verified_state"])
|
|
474
|
+
heading = next(line for line in ctx.splitlines()
|
|
475
|
+
if line.startswith("## Mechanical gate output"))
|
|
476
|
+
assert "required fix" in heading
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
class TestDevAuditContract:
|
|
480
|
+
"""Plan 065: the dev prompt binds a failing mechanical or audit gate to
|
|
481
|
+
dev, and the two copies of the contract stay in sync."""
|
|
482
|
+
|
|
483
|
+
@staticmethod
|
|
484
|
+
def _texts():
|
|
485
|
+
repo = Path(__file__).parent.parent
|
|
486
|
+
return [
|
|
487
|
+
(repo / "agentic-dev-loop" / "sdk_agents" / "dev.agent.md")
|
|
488
|
+
.read_text(encoding="utf-8"),
|
|
489
|
+
load_template("dev.agent.md"),
|
|
490
|
+
]
|
|
491
|
+
|
|
492
|
+
def test_contract_names_both_required_fix_channels(self):
|
|
493
|
+
for text in self._texts():
|
|
494
|
+
assert "*Mechanical gate output*" in text
|
|
495
|
+
assert "*Previous attempt feedback*" in text
|
|
496
|
+
assert "failing output in your notes" not in text
|
|
497
|
+
|
|
498
|
+
def test_contract_has_an_audit_gate_section(self):
|
|
499
|
+
for text in self._texts():
|
|
500
|
+
assert "## AUDIT GATE" in text
|
|
501
|
+
assert "floor-pin" in text.lower()
|
|
502
|
+
|
|
466
503
|
|
|
467
504
|
class TestVerifiedStateAge:
|
|
468
505
|
"""m4: a verified fact carries the attempt that produced it, so attempt 1's
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/core/profiles/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/agent_error_guide.md
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/agent_error_guide.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/allowlist.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/completion.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/containers.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/copilot_auth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/egress_policy.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/egress_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/extensions/aidlc.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/forbidden.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/hostboundary.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/isolation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/checks.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/doctor.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/onboarding/init.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
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/provider_wire.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/run_status.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/seccomp/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/step_workspace.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/engine/sync_back.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/reporting/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/reporting/metrics.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/reporting/render.py
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop/reporting/sources.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{agentic_dev_loop-0.15.2 → agentic_dev_loop-0.15.4}/src/agentic_dev_loop.egg-info/top_level.txt
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
|
|
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
|
|
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
|