agentic-dev-loop 1.0.0a44__tar.gz → 1.0.0a45__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.0a44/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a45}/PKG-INFO +10 -8
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/README.md +9 -7
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/pyproject.toml +1 -1
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/core/config.py +27 -1
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/agents.py +19 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/brief_coverage.py +7 -18
- agentic_dev_loop-1.0.0a45/src/agentic_dev_loop/engine/brief_prompt.md +46 -0
- agentic_dev_loop-1.0.0a45/src/agentic_dev_loop/engine/brief_prompt.py +47 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/dryrun.py +9 -5
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/stages.py +35 -5
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45/src/agentic_dev_loop.egg-info}/PKG-INFO +10 -8
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop.egg-info/SOURCES.txt +3 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_033_brief_step.py +44 -6
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_041_brief_coverage.py +27 -16
- agentic_dev_loop-1.0.0a45/tests/test_046_brief_prompt.py +45 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_agents.py +20 -1
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_e2e_fixtures.py +1 -1
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/LICENSE +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/setup.cfg +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/core/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/core/paths.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/core/results.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/core/verdict.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/actions.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/agent_error_guide.md +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/agent_error_guide.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/allowlist.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/cli.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/containers.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/deps.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/forbidden.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/graph.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/isolation.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/llm.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/loaders.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/mounts.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/outputs.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/presets.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/proc.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/registry.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/secrets.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/sync_back.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/py.typed +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/viz/__init__.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/viz/__main__.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/viz/server.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop.egg-info/requires.txt +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_028_declared_caches.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_029_merge_on_conflict.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_035_finalize_nudge.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_036_banned_commands_and_lane_boundary.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_actions.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_agent_error_guide.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_aidlc.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_cli.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_config.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_containers.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_deps.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_dry_run.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_egress_proxy.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_graph.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_hostboundary.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_hostboundary_integration.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_isolation.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_isolation_integration.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_isolation_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_llm.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_loaders.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_module_contract.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_outputs.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_outputs_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_proc.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_publish.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_qa_prompt.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_registry.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_repo_ascii.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_results.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_sdk_compat.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_secrets.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_secrets_integration.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_secrets_pipeline.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_source_resolution.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_stages.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_step_workspace.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_sync_back.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_trigger_script.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_unit5_config.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_unit5_pbt.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_unit5_pure.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_verdict.py +0 -0
- {agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/tests/test_viz.py +0 -0
{agentic_dev_loop-1.0.0a44/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a45}/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.0a45
|
|
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
|
|
@@ -249,7 +249,7 @@ steps:
|
|
|
249
249
|
| --- | --- |
|
|
250
250
|
| `agent:` / `command:` / `action:` | Exactly one per step. Agents live in `agents_dir` as `<name>.agent.md`; commands run sandboxed (mechanical, never an LLM call). `commit` is the sole host-side built-in action; consumer actions are sandbox-executed, command-shaped scripts (see [Host boundary](#host-boundary-security-model)). |
|
|
251
251
|
| `produces:` / `artifact:` + `verdicts:` | Hygiene-tracked outputs vs verdict-parsed routing. The **last** `VERDICT:` line wins; stale artifacts are deleted at each attempt start. |
|
|
252
|
-
| `brief_inputs:` | Optional agent-step input spec: `{ include: [<paths/globs>], env_facts: [<strings>] }`. The engine resolves the include list against the workspace, passes the resolved docs + include contents + env facts as that step's task message, and regenerates the step only when those inputs change. A produces-only agent step such as `brief` is the documented pattern for per-run context digestion. |
|
|
252
|
+
| `brief_inputs:` | Optional agent-step input spec: `{ include: [<paths/globs>], env_facts: [<strings>], sections: [<headings>] }`. The engine resolves the include list against the workspace, passes the resolved docs + include contents + env facts as that step's task message, and regenerates the step only when those inputs change. `sections` is the ordered list of digest headings the brief must emit (default `[Repo rules digest, Unit scope digest, Environment facts, Open risks]`; non-empty and unique). A produces-only agent step such as `brief` is the documented pattern for per-run context digestion. |
|
|
253
253
|
| `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
254
|
| `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
255
|
| `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. |
|
|
@@ -271,12 +271,14 @@ run start (or when its inputs change), its `produces:` artifact survives attempt
|
|
|
271
271
|
starts, and the dev/review agents read that digest instead of re-deriving repo
|
|
272
272
|
rules and environment facts every attempt.
|
|
273
273
|
|
|
274
|
-
The brief digest is mechanically coverage-checked: the
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
274
|
+
The brief digest is mechanically coverage-checked: the configured
|
|
275
|
+
`brief_inputs.sections` headings must each appear on their own line, every
|
|
276
|
+
anchor extracted from the `include` files (markdown `##` headings, and YAML
|
|
277
|
+
category names plus `enforcement_levels`) must appear on its own line
|
|
278
|
+
(case-insensitive, whitespace-collapsed, `**` decoration allowed), and every
|
|
279
|
+
`env_facts` entry must appear verbatim. The section list feeds both the
|
|
280
|
+
engine-embedded brief prompt and the coverage gate, so the two can never
|
|
281
|
+
disagree; a miss
|
|
280
282
|
re-runs the brief agent once per missing set with a `## Coverage retry`
|
|
281
283
|
correction note, bounded to three retries per input set; if the same items are
|
|
282
284
|
still dropped after the cap, the run fails and `last-error.md` names the
|
|
@@ -205,7 +205,7 @@ steps:
|
|
|
205
205
|
| --- | --- |
|
|
206
206
|
| `agent:` / `command:` / `action:` | Exactly one per step. Agents live in `agents_dir` as `<name>.agent.md`; commands run sandboxed (mechanical, never an LLM call). `commit` is the sole host-side built-in action; consumer actions are sandbox-executed, command-shaped scripts (see [Host boundary](#host-boundary-security-model)). |
|
|
207
207
|
| `produces:` / `artifact:` + `verdicts:` | Hygiene-tracked outputs vs verdict-parsed routing. The **last** `VERDICT:` line wins; stale artifacts are deleted at each attempt start. |
|
|
208
|
-
| `brief_inputs:` | Optional agent-step input spec: `{ include: [<paths/globs>], env_facts: [<strings>] }`. The engine resolves the include list against the workspace, passes the resolved docs + include contents + env facts as that step's task message, and regenerates the step only when those inputs change. A produces-only agent step such as `brief` is the documented pattern for per-run context digestion. |
|
|
208
|
+
| `brief_inputs:` | Optional agent-step input spec: `{ include: [<paths/globs>], env_facts: [<strings>], sections: [<headings>] }`. The engine resolves the include list against the workspace, passes the resolved docs + include contents + env facts as that step's task message, and regenerates the step only when those inputs change. `sections` is the ordered list of digest headings the brief must emit (default `[Repo rules digest, Unit scope digest, Environment facts, Open risks]`; non-empty and unique). A produces-only agent step such as `brief` is the documented pattern for per-run context digestion. |
|
|
209
209
|
| `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
210
|
| `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
211
|
| `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. |
|
|
@@ -227,12 +227,14 @@ run start (or when its inputs change), its `produces:` artifact survives attempt
|
|
|
227
227
|
starts, and the dev/review agents read that digest instead of re-deriving repo
|
|
228
228
|
rules and environment facts every attempt.
|
|
229
229
|
|
|
230
|
-
The brief digest is mechanically coverage-checked: the
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
The brief digest is mechanically coverage-checked: the configured
|
|
231
|
+
`brief_inputs.sections` headings must each appear on their own line, every
|
|
232
|
+
anchor extracted from the `include` files (markdown `##` headings, and YAML
|
|
233
|
+
category names plus `enforcement_levels`) must appear on its own line
|
|
234
|
+
(case-insensitive, whitespace-collapsed, `**` decoration allowed), and every
|
|
235
|
+
`env_facts` entry must appear verbatim. The section list feeds both the
|
|
236
|
+
engine-embedded brief prompt and the coverage gate, so the two can never
|
|
237
|
+
disagree; a miss
|
|
236
238
|
re-runs the brief agent once per missing set with a `## Coverage retry`
|
|
237
239
|
correction note, bounded to three retries per input set; if the same items are
|
|
238
240
|
still dropped after the cap, the run fails and `last-error.md` names the
|
|
@@ -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.0a45"
|
|
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"
|
|
@@ -25,6 +25,16 @@ HOST_ONLY_MOUNT_DIRS = frozenset({".venv"})
|
|
|
25
25
|
KNOWN_EGRESS_PRESETS = frozenset({"package-registries"})
|
|
26
26
|
EGRESS_CLASSES = frozenset({"allowlist", "browser"})
|
|
27
27
|
|
|
28
|
+
# The neutral default section headings a brief step must emit (046). A
|
|
29
|
+
# consumer overrides them via `brief_inputs.sections`; the coverage gate
|
|
30
|
+
# and the embedded brief prompt both render from this list.
|
|
31
|
+
DEFAULT_BRIEF_SECTIONS = [
|
|
32
|
+
"Repo rules digest",
|
|
33
|
+
"Unit scope digest",
|
|
34
|
+
"Environment facts",
|
|
35
|
+
"Open risks",
|
|
36
|
+
]
|
|
37
|
+
|
|
28
38
|
|
|
29
39
|
def _validate_mount_path(path: str) -> str:
|
|
30
40
|
"""Validate one repo-relative mount path (BR-1.3).
|
|
@@ -318,8 +328,9 @@ class BriefInputsSpec(BaseModel):
|
|
|
318
328
|
|
|
319
329
|
include: list[str] = []
|
|
320
330
|
env_facts: list[str] = []
|
|
331
|
+
sections: list[str] = DEFAULT_BRIEF_SECTIONS
|
|
321
332
|
|
|
322
|
-
@field_validator("include", "env_facts", mode="before")
|
|
333
|
+
@field_validator("include", "env_facts", "sections", mode="before")
|
|
323
334
|
@classmethod
|
|
324
335
|
def _coerce_list(cls, v: Any) -> Any:
|
|
325
336
|
return [v] if isinstance(v, str) else v
|
|
@@ -338,6 +349,21 @@ class BriefInputsSpec(BaseModel):
|
|
|
338
349
|
"brief_inputs.env_facts entries must be non-empty strings")
|
|
339
350
|
return v
|
|
340
351
|
|
|
352
|
+
@field_validator("sections")
|
|
353
|
+
@classmethod
|
|
354
|
+
def _valid_sections(cls, v: list[str]) -> list[str]:
|
|
355
|
+
for section in v:
|
|
356
|
+
if not isinstance(section, str) or not section.strip():
|
|
357
|
+
raise ValueError(
|
|
358
|
+
"brief_inputs.sections entries must be non-empty strings")
|
|
359
|
+
if not v:
|
|
360
|
+
raise ValueError(
|
|
361
|
+
"brief_inputs.sections must be a non-empty list of headings")
|
|
362
|
+
if len(set(v)) != len(v):
|
|
363
|
+
raise ValueError(
|
|
364
|
+
"brief_inputs.sections entries must be unique")
|
|
365
|
+
return v
|
|
366
|
+
|
|
341
367
|
|
|
342
368
|
class StepConfig(BaseModel):
|
|
343
369
|
"""One pipeline step. Its type IS the key it carries: exactly one of
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/agents.py
RENAMED
|
@@ -16,6 +16,7 @@ from openhands.tools.task_tracker import TaskTrackerTool # noqa: F401 - registe
|
|
|
16
16
|
from openhands.tools.terminal import TerminalTool # noqa: F401 - registers "terminal"
|
|
17
17
|
|
|
18
18
|
from .forbidden import ForbiddenRule, match_forbidden_command
|
|
19
|
+
from .brief_prompt import render_brief_prompt
|
|
19
20
|
from .isolation import (SandboxError, SandboxExecutionRequest, command_argv,
|
|
20
21
|
resolve_sandbox_env)
|
|
21
22
|
|
|
@@ -59,6 +60,24 @@ def load_agent(agents_dir: Path | str, name: str, llm: LLM) -> "Agent":
|
|
|
59
60
|
return agent_definition_to_factory(agent_def)(llm)
|
|
60
61
|
|
|
61
62
|
|
|
63
|
+
def load_brief_agent(name: str, sections: list[str], llm: LLM) -> "Agent":
|
|
64
|
+
"""Build the brief agent from the engine-embedded prompt (046).
|
|
65
|
+
|
|
66
|
+
The brief prompt is engine-owned and versioned; it is never loaded from
|
|
67
|
+
``agents_dir``. The OUTPUT contract's headings are rendered from the
|
|
68
|
+
configured ``brief_inputs.sections``, so the prompt and the coverage gate
|
|
69
|
+
share one list and cannot diverge (043)."""
|
|
70
|
+
from openhands.sdk.subagent.registry import agent_definition_to_factory
|
|
71
|
+
from openhands.sdk.subagent.schema import AgentDefinition
|
|
72
|
+
|
|
73
|
+
agent_def = AgentDefinition(
|
|
74
|
+
name=name,
|
|
75
|
+
tools=["terminal"],
|
|
76
|
+
system_prompt=render_brief_prompt(sections),
|
|
77
|
+
)
|
|
78
|
+
return agent_definition_to_factory(agent_def)(llm)
|
|
79
|
+
|
|
80
|
+
|
|
62
81
|
class SandboxTerminalExecutor(ToolExecutor):
|
|
63
82
|
"""A stateless terminal executor: each action is a fresh ``Sandbox.run``
|
|
64
83
|
(no persistent shell session). ``is_input`` degrades to an unsupported
|
|
@@ -12,13 +12,6 @@ from __future__ import annotations
|
|
|
12
12
|
|
|
13
13
|
import re
|
|
14
14
|
|
|
15
|
-
_REQUIRED_SECTIONS = (
|
|
16
|
-
"Repo rules digest",
|
|
17
|
-
"Unit scope and lane digest",
|
|
18
|
-
"Environment facts",
|
|
19
|
-
"Open risks",
|
|
20
|
-
)
|
|
21
|
-
|
|
22
15
|
|
|
23
16
|
def _normalize(text: str) -> str:
|
|
24
17
|
"""Case-fold and collapse whitespace - the matching normal form."""
|
|
@@ -38,11 +31,6 @@ def _normalize_line(line: str) -> str:
|
|
|
38
31
|
return _normalize(stripped)
|
|
39
32
|
|
|
40
33
|
|
|
41
|
-
def required_sections() -> list[str]:
|
|
42
|
-
"""The four template headings the brief must emit."""
|
|
43
|
-
return list(_REQUIRED_SECTIONS)
|
|
44
|
-
|
|
45
|
-
|
|
46
34
|
def extract_anchors(content: str) -> list[str]:
|
|
47
35
|
"""Derive the mechanical anchor set from one include file.
|
|
48
36
|
|
|
@@ -75,16 +63,17 @@ def extract_anchors(content: str) -> list[str]:
|
|
|
75
63
|
|
|
76
64
|
|
|
77
65
|
def missing_anchors(brief_text: str, anchors: list[str],
|
|
78
|
-
env_facts: list[str]) -> list[str]:
|
|
66
|
+
env_facts: list[str], sections: list[str]) -> list[str]:
|
|
79
67
|
"""Return every required item the captured brief fails to cover.
|
|
80
68
|
|
|
81
|
-
Required section headings
|
|
82
|
-
(case-insensitive,
|
|
83
|
-
|
|
84
|
-
|
|
69
|
+
Required section headings (from the configured ``brief_inputs.sections``)
|
|
70
|
+
and anchors are matched line-anchored (case-insensitive,
|
|
71
|
+
whitespace-collapsed, ``**`` decoration stripped). Env facts are matched
|
|
72
|
+
verbatim, exactly as handed to the brief agent. An empty list means the
|
|
73
|
+
digest passes coverage."""
|
|
85
74
|
missing: list[str] = []
|
|
86
75
|
lines = {_normalize_line(line) for line in brief_text.splitlines()}
|
|
87
|
-
for section in
|
|
76
|
+
for section in sections:
|
|
88
77
|
if _normalize(section) not in lines:
|
|
89
78
|
missing.append(section)
|
|
90
79
|
for anchor in anchors:
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Brief Agent
|
|
2
|
+
|
|
3
|
+
You are the per-run context digester for a gated construction loop. You run
|
|
4
|
+
once per run (or once when the inputs change) and turn a closed input set into
|
|
5
|
+
a compact brief that the dev and review agents reuse on every attempt.
|
|
6
|
+
|
|
7
|
+
## WORKFLOW
|
|
8
|
+
|
|
9
|
+
1. Read every input section in the task message below. The inputs are the
|
|
10
|
+
resolved unit/plan docs, the listed repo-rule files, and the
|
|
11
|
+
`Environment facts` block. That is the closed list - nothing else.
|
|
12
|
+
2. Digest the inputs into the configured sections named in OUTPUT below.
|
|
13
|
+
Digest, do not transcribe: the brief is compact working memory, not a copy
|
|
14
|
+
of the inputs.
|
|
15
|
+
3. State the brief in your final response. The pipeline captures it as
|
|
16
|
+
`attempt-brief.md`.
|
|
17
|
+
|
|
18
|
+
## RULES
|
|
19
|
+
|
|
20
|
+
- One pass, no exploration. Read the listed inputs, emit the brief, finish.
|
|
21
|
+
Do not explore, do not verify, do not run commands, and do not read anything
|
|
22
|
+
not listed in the task message. Your inputs are already embedded in the task
|
|
23
|
+
message; the terminal is available only if a listed input must be re-read.
|
|
24
|
+
- Prior verdicts and feedback are deliberately absent from your inputs. They
|
|
25
|
+
reach the dev and review agents through a separate notes channel every
|
|
26
|
+
attempt. Do not invent them and do not re-derive them.
|
|
27
|
+
- The repo-rules digest is structural: one line per top-level section of each
|
|
28
|
+
repo-rule input. Markdown anchors are the `##` headings: keep each heading
|
|
29
|
+
verbatim, then compress that section's rules into the one line that follows
|
|
30
|
+
it. YAML anchors are each `- name:` entry under `categories:` plus the
|
|
31
|
+
`enforcement_levels` preamble: keep each name verbatim. No top-level section
|
|
32
|
+
or category may be dropped; merging is allowed only between a section and
|
|
33
|
+
its own subsections. The anchor line holds the heading and nothing else; the
|
|
34
|
+
compressed rules go on the following line:
|
|
35
|
+
|
|
36
|
+
- general_principles
|
|
37
|
+
Simplest thing that works; defer decisions to the last responsible moment.
|
|
38
|
+
|
|
39
|
+
A line like `general_principles: Simplest thing that works; ...` does not
|
|
40
|
+
satisfy coverage; the heading must be the only text on its line.
|
|
41
|
+
- Keep the environment-facts entries verbatim: each fact and the behavior it
|
|
42
|
+
implies travel together.
|
|
43
|
+
- ASCII only. Do not use em dash characters.
|
|
44
|
+
- If the task message carries a `## Coverage retry` section, regenerate the
|
|
45
|
+
brief so every listed item appears, verbatim where the contract requires
|
|
46
|
+
verbatim. No exploration: the listed items are the only correction signal.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Bundled brief-agent prompt (046).
|
|
2
|
+
|
|
3
|
+
The brief prompt is an engine-owned resource, versioned with the engine so the
|
|
4
|
+
prompt contract and the coverage gate cannot drift (the 043 divergence class).
|
|
5
|
+
The static prose is packaged and read at runtime like the 034 error guide; the
|
|
6
|
+
section-dependent OUTPUT block is rendered here from the configured
|
|
7
|
+
``brief_inputs.sections`` list, so one list feeds the prompt and the gate.
|
|
8
|
+
|
|
9
|
+
``BRIEF_PROMPT_VERSION`` joins the brief digest hash: an engine upgrade (or a
|
|
10
|
+
sections edit) busts a cached digest and forces a fresh capture.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from importlib.resources import files
|
|
16
|
+
|
|
17
|
+
BRIEF_PROMPT_RESOURCE = "brief_prompt.md"
|
|
18
|
+
BRIEF_PROMPT_VERSION = "1"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def load_template() -> str:
|
|
22
|
+
"""The static brief-prompt prose (header, workflow, rules)."""
|
|
23
|
+
return (files("agentic_dev_loop.engine")
|
|
24
|
+
.joinpath(BRIEF_PROMPT_RESOURCE)
|
|
25
|
+
.read_text(encoding="utf-8"))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _output_block(sections: list[str]) -> str:
|
|
29
|
+
"""Render the OUTPUT contract from the configured section headings."""
|
|
30
|
+
headings = "\n\n".join(f"## {section}" for section in sections)
|
|
31
|
+
names = ", ".join(f"`## {section}`" for section in sections)
|
|
32
|
+
return (
|
|
33
|
+
"## OUTPUT\n\n"
|
|
34
|
+
"Start your final response with exactly this structure. Each configured "
|
|
35
|
+
"section heading appears as its own `## ` line, followed by the "
|
|
36
|
+
"compressed content for that section (write `None` when a section has "
|
|
37
|
+
"nothing):\n\n"
|
|
38
|
+
f"{headings}\n\n"
|
|
39
|
+
f"The section headings must appear exactly as written above: {names}. "
|
|
40
|
+
"Do not shorten or rename them, and do not merge a section with "
|
|
41
|
+
"another section."
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def render_brief_prompt(sections: list[str]) -> str:
|
|
46
|
+
"""The full brief prompt: static prose plus the section-rendered OUTPUT."""
|
|
47
|
+
return load_template() + "\n\n" + _output_block(sections)
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/dryrun.py
RENAMED
|
@@ -25,12 +25,16 @@ from .secrets import scan_env_files
|
|
|
25
25
|
|
|
26
26
|
def _validate_agents(cfg: PipelineConfig, agents_dir: Path) -> None:
|
|
27
27
|
"""Every `agent:` step must resolve to an existing file under agents_dir
|
|
28
|
-
(the same fail-fast `load_agent` enforces at run time).
|
|
28
|
+
(the same fail-fast `load_agent` enforces at run time).
|
|
29
|
+
|
|
30
|
+
The brief prompt is engine-embedded (046), so a ``brief_inputs:`` step is
|
|
31
|
+
exempt from the agents_dir lookup - it never reads a vendored file."""
|
|
29
32
|
for step in cfg.steps:
|
|
30
|
-
if step.agent is not None:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
if step.agent is None or step.brief_inputs is not None:
|
|
34
|
+
continue
|
|
35
|
+
path = agents_dir / f"{step.agent}.agent.md"
|
|
36
|
+
if not path.is_file():
|
|
37
|
+
raise FileNotFoundError(f"Agent file not found: {path}")
|
|
34
38
|
|
|
35
39
|
|
|
36
40
|
def _validate_actions(cfg: PipelineConfig, registry: Registry) -> None:
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/stages.py
RENAMED
|
@@ -32,8 +32,9 @@ from langgraph.graph import END
|
|
|
32
32
|
from openhands.sdk import Conversation
|
|
33
33
|
|
|
34
34
|
from .agent_error_guide import guide_section
|
|
35
|
-
from .agents import load_agent, register_sandbox_terminal
|
|
35
|
+
from .agents import load_agent, load_brief_agent, register_sandbox_terminal
|
|
36
36
|
from .brief_coverage import extract_anchors, missing_anchors
|
|
37
|
+
from .brief_prompt import BRIEF_PROMPT_VERSION
|
|
37
38
|
from agentic_dev_loop.core.config import TERMINALS, PipelineConfig, Route, StepConfig, route_target
|
|
38
39
|
from agentic_dev_loop.core.paths import _has_wildcards
|
|
39
40
|
from .deps import extension_message, parse_missing_dependencies, policy_injection
|
|
@@ -173,7 +174,11 @@ class Runtime:
|
|
|
173
174
|
if step is not None else None),
|
|
174
175
|
forbidden_commands=forbidden_commands,
|
|
175
176
|
allowlist=allowlist)
|
|
176
|
-
|
|
177
|
+
if step is not None and step.brief_inputs is not None:
|
|
178
|
+
agent = load_brief_agent(
|
|
179
|
+
agent_name, step.brief_inputs.sections, self.llm)
|
|
180
|
+
else:
|
|
181
|
+
agent = load_agent(self.agents_dir, agent_name, self.llm)
|
|
177
182
|
callbacks = []
|
|
178
183
|
if finalize_controller is not None:
|
|
179
184
|
callbacks.append(finalize_controller.on_event)
|
|
@@ -543,6 +548,14 @@ def brief_inputs_hash(runtime: Runtime, step: StepConfig,
|
|
|
543
548
|
brief step, otherwise the existing digest is reused without an LLM call."""
|
|
544
549
|
sections, env_facts = _brief_sections(runtime, step, docs, doc_sources)
|
|
545
550
|
digest = hashlib.sha256()
|
|
551
|
+
# 046, D6: the embedded prompt version and the configured section headings
|
|
552
|
+
# join the hash, so an engine upgrade or a sections edit busts the cached
|
|
553
|
+
# digest and forces a fresh capture.
|
|
554
|
+
digest.update(BRIEF_PROMPT_VERSION.encode("utf-8"))
|
|
555
|
+
digest.update(b"\0")
|
|
556
|
+
for section in step.brief_inputs.sections:
|
|
557
|
+
digest.update(section.encode("utf-8"))
|
|
558
|
+
digest.update(b"\0")
|
|
546
559
|
for key in sorted(sections):
|
|
547
560
|
digest.update(key.encode("utf-8"))
|
|
548
561
|
digest.update(b"\0")
|
|
@@ -751,6 +764,20 @@ def make_agent_node(runtime: Runtime, step: StepConfig):
|
|
|
751
764
|
return node
|
|
752
765
|
|
|
753
766
|
|
|
767
|
+
def _warn_vendored_brief(runtime: Runtime, step: StepConfig) -> None:
|
|
768
|
+
"""Warn once per load when a vendored brief prompt exists (046, D5).
|
|
769
|
+
|
|
770
|
+
The embedded prompt is authoritative, so a leftover
|
|
771
|
+
``<agents_dir>/<agent>.agent.md`` for a ``brief_inputs:`` step is ignored;
|
|
772
|
+
the warning names it without failing the run."""
|
|
773
|
+
vendored = runtime.agents_dir / f"{step.agent}.agent.md"
|
|
774
|
+
if vendored.is_file():
|
|
775
|
+
print(
|
|
776
|
+
f"[{runtime.cfg.name}] ignoring vendored brief prompt {vendored} - "
|
|
777
|
+
"the engine-embedded prompt is authoritative",
|
|
778
|
+
file=sys.stderr, flush=True)
|
|
779
|
+
|
|
780
|
+
|
|
754
781
|
def make_brief_node(runtime: Runtime, step: StepConfig):
|
|
755
782
|
"""Node closure for a ``brief_inputs:`` agent step (033).
|
|
756
783
|
|
|
@@ -768,6 +795,7 @@ def make_brief_node(runtime: Runtime, step: StepConfig):
|
|
|
768
795
|
re-runs the agent with a ``## Coverage retry`` correction note. Exhausting
|
|
769
796
|
the budget writes last-error.md and fails the run."""
|
|
770
797
|
captures = step.artifact is not None or bool(step.produces)
|
|
798
|
+
_warn_vendored_brief(runtime, step)
|
|
771
799
|
|
|
772
800
|
def node(state: dict) -> dict:
|
|
773
801
|
attempt = state["attempt"]
|
|
@@ -780,6 +808,8 @@ def make_brief_node(runtime: Runtime, step: StepConfig):
|
|
|
780
808
|
anchors = _brief_anchors(runtime, step)
|
|
781
809
|
env_facts = (list(step.brief_inputs.env_facts)
|
|
782
810
|
if step.brief_inputs is not None else [])
|
|
811
|
+
sections = (list(step.brief_inputs.sections)
|
|
812
|
+
if step.brief_inputs is not None else [])
|
|
783
813
|
except Exception:
|
|
784
814
|
err = redact_values(traceback.format_exc(), runtime.secrets.values())
|
|
785
815
|
print(err[-4000:], file=sys.stderr, flush=True)
|
|
@@ -793,7 +823,7 @@ def make_brief_node(runtime: Runtime, step: StepConfig):
|
|
|
793
823
|
reused = (existing is not None
|
|
794
824
|
and state.get("brief_hashes", {}).get(step.name) == current_hash)
|
|
795
825
|
|
|
796
|
-
if reused and not missing_anchors(existing, anchors, env_facts):
|
|
826
|
+
if reused and not missing_anchors(existing, anchors, env_facts, sections):
|
|
797
827
|
print(f"[{subject}] {step.name} brief inputs unchanged - reusing.",
|
|
798
828
|
flush=True)
|
|
799
829
|
merged = {**state["step_verdicts"], step.name: "pass"}
|
|
@@ -802,7 +832,7 @@ def make_brief_node(runtime: Runtime, step: StepConfig):
|
|
|
802
832
|
coverage_note = None
|
|
803
833
|
if reused:
|
|
804
834
|
coverage_note = _coverage_note_text(
|
|
805
|
-
missing_anchors(existing, anchors, env_facts))
|
|
835
|
+
missing_anchors(existing, anchors, env_facts, sections))
|
|
806
836
|
message = build_brief_context(runtime, step, state["docs"],
|
|
807
837
|
state.get("doc_sources"),
|
|
808
838
|
coverage_note=coverage_note)
|
|
@@ -824,7 +854,7 @@ def make_brief_node(runtime: Runtime, step: StepConfig):
|
|
|
824
854
|
result.truncated, max_iterations)],
|
|
825
855
|
"retry_target": _unclear_target(runtime, step)}
|
|
826
856
|
|
|
827
|
-
missing = missing_anchors(result.response or "", anchors, env_facts)
|
|
857
|
+
missing = missing_anchors(result.response or "", anchors, env_facts, sections)
|
|
828
858
|
if missing:
|
|
829
859
|
prev_hash = state.get("brief_hashes", {}).get(step.name)
|
|
830
860
|
retries = (0 if prev_hash != current_hash
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45/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.0a45
|
|
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
|
|
@@ -249,7 +249,7 @@ steps:
|
|
|
249
249
|
| --- | --- |
|
|
250
250
|
| `agent:` / `command:` / `action:` | Exactly one per step. Agents live in `agents_dir` as `<name>.agent.md`; commands run sandboxed (mechanical, never an LLM call). `commit` is the sole host-side built-in action; consumer actions are sandbox-executed, command-shaped scripts (see [Host boundary](#host-boundary-security-model)). |
|
|
251
251
|
| `produces:` / `artifact:` + `verdicts:` | Hygiene-tracked outputs vs verdict-parsed routing. The **last** `VERDICT:` line wins; stale artifacts are deleted at each attempt start. |
|
|
252
|
-
| `brief_inputs:` | Optional agent-step input spec: `{ include: [<paths/globs>], env_facts: [<strings>] }`. The engine resolves the include list against the workspace, passes the resolved docs + include contents + env facts as that step's task message, and regenerates the step only when those inputs change. A produces-only agent step such as `brief` is the documented pattern for per-run context digestion. |
|
|
252
|
+
| `brief_inputs:` | Optional agent-step input spec: `{ include: [<paths/globs>], env_facts: [<strings>], sections: [<headings>] }`. The engine resolves the include list against the workspace, passes the resolved docs + include contents + env facts as that step's task message, and regenerates the step only when those inputs change. `sections` is the ordered list of digest headings the brief must emit (default `[Repo rules digest, Unit scope digest, Environment facts, Open risks]`; non-empty and unique). A produces-only agent step such as `brief` is the documented pattern for per-run context digestion. |
|
|
253
253
|
| `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
254
|
| `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
255
|
| `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. |
|
|
@@ -271,12 +271,14 @@ run start (or when its inputs change), its `produces:` artifact survives attempt
|
|
|
271
271
|
starts, and the dev/review agents read that digest instead of re-deriving repo
|
|
272
272
|
rules and environment facts every attempt.
|
|
273
273
|
|
|
274
|
-
The brief digest is mechanically coverage-checked: the
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
274
|
+
The brief digest is mechanically coverage-checked: the configured
|
|
275
|
+
`brief_inputs.sections` headings must each appear on their own line, every
|
|
276
|
+
anchor extracted from the `include` files (markdown `##` headings, and YAML
|
|
277
|
+
category names plus `enforcement_levels`) must appear on its own line
|
|
278
|
+
(case-insensitive, whitespace-collapsed, `**` decoration allowed), and every
|
|
279
|
+
`env_facts` entry must appear verbatim. The section list feeds both the
|
|
280
|
+
engine-embedded brief prompt and the coverage gate, so the two can never
|
|
281
|
+
disagree; a miss
|
|
280
282
|
re-runs the brief agent once per missing set with a `## Coverage retry`
|
|
281
283
|
correction note, bounded to three retries per input set; if the same items are
|
|
282
284
|
still dropped after the cap, the run fails and `last-error.md` names the
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop.egg-info/SOURCES.txt
RENAMED
|
@@ -21,6 +21,8 @@ src/agentic_dev_loop/engine/agent_error_guide.py
|
|
|
21
21
|
src/agentic_dev_loop/engine/agents.py
|
|
22
22
|
src/agentic_dev_loop/engine/allowlist.py
|
|
23
23
|
src/agentic_dev_loop/engine/brief_coverage.py
|
|
24
|
+
src/agentic_dev_loop/engine/brief_prompt.md
|
|
25
|
+
src/agentic_dev_loop/engine/brief_prompt.py
|
|
24
26
|
src/agentic_dev_loop/engine/cli.py
|
|
25
27
|
src/agentic_dev_loop/engine/containers.py
|
|
26
28
|
src/agentic_dev_loop/engine/deps.py
|
|
@@ -55,6 +57,7 @@ tests/test_033_brief_step.py
|
|
|
55
57
|
tests/test_035_finalize_nudge.py
|
|
56
58
|
tests/test_036_banned_commands_and_lane_boundary.py
|
|
57
59
|
tests/test_041_brief_coverage.py
|
|
60
|
+
tests/test_046_brief_prompt.py
|
|
58
61
|
tests/test_actions.py
|
|
59
62
|
tests/test_agent_error_guide.py
|
|
60
63
|
tests/test_agents.py
|
|
@@ -44,7 +44,7 @@ def _load(tmp_path, data):
|
|
|
44
44
|
|
|
45
45
|
BRIEF_OK = (
|
|
46
46
|
"## Repo rules digest\n\nREPO RULES\n\n"
|
|
47
|
-
"## Unit scope
|
|
47
|
+
"## Unit scope digest\n\nSCOPE\n\n"
|
|
48
48
|
"## Environment facts\n\n- offline; never fetch\n\n"
|
|
49
49
|
"## Open risks\n\nNone\n"
|
|
50
50
|
)
|
|
@@ -167,6 +167,48 @@ class TestBriefInputsConfig:
|
|
|
167
167
|
_load(tmp_path, data)
|
|
168
168
|
|
|
169
169
|
|
|
170
|
+
def test_sections_default_neutral(self, tmp_path):
|
|
171
|
+
data = _base()
|
|
172
|
+
data["steps"] = [BRIEF_STEP, {"name": "dev", "agent": "dev",
|
|
173
|
+
"on_pass": "success"}]
|
|
174
|
+
brief = _load(tmp_path, data).steps[0]
|
|
175
|
+
assert brief.brief_inputs.sections == [
|
|
176
|
+
"Repo rules digest", "Unit scope digest",
|
|
177
|
+
"Environment facts", "Open risks",
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
def test_sections_override(self, tmp_path):
|
|
181
|
+
data = _base()
|
|
182
|
+
step = dict(BRIEF_STEP)
|
|
183
|
+
step["brief_inputs"] = {**step["brief_inputs"],
|
|
184
|
+
"sections": ["Rules", "Scope", "Risks"]}
|
|
185
|
+
data["steps"] = [step, {"name": "dev", "agent": "dev",
|
|
186
|
+
"on_pass": "success"}]
|
|
187
|
+
brief = _load(tmp_path, data).steps[0]
|
|
188
|
+
assert brief.brief_inputs.sections == ["Rules", "Scope", "Risks"]
|
|
189
|
+
|
|
190
|
+
def test_sections_empty_rejected(self, tmp_path):
|
|
191
|
+
data = _base()
|
|
192
|
+
data["steps"] = [{
|
|
193
|
+
"name": "brief", "agent": "brief", "produces": "attempt-brief.md",
|
|
194
|
+
"brief_inputs": {"include": ["AGENTS.md"], "sections": []},
|
|
195
|
+
"on_pass": "success",
|
|
196
|
+
}]
|
|
197
|
+
with pytest.raises(ValidationError, match="non-empty list"):
|
|
198
|
+
_load(tmp_path, data)
|
|
199
|
+
|
|
200
|
+
def test_sections_duplicate_rejected(self, tmp_path):
|
|
201
|
+
data = _base()
|
|
202
|
+
data["steps"] = [{
|
|
203
|
+
"name": "brief", "agent": "brief", "produces": "attempt-brief.md",
|
|
204
|
+
"brief_inputs": {"include": ["AGENTS.md"],
|
|
205
|
+
"sections": ["Rules", "Rules"]},
|
|
206
|
+
"on_pass": "success",
|
|
207
|
+
}]
|
|
208
|
+
with pytest.raises(ValidationError, match="unique"):
|
|
209
|
+
_load(tmp_path, data)
|
|
210
|
+
|
|
211
|
+
|
|
170
212
|
def make_cfg(steps, **over):
|
|
171
213
|
base = {"name": "t", "llm": {"model": "m", "api_key_env": "K"},
|
|
172
214
|
"agents_dir": "agents", "lockfiles": ["uv.lock"], "steps": steps}
|
|
@@ -486,8 +528,6 @@ class TestDryRunBriefInputs:
|
|
|
486
528
|
" on_pass: success\n")
|
|
487
529
|
agents = repo / "agents"
|
|
488
530
|
agents.mkdir()
|
|
489
|
-
(agents / "brief.agent.md").write_text(
|
|
490
|
-
"---\nname: brief\ntools: [terminal]\n---\nYou are brief.\n")
|
|
491
531
|
monkeypatch.chdir(repo)
|
|
492
532
|
from agentic_dev_loop.engine.dryrun import dry_run
|
|
493
533
|
with pytest.raises(FileNotFoundError, match="NO-SUCH.md"):
|
|
@@ -513,8 +553,6 @@ class TestDryRunBriefInputs:
|
|
|
513
553
|
" on_pass: success\n")
|
|
514
554
|
agents = repo / "agents"
|
|
515
555
|
agents.mkdir()
|
|
516
|
-
(agents / "brief.agent.md").write_text(
|
|
517
|
-
"---\nname: brief\ntools: [terminal]\n---\nYou are brief.\n")
|
|
518
556
|
monkeypatch.chdir(repo)
|
|
519
557
|
from agentic_dev_loop.engine.dryrun import dry_run
|
|
520
558
|
assert dry_run("pipeline.yaml",
|
|
@@ -580,7 +618,7 @@ class TestBriefPipeline:
|
|
|
580
618
|
|
|
581
619
|
brief_digest = (
|
|
582
620
|
"## Repo rules digest\n\nREPO RULES\n\n"
|
|
583
|
-
"## Unit scope
|
|
621
|
+
"## Unit scope digest\n\nBRIEF DIGEST\n\n"
|
|
584
622
|
"## Environment facts\n\n"
|
|
585
623
|
"- the workspace is an export with no .git; verify with find/ls, never git status\n\n"
|
|
586
624
|
"## Open risks\n\nNone\n"
|
|
@@ -11,7 +11,6 @@ from agentic_dev_loop.core.config import PipelineConfig
|
|
|
11
11
|
from agentic_dev_loop.engine.brief_coverage import (
|
|
12
12
|
extract_anchors,
|
|
13
13
|
missing_anchors,
|
|
14
|
-
required_sections,
|
|
15
14
|
)
|
|
16
15
|
from agentic_dev_loop.engine.registry import default_registry
|
|
17
16
|
from agentic_dev_loop.engine.stages import (
|
|
@@ -24,6 +23,8 @@ from agentic_dev_loop.engine.stages import (
|
|
|
24
23
|
ROOT = Path(__file__).resolve().parents[1]
|
|
25
24
|
AGENTS_MD = (ROOT / "AGENTS.md").read_text(encoding="utf-8")
|
|
26
25
|
STANDARDS_YAML = (ROOT / "coding-standards-ddd.yaml").read_text(encoding="utf-8")
|
|
26
|
+
SECTIONS = ["Repo rules digest", "Unit scope digest",
|
|
27
|
+
"Environment facts", "Open risks"]
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
def _brief_ok() -> str:
|
|
@@ -31,7 +32,7 @@ def _brief_ok() -> str:
|
|
|
31
32
|
"## Repo rules digest\n\n"
|
|
32
33
|
"**Error handling**\nNever fall back silently.\n\n"
|
|
33
34
|
"**Mock policy**\nNo mocks unless unavoidable.\n\n"
|
|
34
|
-
"## Unit scope
|
|
35
|
+
"## Unit scope digest\n\nunit scope\n\n"
|
|
35
36
|
"## Environment facts\n\n- offline; never fetch\n\n"
|
|
36
37
|
"## Open risks\n\nNone\n"
|
|
37
38
|
)
|
|
@@ -93,13 +94,12 @@ def runtime(tmp_path, fake_sandbox):
|
|
|
93
94
|
|
|
94
95
|
|
|
95
96
|
class TestExtractAnchors:
|
|
96
|
-
def
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
"
|
|
102
|
-
]
|
|
97
|
+
def test_required_sections_are_config_driven(self):
|
|
98
|
+
# 046: the required set is handed in, not read from an engine constant.
|
|
99
|
+
text = _brief_ok()
|
|
100
|
+
assert missing_anchors(text, [], [], SECTIONS) == []
|
|
101
|
+
assert "Renamed section" in missing_anchors(
|
|
102
|
+
text, [], [], ["Renamed section"])
|
|
103
103
|
|
|
104
104
|
def test_markdown_headings_from_real_agents_md(self):
|
|
105
105
|
anchors = extract_anchors(AGENTS_MD)
|
|
@@ -142,39 +142,42 @@ class TestMissingAnchors:
|
|
|
142
142
|
def test_all_present_passes(self):
|
|
143
143
|
assert missing_anchors(_brief_ok(),
|
|
144
144
|
["error handling", "mock policy"],
|
|
145
|
-
["offline; never fetch"]) == []
|
|
145
|
+
["offline; never fetch"], SECTIONS) == []
|
|
146
146
|
|
|
147
147
|
def test_missing_anchor_is_named(self):
|
|
148
148
|
assert "mock policy" in missing_anchors(
|
|
149
149
|
_brief_missing_mock(), ["error handling", "mock policy"],
|
|
150
|
-
["offline; never fetch"])
|
|
150
|
+
["offline; never fetch"], SECTIONS)
|
|
151
151
|
|
|
152
152
|
def test_missing_section_heading_is_named(self):
|
|
153
153
|
text = _brief_ok().replace("## Open risks\n\nNone\n", "")
|
|
154
154
|
assert "Open risks" in missing_anchors(
|
|
155
|
-
text, ["error handling", "mock policy"], ["offline; never fetch"]
|
|
155
|
+
text, ["error handling", "mock policy"], ["offline; never fetch"],
|
|
156
|
+
SECTIONS)
|
|
156
157
|
|
|
157
158
|
def test_altered_env_fact_is_named(self):
|
|
158
159
|
text = _brief_ok().replace("offline; never fetch", "offline maybe")
|
|
159
160
|
assert "offline; never fetch" in missing_anchors(
|
|
160
|
-
text, ["error handling", "mock policy"], ["offline; never fetch"]
|
|
161
|
+
text, ["error handling", "mock policy"], ["offline; never fetch"],
|
|
162
|
+
SECTIONS)
|
|
161
163
|
|
|
162
164
|
def test_mid_line_mention_does_not_satisfy(self):
|
|
163
165
|
text = _brief_ok().replace(
|
|
164
166
|
"**Error handling**\nNever fall back silently.\n\n",
|
|
165
167
|
"See error handling for the rules.\n\n")
|
|
166
168
|
assert "error handling" in missing_anchors(
|
|
167
|
-
text, ["error handling", "mock policy"], ["offline; never fetch"]
|
|
169
|
+
text, ["error handling", "mock policy"], ["offline; never fetch"],
|
|
170
|
+
SECTIONS)
|
|
168
171
|
|
|
169
172
|
def test_case_and_whitespace_variants_pass(self):
|
|
170
173
|
text = _brief_ok().replace(
|
|
171
174
|
"**Error handling**", "** ERROR HANDLING **")
|
|
172
175
|
assert missing_anchors(text, ["error handling", "mock policy"],
|
|
173
|
-
["offline; never fetch"]) == []
|
|
176
|
+
["offline; never fetch"], SECTIONS) == []
|
|
174
177
|
|
|
175
178
|
def test_bold_wrapped_heading_passes(self):
|
|
176
179
|
assert missing_anchors(_brief_ok(), ["error handling", "mock policy"],
|
|
177
|
-
["offline; never fetch"]) == []
|
|
180
|
+
["offline; never fetch"], SECTIONS) == []
|
|
178
181
|
|
|
179
182
|
|
|
180
183
|
class TestCoverageNoteWording:
|
|
@@ -205,6 +208,14 @@ class TestCoverageNoteWording:
|
|
|
205
208
|
|
|
206
209
|
|
|
207
210
|
class TestBriefNodeCoverage:
|
|
211
|
+
def test_vendored_brief_prompt_warns(self, runtime, capsys):
|
|
212
|
+
runtime.agents_dir.mkdir(exist_ok=True)
|
|
213
|
+
(runtime.agents_dir / "brief.agent.md").write_text("vendored\n")
|
|
214
|
+
make_brief_node(runtime, runtime.cfg.steps[0])
|
|
215
|
+
err = capsys.readouterr().err
|
|
216
|
+
assert "ignoring vendored brief prompt" in err
|
|
217
|
+
assert "embedded prompt is authoritative" in err
|
|
218
|
+
|
|
208
219
|
def test_miss_returns_retry_note_and_reruns(self, runtime, fake_agents):
|
|
209
220
|
good = _brief_ok()
|
|
210
221
|
bad = _brief_missing_mock()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Brief prompt embedding (046): the OUTPUT contract renders from the
|
|
2
|
+
configured section headings, so the prompt and the coverage gate share one
|
|
3
|
+
list and cannot drift apart (the 043 divergence class)."""
|
|
4
|
+
|
|
5
|
+
from agentic_dev_loop.engine.brief_prompt import (
|
|
6
|
+
BRIEF_PROMPT_VERSION,
|
|
7
|
+
load_template,
|
|
8
|
+
render_brief_prompt,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
SECTIONS = ["Repo rules digest", "Unit scope digest",
|
|
12
|
+
"Environment facts", "Open risks"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestRenderBriefPrompt:
|
|
16
|
+
def test_each_configured_section_is_its_own_heading(self):
|
|
17
|
+
prompt = render_brief_prompt(SECTIONS)
|
|
18
|
+
lines = prompt.splitlines()
|
|
19
|
+
for section in SECTIONS:
|
|
20
|
+
assert f"## {section}" in lines
|
|
21
|
+
|
|
22
|
+
def test_custom_sections_rendered(self):
|
|
23
|
+
prompt = render_brief_prompt(["Rules", "Scope", "Risks"])
|
|
24
|
+
lines = prompt.splitlines()
|
|
25
|
+
assert "## Rules" in lines
|
|
26
|
+
assert "## Scope" in lines
|
|
27
|
+
assert "## Risks" in lines
|
|
28
|
+
assert "## Repo rules digest" not in lines
|
|
29
|
+
|
|
30
|
+
def test_warning_lists_configured_names(self):
|
|
31
|
+
prompt = render_brief_prompt(["Rules", "Scope", "Risks"])
|
|
32
|
+
assert "`## Rules`" in prompt
|
|
33
|
+
assert "`## Scope`" in prompt
|
|
34
|
+
assert "`## Risks`" in prompt
|
|
35
|
+
assert "Do not shorten or rename them" in prompt
|
|
36
|
+
|
|
37
|
+
def test_static_template_loads(self):
|
|
38
|
+
template = load_template()
|
|
39
|
+
assert "## WORKFLOW" in template
|
|
40
|
+
assert "## RULES" in template
|
|
41
|
+
assert "Do not use em dash characters" in template
|
|
42
|
+
|
|
43
|
+
def test_version_is_stable_string(self):
|
|
44
|
+
assert isinstance(BRIEF_PROMPT_VERSION, str)
|
|
45
|
+
assert BRIEF_PROMPT_VERSION
|
|
@@ -9,7 +9,7 @@ import pytest
|
|
|
9
9
|
from openhands.sdk import LLM
|
|
10
10
|
from openhands.sdk.agent.agent import Agent
|
|
11
11
|
|
|
12
|
-
from agentic_dev_loop.engine.agents import load_agent
|
|
12
|
+
from agentic_dev_loop.engine.agents import load_agent, load_brief_agent
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
@pytest.fixture
|
|
@@ -88,6 +88,25 @@ class TestLoadAgent:
|
|
|
88
88
|
assert agent.filter_tools_regex is None
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
class TestLoadBriefAgent:
|
|
92
|
+
"""The brief agent is engine-embedded (046): no vendored file is read,
|
|
93
|
+
and the rendered OUTPUT contract is driven by the configured sections."""
|
|
94
|
+
|
|
95
|
+
def test_builds_embedded_agent_without_file(self, tmp_path, llm):
|
|
96
|
+
sections = ["Repo rules digest", "Unit scope digest",
|
|
97
|
+
"Environment facts", "Open risks"]
|
|
98
|
+
agent = load_brief_agent("brief", sections, llm)
|
|
99
|
+
assert isinstance(agent, Agent)
|
|
100
|
+
assert [t.name for t in agent.tools] == ["terminal"]
|
|
101
|
+
|
|
102
|
+
def test_does_not_read_agents_dir(self, tmp_path, llm):
|
|
103
|
+
agents_dir = tmp_path / "agents"
|
|
104
|
+
agents_dir.mkdir()
|
|
105
|
+
# No brief.agent.md exists; the embedded loader must not look for one.
|
|
106
|
+
agent = load_brief_agent("brief", ["Repo rules digest"], llm)
|
|
107
|
+
assert isinstance(agent, Agent)
|
|
108
|
+
|
|
109
|
+
|
|
91
110
|
from agentic_dev_loop.engine.isolation import SandboxError
|
|
92
111
|
|
|
93
112
|
|
|
@@ -64,7 +64,7 @@ def _script_test(*behaviors):
|
|
|
64
64
|
|
|
65
65
|
_BRIEF_DIGEST = (
|
|
66
66
|
"## Repo rules digest\n\n# AGENTS.md\n# coding-standards-ddd.yaml\n\n"
|
|
67
|
-
"## Unit scope
|
|
67
|
+
"## Unit scope digest\n\nplan scope\n\n"
|
|
68
68
|
"## Environment facts\n\n"
|
|
69
69
|
"- the workspace is an export with no .git; verify with find/ls, never git status\n"
|
|
70
70
|
"- the sandbox is network-off by default; never run package-manager fetches\n"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/core/results.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/core/verdict.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/actions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/allowlist.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/containers.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/egress_policy.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/egress_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/forbidden.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/graph.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/hostboundary.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/isolation.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/loaders.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/mounts.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/outputs.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/presets.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/secrets.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/engine/sync_back.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/viz/__init__.py
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop/viz/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/src/agentic_dev_loop.egg-info/requires.txt
RENAMED
|
File without changes
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/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
|
{agentic_dev_loop-1.0.0a44 → agentic_dev_loop-1.0.0a45}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|