agentic-dev-loop 1.0.0a45__tar.gz → 1.0.0a46__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.
Potentially problematic release.
This version of agentic-dev-loop might be problematic. Click here for more details.
- {agentic_dev_loop-1.0.0a45/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a46}/PKG-INFO +28 -1
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/README.md +27 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/pyproject.toml +1 -1
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/core/config.py +13 -1
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/llm.py +14 -7
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/stages.py +10 -2
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46/src/agentic_dev_loop.egg-info}/PKG-INFO +28 -1
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_config.py +34 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_llm.py +40 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_publish.py +39 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_trigger_script.py +49 -4
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/LICENSE +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/setup.cfg +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/core/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/core/paths.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/core/results.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/core/verdict.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/actions.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/agent_error_guide.md +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/agent_error_guide.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/agents.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/allowlist.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/brief_coverage.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/brief_prompt.md +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/brief_prompt.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/cli.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/containers.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/deps.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/dryrun.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/forbidden.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/graph.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/isolation.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/loaders.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/mounts.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/outputs.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/presets.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/proc.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/registry.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/secrets.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/sync_back.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/py.typed +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/viz/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/viz/__main__.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/viz/server.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop.egg-info/SOURCES.txt +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop.egg-info/requires.txt +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_028_declared_caches.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_029_merge_on_conflict.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_033_brief_step.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_035_finalize_nudge.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_036_banned_commands_and_lane_boundary.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_041_brief_coverage.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_046_brief_prompt.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_actions.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_agent_error_guide.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_agents.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_aidlc.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_cli.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_containers.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_deps.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_dry_run.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_e2e_fixtures.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_graph.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_hostboundary_integration.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_isolation.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_isolation_integration.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_isolation_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_loaders.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_module_contract.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_outputs.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_outputs_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_proc.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_qa_prompt.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_registry.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_repo_ascii.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_results.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_sdk_compat.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_secrets.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_secrets_integration.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_secrets_pipeline.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_source_resolution.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_stages.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_sync_back.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_unit5_config.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_unit5_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_unit5_pure.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_verdict.py +0 -0
- {agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_viz.py +0 -0
{agentic_dev_loop-1.0.0a45/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a46}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-dev-loop
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0a46
|
|
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
|
|
@@ -199,6 +199,7 @@ llm:
|
|
|
199
199
|
model: openai/deepseek-v4-pro
|
|
200
200
|
base_url: https://api.deepseek.com
|
|
201
201
|
api_key_env: OPENAI_API_KEY
|
|
202
|
+
# reasoning_effort: medium # optional: low | medium | high | xhigh | none
|
|
202
203
|
|
|
203
204
|
max_attempts: 10 # CLI --max-attempts overrides
|
|
204
205
|
agents_dir: sdk_agents # your <name>.agent.md files
|
|
@@ -228,6 +229,7 @@ steps:
|
|
|
228
229
|
agent: review
|
|
229
230
|
artifact: review-findings.md
|
|
230
231
|
verdicts: { pass: APPROVED, fail: NEEDS CHANGES }
|
|
232
|
+
# reasoning_effort: xhigh # per-step override; falls back to the llm block, then SDK default
|
|
231
233
|
on_pass: qa
|
|
232
234
|
on_fail: { goto: dev, retry: true }
|
|
233
235
|
|
|
@@ -253,6 +255,7 @@ steps:
|
|
|
253
255
|
| `terminal_timeout:` | Optional agent-step per-action timeout in seconds (gt 0). `SandboxTerminalExecutor` uses it when the agent leaves the terminal action timeout unset, overriding the SDK tool's default. `None` = current behavior. |
|
|
254
256
|
| `finalize_nudge_turns:` | Optional agent-step final-response nudge (gt 0). Requires `max_iterations:` and must be less than it. At `max_iterations - finalize_nudge_turns` completed turns the engine injects one advisory turn ("`N turns remain: produce your final response now`"), exactly once; the agent may still exhaust its turns and existing stuck/unclear handling applies unchanged. Absent = current behavior. Provisional pending one consumer run (revert if noisy or the raised cap inflates cost). |
|
|
255
257
|
| `custom_prompt:` | Planned (planning-docs/040). Optional agent-step value: literal text, or a path whose file contents are read at load time, appended verbatim to the agent prompt at context assembly (after the prompt, before the task/artifacts). A value that looks like a path but names no file is a validation error. Agent steps only. |
|
|
258
|
+
| `reasoning_effort:` | Optional `low` / `medium` / `high` / `xhigh` / `none`. Set on the `llm` block (pipeline-global) or per-step (overrides the block). Unset anywhere = the field is not passed and the SDK default (`high`) applies, so today's behavior is unchanged. Forwarded only for models the SDK/LiteLLM mark as supporting it; an unsupported value fails at the first LLM call. See [Reasoning effort](#reasoning-effort-opt-in). |
|
|
256
259
|
| `on_pass:` / `on_fail:` | A step name, terminal `success`/`failure`, or `{goto: X, retry: true}`. No loops happen unless you write them. |
|
|
257
260
|
| `env:` / `setup:` / `network:` | `env:` declares step vars (fixed safe base + declared vars only); `setup:` provisions the sandbox before the step runs (command or agent steps; network ON; stamp-cached, re-runs when the pipeline's lockfiles change); `network: true` lets a command/agent step reach the hosts its `egress:` allowlist names (default off) - see [Per-stage networking](#per-stage-networking). |
|
|
258
261
|
| `setup_probe:` | Optional consumer-authored in-container probe run on a warm `setup:` stamp instead of the venv probe. Exit 0 trusts the stamp (skips); any nonzero re-provisions with network on (fail toward freshness). The probe text is NOT part of the stamp key, so a probe-only change needs `--refresh` or `--clean-stamps` to take effect. Example (asserting a warmed esbuild binary is Linux-shaped): `file frontend-editor/node_modules/esbuild/bin/esbuild | grep -q ELF`. |
|
|
@@ -266,6 +269,30 @@ steps:
|
|
|
266
269
|
| `caches:` / `sync_excludes:` | Top-level run-wide lists. `caches:` names repo-relative toolchain cache dirs bind-mounted rw from the real workspace (auto-created if missing); a `setup:` hook can warm them (the provision container carries the same cache mounts); `sync_excludes:` names scratch paths skipped from both the export copy and sync-back (wildcard `*` spans separators, so `**/bin/**` matches a `/bin/` segment at any depth). Both default to `[]`. See [docs/setup.md](docs/setup.md). |
|
|
267
270
|
| `merge_on_conflict:` | Top-level run-wide list of append-style logs (same path vocabulary as `sync_excludes:`, default `[]`). A concurrent host edit to a listed path is union-merged instead of raising: the host file wins and the sandbox's export-only lines are appended in order; both sides converge and the run continues. See [docs/setup.md](docs/setup.md). |
|
|
268
271
|
|
|
272
|
+
### Reasoning effort (opt-in)
|
|
273
|
+
|
|
274
|
+
`reasoning_effort` is an opt-in latency dial on the pipeline `llm` block and
|
|
275
|
+
on individual agent steps. It takes one of `low`, `medium`, `high`, `xhigh`,
|
|
276
|
+
or `none`; unset means the field is never passed and the SDK default
|
|
277
|
+
(`high`) applies, so a pipeline that omits it behaves exactly as before. A
|
|
278
|
+
step's value overrides the `llm` block's value, so the review lane can hold
|
|
279
|
+
a higher effort than the rest.
|
|
280
|
+
|
|
281
|
+
The value is forwarded only for models the SDK/LiteLLM mark as supporting
|
|
282
|
+
it; an unsupported value fails at the first LLM call (the schema rejects
|
|
283
|
+
unknown names at load time, but cannot know provider capability). No
|
|
284
|
+
pipeline ships a value: adopt one only after an observed run proves lower
|
|
285
|
+
per-turn latency with a green suite and no provider 400s.
|
|
286
|
+
|
|
287
|
+
Recommended lane defaults (guidance only, not enforced):
|
|
288
|
+
|
|
289
|
+
| Lane | reasoning_effort | Why |
|
|
290
|
+
| --- | --- | --- |
|
|
291
|
+
| brief | medium | digest and classify, no design work |
|
|
292
|
+
| dev | high | hold the line: dev caught a real plan bug and a real sandbox triage this unit |
|
|
293
|
+
| qa | medium | classification discipline must stay reliable |
|
|
294
|
+
| review | xhigh | shortest lane, highest stakes: a missed detection sails past the last gate into commit |
|
|
295
|
+
|
|
269
296
|
A `brief_inputs:` step is the per-run context-digestion pattern: it runs once at
|
|
270
297
|
run start (or when its inputs change), its `produces:` artifact survives attempt
|
|
271
298
|
starts, and the dev/review agents read that digest instead of re-deriving repo
|
|
@@ -155,6 +155,7 @@ llm:
|
|
|
155
155
|
model: openai/deepseek-v4-pro
|
|
156
156
|
base_url: https://api.deepseek.com
|
|
157
157
|
api_key_env: OPENAI_API_KEY
|
|
158
|
+
# reasoning_effort: medium # optional: low | medium | high | xhigh | none
|
|
158
159
|
|
|
159
160
|
max_attempts: 10 # CLI --max-attempts overrides
|
|
160
161
|
agents_dir: sdk_agents # your <name>.agent.md files
|
|
@@ -184,6 +185,7 @@ steps:
|
|
|
184
185
|
agent: review
|
|
185
186
|
artifact: review-findings.md
|
|
186
187
|
verdicts: { pass: APPROVED, fail: NEEDS CHANGES }
|
|
188
|
+
# reasoning_effort: xhigh # per-step override; falls back to the llm block, then SDK default
|
|
187
189
|
on_pass: qa
|
|
188
190
|
on_fail: { goto: dev, retry: true }
|
|
189
191
|
|
|
@@ -209,6 +211,7 @@ steps:
|
|
|
209
211
|
| `terminal_timeout:` | Optional agent-step per-action timeout in seconds (gt 0). `SandboxTerminalExecutor` uses it when the agent leaves the terminal action timeout unset, overriding the SDK tool's default. `None` = current behavior. |
|
|
210
212
|
| `finalize_nudge_turns:` | Optional agent-step final-response nudge (gt 0). Requires `max_iterations:` and must be less than it. At `max_iterations - finalize_nudge_turns` completed turns the engine injects one advisory turn ("`N turns remain: produce your final response now`"), exactly once; the agent may still exhaust its turns and existing stuck/unclear handling applies unchanged. Absent = current behavior. Provisional pending one consumer run (revert if noisy or the raised cap inflates cost). |
|
|
211
213
|
| `custom_prompt:` | Planned (planning-docs/040). Optional agent-step value: literal text, or a path whose file contents are read at load time, appended verbatim to the agent prompt at context assembly (after the prompt, before the task/artifacts). A value that looks like a path but names no file is a validation error. Agent steps only. |
|
|
214
|
+
| `reasoning_effort:` | Optional `low` / `medium` / `high` / `xhigh` / `none`. Set on the `llm` block (pipeline-global) or per-step (overrides the block). Unset anywhere = the field is not passed and the SDK default (`high`) applies, so today's behavior is unchanged. Forwarded only for models the SDK/LiteLLM mark as supporting it; an unsupported value fails at the first LLM call. See [Reasoning effort](#reasoning-effort-opt-in). |
|
|
212
215
|
| `on_pass:` / `on_fail:` | A step name, terminal `success`/`failure`, or `{goto: X, retry: true}`. No loops happen unless you write them. |
|
|
213
216
|
| `env:` / `setup:` / `network:` | `env:` declares step vars (fixed safe base + declared vars only); `setup:` provisions the sandbox before the step runs (command or agent steps; network ON; stamp-cached, re-runs when the pipeline's lockfiles change); `network: true` lets a command/agent step reach the hosts its `egress:` allowlist names (default off) - see [Per-stage networking](#per-stage-networking). |
|
|
214
217
|
| `setup_probe:` | Optional consumer-authored in-container probe run on a warm `setup:` stamp instead of the venv probe. Exit 0 trusts the stamp (skips); any nonzero re-provisions with network on (fail toward freshness). The probe text is NOT part of the stamp key, so a probe-only change needs `--refresh` or `--clean-stamps` to take effect. Example (asserting a warmed esbuild binary is Linux-shaped): `file frontend-editor/node_modules/esbuild/bin/esbuild | grep -q ELF`. |
|
|
@@ -222,6 +225,30 @@ steps:
|
|
|
222
225
|
| `caches:` / `sync_excludes:` | Top-level run-wide lists. `caches:` names repo-relative toolchain cache dirs bind-mounted rw from the real workspace (auto-created if missing); a `setup:` hook can warm them (the provision container carries the same cache mounts); `sync_excludes:` names scratch paths skipped from both the export copy and sync-back (wildcard `*` spans separators, so `**/bin/**` matches a `/bin/` segment at any depth). Both default to `[]`. See [docs/setup.md](docs/setup.md). |
|
|
223
226
|
| `merge_on_conflict:` | Top-level run-wide list of append-style logs (same path vocabulary as `sync_excludes:`, default `[]`). A concurrent host edit to a listed path is union-merged instead of raising: the host file wins and the sandbox's export-only lines are appended in order; both sides converge and the run continues. See [docs/setup.md](docs/setup.md). |
|
|
224
227
|
|
|
228
|
+
### Reasoning effort (opt-in)
|
|
229
|
+
|
|
230
|
+
`reasoning_effort` is an opt-in latency dial on the pipeline `llm` block and
|
|
231
|
+
on individual agent steps. It takes one of `low`, `medium`, `high`, `xhigh`,
|
|
232
|
+
or `none`; unset means the field is never passed and the SDK default
|
|
233
|
+
(`high`) applies, so a pipeline that omits it behaves exactly as before. A
|
|
234
|
+
step's value overrides the `llm` block's value, so the review lane can hold
|
|
235
|
+
a higher effort than the rest.
|
|
236
|
+
|
|
237
|
+
The value is forwarded only for models the SDK/LiteLLM mark as supporting
|
|
238
|
+
it; an unsupported value fails at the first LLM call (the schema rejects
|
|
239
|
+
unknown names at load time, but cannot know provider capability). No
|
|
240
|
+
pipeline ships a value: adopt one only after an observed run proves lower
|
|
241
|
+
per-turn latency with a green suite and no provider 400s.
|
|
242
|
+
|
|
243
|
+
Recommended lane defaults (guidance only, not enforced):
|
|
244
|
+
|
|
245
|
+
| Lane | reasoning_effort | Why |
|
|
246
|
+
| --- | --- | --- |
|
|
247
|
+
| brief | medium | digest and classify, no design work |
|
|
248
|
+
| dev | high | hold the line: dev caught a real plan bug and a real sandbox triage this unit |
|
|
249
|
+
| qa | medium | classification discipline must stay reliable |
|
|
250
|
+
| review | xhigh | shortest lane, highest stakes: a missed detection sails past the last gate into commit |
|
|
251
|
+
|
|
225
252
|
A `brief_inputs:` step is the per-run context-digestion pattern: it runs once at
|
|
226
253
|
run start (or when its inputs change), its `produces:` artifact survives attempt
|
|
227
254
|
starts, and the dev/review agents read that digest instead of re-deriving repo
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentic-dev-loop"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.0a46"
|
|
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"
|
|
@@ -6,7 +6,7 @@ import hashlib
|
|
|
6
6
|
import re
|
|
7
7
|
import warnings
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Any
|
|
9
|
+
from typing import Any, Literal
|
|
10
10
|
|
|
11
11
|
import yaml
|
|
12
12
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
@@ -35,6 +35,11 @@ DEFAULT_BRIEF_SECTIONS = [
|
|
|
35
35
|
"Open risks",
|
|
36
36
|
]
|
|
37
37
|
|
|
38
|
+
# 047: the full SDK reasoning_effort literal, passed through verbatim. The
|
|
39
|
+
# engine is provider-generic, so it validates shape only - whether a given
|
|
40
|
+
# provider accepts every value (notably "none") is operator risk (D3).
|
|
41
|
+
ReasoningEffort = Literal["low", "medium", "high", "xhigh", "none"]
|
|
42
|
+
|
|
38
43
|
|
|
39
44
|
def _validate_mount_path(path: str) -> str:
|
|
40
45
|
"""Validate one repo-relative mount path (BR-1.3).
|
|
@@ -385,6 +390,9 @@ class StepConfig(BaseModel):
|
|
|
385
390
|
terminal_timeout: float | None = Field(default=None, gt=0) # seconds, agent steps only (032)
|
|
386
391
|
finalize_nudge_turns: int | None = Field(default=None, gt=0) # agent steps only (035)
|
|
387
392
|
brief_inputs: BriefInputsSpec | None = None # agent steps only (033)
|
|
393
|
+
# 047 (D7): per-step opt-in override; unset falls back to the llm block,
|
|
394
|
+
# then the SDK default. Full SDK literal, passthrough semantics.
|
|
395
|
+
reasoning_effort: ReasoningEffort | None = None
|
|
388
396
|
custom_prompt: str | None = None # agent steps only (040); file path resolved at load
|
|
389
397
|
env: dict[str, str | None] | None = None # NFR-1: null = inherit host value
|
|
390
398
|
setup: str | None = None # BR-13: command steps only
|
|
@@ -552,6 +560,10 @@ class LlmConfig(BaseModel):
|
|
|
552
560
|
base_url: str | None = None
|
|
553
561
|
api_key_env: str
|
|
554
562
|
timeout: float | None = None # omitted → opinionated no-timeout default
|
|
563
|
+
# 047 (D1): opt-in passthrough; unset means the field is not passed at
|
|
564
|
+
# all, so the SDK default ("high") applies and today's behavior is
|
|
565
|
+
# byte-identical. No default may move without an observed run (D6).
|
|
566
|
+
reasoning_effort: ReasoningEffort | None = None
|
|
555
567
|
|
|
556
568
|
|
|
557
569
|
class PipelineConfig(BaseModel):
|
|
@@ -48,13 +48,20 @@ if not getattr(_ORIGINAL_FORMAT_MESSAGES, "_agentic_dev_loop_reasoning_repair",
|
|
|
48
48
|
LLM.format_messages_for_llm = _repair_reasoning_passback
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def build_llm(cfg: LlmConfig) -> LLM:
|
|
51
|
+
def build_llm(cfg: LlmConfig, reasoning_effort: str | None = None) -> LLM:
|
|
52
52
|
api_key = os.environ.get(cfg.api_key_env)
|
|
53
53
|
if not api_key:
|
|
54
54
|
raise RuntimeError(f"{cfg.api_key_env} environment variable is required")
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
# 047 (D2/D7): an explicit per-step override wins, else the llm block's
|
|
56
|
+
# value applies, else the field is omitted entirely and the SDK default
|
|
57
|
+
# ("high") is in force. The reasoning_content shims above stay untouched.
|
|
58
|
+
effort = reasoning_effort if reasoning_effort is not None else cfg.reasoning_effort
|
|
59
|
+
kwargs = {
|
|
60
|
+
"model": cfg.model,
|
|
61
|
+
"api_key": api_key,
|
|
62
|
+
"base_url": cfg.base_url,
|
|
63
|
+
"timeout": cfg.timeout, # policy: no LLM timeout unless explicitly set
|
|
64
|
+
}
|
|
65
|
+
if effort is not None:
|
|
66
|
+
kwargs["reasoning_effort"] = effort
|
|
67
|
+
return LLM(**kwargs)
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/stages.py
RENAMED
|
@@ -42,6 +42,7 @@ from .egress_policy import assemble_egress_policy
|
|
|
42
42
|
from .forbidden import resolve_forbidden_rules
|
|
43
43
|
from .isolation import (SandboxError, SandboxExecutionRequest, command_argv,
|
|
44
44
|
resolve_sandbox_env)
|
|
45
|
+
from .llm import build_llm
|
|
45
46
|
from .mounts import resolve_mount_set
|
|
46
47
|
from .outputs import CapturedOutput
|
|
47
48
|
from .secrets import redact_values, step_secret_env
|
|
@@ -174,11 +175,18 @@ class Runtime:
|
|
|
174
175
|
if step is not None else None),
|
|
175
176
|
forbidden_commands=forbidden_commands,
|
|
176
177
|
allowlist=allowlist)
|
|
178
|
+
# 047 (D7): a step's reasoning_effort overrides the llm block's;
|
|
179
|
+
# self.llm already carries the block value (or the SDK default),
|
|
180
|
+
# so only build a fresh LLM when the step overrides it.
|
|
181
|
+
llm = self.llm
|
|
182
|
+
if step is not None and step.reasoning_effort is not None:
|
|
183
|
+
llm = build_llm(self.cfg.llm,
|
|
184
|
+
reasoning_effort=step.reasoning_effort)
|
|
177
185
|
if step is not None and step.brief_inputs is not None:
|
|
178
186
|
agent = load_brief_agent(
|
|
179
|
-
agent_name, step.brief_inputs.sections,
|
|
187
|
+
agent_name, step.brief_inputs.sections, llm)
|
|
180
188
|
else:
|
|
181
|
-
agent = load_agent(self.agents_dir, agent_name,
|
|
189
|
+
agent = load_agent(self.agents_dir, agent_name, llm)
|
|
182
190
|
callbacks = []
|
|
183
191
|
if finalize_controller is not None:
|
|
184
192
|
callbacks.append(finalize_controller.on_event)
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46/src/agentic_dev_loop.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-dev-loop
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0a46
|
|
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
|
|
@@ -199,6 +199,7 @@ llm:
|
|
|
199
199
|
model: openai/deepseek-v4-pro
|
|
200
200
|
base_url: https://api.deepseek.com
|
|
201
201
|
api_key_env: OPENAI_API_KEY
|
|
202
|
+
# reasoning_effort: medium # optional: low | medium | high | xhigh | none
|
|
202
203
|
|
|
203
204
|
max_attempts: 10 # CLI --max-attempts overrides
|
|
204
205
|
agents_dir: sdk_agents # your <name>.agent.md files
|
|
@@ -228,6 +229,7 @@ steps:
|
|
|
228
229
|
agent: review
|
|
229
230
|
artifact: review-findings.md
|
|
230
231
|
verdicts: { pass: APPROVED, fail: NEEDS CHANGES }
|
|
232
|
+
# reasoning_effort: xhigh # per-step override; falls back to the llm block, then SDK default
|
|
231
233
|
on_pass: qa
|
|
232
234
|
on_fail: { goto: dev, retry: true }
|
|
233
235
|
|
|
@@ -253,6 +255,7 @@ steps:
|
|
|
253
255
|
| `terminal_timeout:` | Optional agent-step per-action timeout in seconds (gt 0). `SandboxTerminalExecutor` uses it when the agent leaves the terminal action timeout unset, overriding the SDK tool's default. `None` = current behavior. |
|
|
254
256
|
| `finalize_nudge_turns:` | Optional agent-step final-response nudge (gt 0). Requires `max_iterations:` and must be less than it. At `max_iterations - finalize_nudge_turns` completed turns the engine injects one advisory turn ("`N turns remain: produce your final response now`"), exactly once; the agent may still exhaust its turns and existing stuck/unclear handling applies unchanged. Absent = current behavior. Provisional pending one consumer run (revert if noisy or the raised cap inflates cost). |
|
|
255
257
|
| `custom_prompt:` | Planned (planning-docs/040). Optional agent-step value: literal text, or a path whose file contents are read at load time, appended verbatim to the agent prompt at context assembly (after the prompt, before the task/artifacts). A value that looks like a path but names no file is a validation error. Agent steps only. |
|
|
258
|
+
| `reasoning_effort:` | Optional `low` / `medium` / `high` / `xhigh` / `none`. Set on the `llm` block (pipeline-global) or per-step (overrides the block). Unset anywhere = the field is not passed and the SDK default (`high`) applies, so today's behavior is unchanged. Forwarded only for models the SDK/LiteLLM mark as supporting it; an unsupported value fails at the first LLM call. See [Reasoning effort](#reasoning-effort-opt-in). |
|
|
256
259
|
| `on_pass:` / `on_fail:` | A step name, terminal `success`/`failure`, or `{goto: X, retry: true}`. No loops happen unless you write them. |
|
|
257
260
|
| `env:` / `setup:` / `network:` | `env:` declares step vars (fixed safe base + declared vars only); `setup:` provisions the sandbox before the step runs (command or agent steps; network ON; stamp-cached, re-runs when the pipeline's lockfiles change); `network: true` lets a command/agent step reach the hosts its `egress:` allowlist names (default off) - see [Per-stage networking](#per-stage-networking). |
|
|
258
261
|
| `setup_probe:` | Optional consumer-authored in-container probe run on a warm `setup:` stamp instead of the venv probe. Exit 0 trusts the stamp (skips); any nonzero re-provisions with network on (fail toward freshness). The probe text is NOT part of the stamp key, so a probe-only change needs `--refresh` or `--clean-stamps` to take effect. Example (asserting a warmed esbuild binary is Linux-shaped): `file frontend-editor/node_modules/esbuild/bin/esbuild | grep -q ELF`. |
|
|
@@ -266,6 +269,30 @@ steps:
|
|
|
266
269
|
| `caches:` / `sync_excludes:` | Top-level run-wide lists. `caches:` names repo-relative toolchain cache dirs bind-mounted rw from the real workspace (auto-created if missing); a `setup:` hook can warm them (the provision container carries the same cache mounts); `sync_excludes:` names scratch paths skipped from both the export copy and sync-back (wildcard `*` spans separators, so `**/bin/**` matches a `/bin/` segment at any depth). Both default to `[]`. See [docs/setup.md](docs/setup.md). |
|
|
267
270
|
| `merge_on_conflict:` | Top-level run-wide list of append-style logs (same path vocabulary as `sync_excludes:`, default `[]`). A concurrent host edit to a listed path is union-merged instead of raising: the host file wins and the sandbox's export-only lines are appended in order; both sides converge and the run continues. See [docs/setup.md](docs/setup.md). |
|
|
268
271
|
|
|
272
|
+
### Reasoning effort (opt-in)
|
|
273
|
+
|
|
274
|
+
`reasoning_effort` is an opt-in latency dial on the pipeline `llm` block and
|
|
275
|
+
on individual agent steps. It takes one of `low`, `medium`, `high`, `xhigh`,
|
|
276
|
+
or `none`; unset means the field is never passed and the SDK default
|
|
277
|
+
(`high`) applies, so a pipeline that omits it behaves exactly as before. A
|
|
278
|
+
step's value overrides the `llm` block's value, so the review lane can hold
|
|
279
|
+
a higher effort than the rest.
|
|
280
|
+
|
|
281
|
+
The value is forwarded only for models the SDK/LiteLLM mark as supporting
|
|
282
|
+
it; an unsupported value fails at the first LLM call (the schema rejects
|
|
283
|
+
unknown names at load time, but cannot know provider capability). No
|
|
284
|
+
pipeline ships a value: adopt one only after an observed run proves lower
|
|
285
|
+
per-turn latency with a green suite and no provider 400s.
|
|
286
|
+
|
|
287
|
+
Recommended lane defaults (guidance only, not enforced):
|
|
288
|
+
|
|
289
|
+
| Lane | reasoning_effort | Why |
|
|
290
|
+
| --- | --- | --- |
|
|
291
|
+
| brief | medium | digest and classify, no design work |
|
|
292
|
+
| dev | high | hold the line: dev caught a real plan bug and a real sandbox triage this unit |
|
|
293
|
+
| qa | medium | classification discipline must stay reliable |
|
|
294
|
+
| review | xhigh | shortest lane, highest stakes: a missed detection sails past the last gate into commit |
|
|
295
|
+
|
|
269
296
|
A `brief_inputs:` step is the per-run context-digestion pattern: it runs once at
|
|
270
297
|
run start (or when its inputs change), its `produces:` artifact survives attempt
|
|
271
298
|
starts, and the dev/review agents read that digest instead of re-deriving repo
|
|
@@ -180,6 +180,40 @@ def test_extra_body_llm_key_rejected(tmp_path):
|
|
|
180
180
|
_load(tmp_path, data)
|
|
181
181
|
|
|
182
182
|
|
|
183
|
+
def test_llm_reasoning_effort_round_trips(tmp_path):
|
|
184
|
+
data = _base()
|
|
185
|
+
data["llm"]["reasoning_effort"] = "medium"
|
|
186
|
+
assert _load(tmp_path, data).llm.reasoning_effort == "medium"
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_llm_reasoning_effort_defaults_none(tmp_path):
|
|
190
|
+
assert _load(tmp_path, _base()).llm.reasoning_effort is None
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_llm_reasoning_effort_unknown_value_rejected(tmp_path):
|
|
194
|
+
data = _base()
|
|
195
|
+
data["llm"]["reasoning_effort"] = "maximum"
|
|
196
|
+
with pytest.raises(ValidationError):
|
|
197
|
+
_load(tmp_path, data)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def test_step_reasoning_effort_round_trips(tmp_path):
|
|
201
|
+
data = _base()
|
|
202
|
+
data["steps"][0]["reasoning_effort"] = "xhigh"
|
|
203
|
+
assert _load(tmp_path, data).steps[0].reasoning_effort == "xhigh"
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def test_step_reasoning_effort_defaults_none(tmp_path):
|
|
207
|
+
assert _load(tmp_path, _base()).steps[0].reasoning_effort is None
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_step_reasoning_effort_unknown_value_rejected(tmp_path):
|
|
211
|
+
data = _base()
|
|
212
|
+
data["steps"][0]["reasoning_effort"] = "banana"
|
|
213
|
+
with pytest.raises(ValidationError):
|
|
214
|
+
_load(tmp_path, data)
|
|
215
|
+
|
|
216
|
+
|
|
183
217
|
def test_unknown_route_key_rejected(tmp_path):
|
|
184
218
|
data = _base()
|
|
185
219
|
data["steps"][0]["on_pass"] = {"goto": "success", "bogus": 1}
|
|
@@ -43,6 +43,46 @@ class TestBuildLlm:
|
|
|
43
43
|
|
|
44
44
|
assert mock_cls.call_args.kwargs["timeout"] == 30
|
|
45
45
|
|
|
46
|
+
def test_reasoning_effort_omitted_when_unset(self, monkeypatch):
|
|
47
|
+
monkeypatch.setenv(KEY, "sk-test")
|
|
48
|
+
with patch("agentic_dev_loop.engine.llm.LLM") as mock_cls:
|
|
49
|
+
build_llm(_cfg())
|
|
50
|
+
|
|
51
|
+
assert "reasoning_effort" not in mock_cls.call_args.kwargs
|
|
52
|
+
|
|
53
|
+
def test_reasoning_effort_passed_through_when_set(self, monkeypatch):
|
|
54
|
+
monkeypatch.setenv(KEY, "sk-test")
|
|
55
|
+
with patch("agentic_dev_loop.engine.llm.LLM") as mock_cls:
|
|
56
|
+
build_llm(_cfg(reasoning_effort="medium"))
|
|
57
|
+
|
|
58
|
+
assert mock_cls.call_args.kwargs["reasoning_effort"] == "medium"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TestReasoningEffortResolution:
|
|
62
|
+
"""D7: the step's value wins, else the llm block's value, else unset
|
|
63
|
+
(the SDK default "high" applies)."""
|
|
64
|
+
|
|
65
|
+
def test_step_override_wins_over_block(self, monkeypatch):
|
|
66
|
+
monkeypatch.setenv(KEY, "sk-test")
|
|
67
|
+
with patch("agentic_dev_loop.engine.llm.LLM") as mock_cls:
|
|
68
|
+
build_llm(_cfg(reasoning_effort="low"), reasoning_effort="xhigh")
|
|
69
|
+
|
|
70
|
+
assert mock_cls.call_args.kwargs["reasoning_effort"] == "xhigh"
|
|
71
|
+
|
|
72
|
+
def test_block_value_applies_without_step_override(self, monkeypatch):
|
|
73
|
+
monkeypatch.setenv(KEY, "sk-test")
|
|
74
|
+
with patch("agentic_dev_loop.engine.llm.LLM") as mock_cls:
|
|
75
|
+
build_llm(_cfg(reasoning_effort="medium"))
|
|
76
|
+
|
|
77
|
+
assert mock_cls.call_args.kwargs["reasoning_effort"] == "medium"
|
|
78
|
+
|
|
79
|
+
def test_unset_everywhere_omits_the_field(self, monkeypatch):
|
|
80
|
+
monkeypatch.setenv(KEY, "sk-test")
|
|
81
|
+
with patch("agentic_dev_loop.engine.llm.LLM") as mock_cls:
|
|
82
|
+
build_llm(_cfg())
|
|
83
|
+
|
|
84
|
+
assert "reasoning_effort" not in mock_cls.call_args.kwargs
|
|
85
|
+
|
|
46
86
|
|
|
47
87
|
class TestReasoningContentShim:
|
|
48
88
|
"""DeepSeek thinking mode 400s on multi-turn requests unless prior
|
|
@@ -226,6 +226,45 @@ class TestChangelog:
|
|
|
226
226
|
assert read_version(repo) == "0.2.0"
|
|
227
227
|
|
|
228
228
|
|
|
229
|
+
class TestConsumerAdoption:
|
|
230
|
+
def test_marker_without_adoption_section_fails(self, tmp_path):
|
|
231
|
+
repo, _ = make_repo(
|
|
232
|
+
tmp_path,
|
|
233
|
+
unreleased=(
|
|
234
|
+
"### Changed\n\n"
|
|
235
|
+
"- feat: construct plan 031-qa-environmental-verdict.md\n"
|
|
236
|
+
),
|
|
237
|
+
)
|
|
238
|
+
proc = run_publish(repo, "--patch")
|
|
239
|
+
assert proc.returncode != 0
|
|
240
|
+
assert "Consumer adoption" in proc.stderr
|
|
241
|
+
assert read_version(repo) == "0.2.0"
|
|
242
|
+
assert tags(repo) == []
|
|
243
|
+
|
|
244
|
+
def test_marker_with_adoption_section_passes(self, tmp_path):
|
|
245
|
+
repo, _ = make_repo(
|
|
246
|
+
tmp_path,
|
|
247
|
+
unreleased=(
|
|
248
|
+
"### Changed\n\n"
|
|
249
|
+
"- feat: construct plan 031-qa-environmental-verdict.md\n\n"
|
|
250
|
+
"### Consumer adoption\n\n"
|
|
251
|
+
"- qa verdict steps must add `env: ENV` to their verdicts map\n"
|
|
252
|
+
),
|
|
253
|
+
)
|
|
254
|
+
proc = run_publish(repo, "--patch")
|
|
255
|
+
assert proc.returncode == 0, proc.stderr
|
|
256
|
+
assert read_version(repo) == "0.2.1"
|
|
257
|
+
|
|
258
|
+
def test_no_marker_passes_without_section(self, tmp_path):
|
|
259
|
+
repo, _ = make_repo(
|
|
260
|
+
tmp_path,
|
|
261
|
+
unreleased="### Changed\n\n- feat: add kernel sandbox\n",
|
|
262
|
+
)
|
|
263
|
+
proc = run_publish(repo, "--patch")
|
|
264
|
+
assert proc.returncode == 0, proc.stderr
|
|
265
|
+
assert read_version(repo) == "0.2.1"
|
|
266
|
+
|
|
267
|
+
|
|
229
268
|
class TestGitOps:
|
|
230
269
|
def test_commit_tag_and_push(self, tmp_path):
|
|
231
270
|
repo, bare = make_repo(tmp_path)
|
|
@@ -109,8 +109,8 @@ def test_trigger_rejects_both_flags(tmp_path):
|
|
|
109
109
|
env=_env_with(bin_dir))
|
|
110
110
|
|
|
111
111
|
assert result.returncode != 0
|
|
112
|
-
assert ("pass exactly one of --plan <path
|
|
113
|
-
"
|
|
112
|
+
assert ("pass exactly one of --plan <path>, --aidlc-unit <slug>, or "
|
|
113
|
+
"--resume <thread-id>") in result.stderr
|
|
114
114
|
assert "cli-ran:" not in result.stdout
|
|
115
115
|
|
|
116
116
|
|
|
@@ -120,8 +120,8 @@ def test_trigger_requires_exactly_one_flag(tmp_path):
|
|
|
120
120
|
result = _run_script(env=_env_with(bin_dir))
|
|
121
121
|
|
|
122
122
|
assert result.returncode != 0
|
|
123
|
-
assert ("pass exactly one of --plan <path
|
|
124
|
-
in result.stderr
|
|
123
|
+
assert ("pass exactly one of --plan <path>, --aidlc-unit <slug>, or "
|
|
124
|
+
"--resume <thread-id>") in result.stderr
|
|
125
125
|
assert "cli-ran:" not in result.stdout
|
|
126
126
|
|
|
127
127
|
|
|
@@ -135,6 +135,51 @@ def test_trigger_forwards_aidlc_unit(tmp_path):
|
|
|
135
135
|
assert "--aidlc-unit unit-3" in result.stdout
|
|
136
136
|
|
|
137
137
|
|
|
138
|
+
def test_trigger_forwards_resume(tmp_path):
|
|
139
|
+
bin_dir = _stub_env(tmp_path)
|
|
140
|
+
|
|
141
|
+
result = _run_script("--resume", "07a767a50de64529ac442759b3685a78",
|
|
142
|
+
env=_env_with(bin_dir))
|
|
143
|
+
|
|
144
|
+
assert result.returncode == 0, result.stderr
|
|
145
|
+
assert "cli-ran:" in result.stdout
|
|
146
|
+
assert "--resume 07a767a50de64529ac442759b3685a78" in result.stdout
|
|
147
|
+
assert "--plan" not in result.stdout
|
|
148
|
+
assert "--aidlc-unit" not in result.stdout
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_trigger_resume_equals_form(tmp_path):
|
|
152
|
+
bin_dir = _stub_env(tmp_path)
|
|
153
|
+
|
|
154
|
+
result = _run_script("--resume=07a767a50de64529ac442759b3685a78",
|
|
155
|
+
env=_env_with(bin_dir))
|
|
156
|
+
|
|
157
|
+
assert result.returncode == 0, result.stderr
|
|
158
|
+
assert "--resume 07a767a50de64529ac442759b3685a78" in result.stdout
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_trigger_resume_missing_value_is_usage_error(tmp_path):
|
|
162
|
+
bin_dir = _stub_env(tmp_path)
|
|
163
|
+
|
|
164
|
+
result = _run_script("--resume", env=_env_with(bin_dir))
|
|
165
|
+
|
|
166
|
+
assert result.returncode != 0
|
|
167
|
+
assert "--resume requires a thread id" in result.stderr
|
|
168
|
+
assert "cli-ran:" not in result.stdout
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_trigger_rejects_resume_with_plan(tmp_path):
|
|
172
|
+
bin_dir = _stub_env(tmp_path)
|
|
173
|
+
|
|
174
|
+
result = _run_script("--resume", "abc123", "--plan", "plan.md",
|
|
175
|
+
env=_env_with(bin_dir))
|
|
176
|
+
|
|
177
|
+
assert result.returncode != 0
|
|
178
|
+
assert ("pass exactly one of --plan <path>, --aidlc-unit <slug>, or "
|
|
179
|
+
"--resume <thread-id>") in result.stderr
|
|
180
|
+
assert "cli-ran:" not in result.stdout
|
|
181
|
+
|
|
182
|
+
|
|
138
183
|
def test_trigger_unit_positional_is_aidlc_shorthand(tmp_path):
|
|
139
184
|
bin_dir = _stub_env(tmp_path)
|
|
140
185
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/core/results.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/core/verdict.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/actions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/agents.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/allowlist.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/brief_prompt.md
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/brief_prompt.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/containers.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/dryrun.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/egress_policy.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/egress_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/forbidden.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/graph.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/hostboundary.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/isolation.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/loaders.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/mounts.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/outputs.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/presets.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/secrets.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/engine/sync_back.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/viz/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop/viz/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/src/agentic_dev_loop.egg-info/requires.txt
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/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
|
{agentic_dev_loop-1.0.0a45 → agentic_dev_loop-1.0.0a46}/tests/test_hostboundary_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
|
|
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
|