devagent-ai 0.8.3__tar.gz → 0.8.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {devagent_ai-0.8.3/devagent_ai.egg-info → devagent_ai-0.8.4}/PKG-INFO +34 -1
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/README.md +33 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/__init__.py +1 -1
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/cli.py +91 -4
- {devagent_ai-0.8.3 → devagent_ai-0.8.4/devagent_ai.egg-info}/PKG-INFO +34 -1
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/SOURCES.txt +1 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/pyproject.toml +1 -1
- devagent_ai-0.8.4/tests/test_cli_progress.py +91 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_production_v040.py +1 -1
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/LICENSE +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/NOTICE +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/__init__.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/llm.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/loop.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/memory.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/prompts.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/agent/tools.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/__main__.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/artifacts.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/automations.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/autonomy.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/browser.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/config.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/discovery.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/evaluation.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/memory.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/models.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/orchestrator.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/provider_benchmark.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/providers.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/qualification.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/realworld.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/report.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/retrieval.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/routing.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/runtime.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/safety.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/skills.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/source_control.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/state_machine.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/tasking.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/technical_review.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/workspace.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent/worktree.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/dependency_links.txt +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/entry_points.txt +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/requires.txt +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/devagent_ai.egg-info/top_level.txt +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/setup.cfg +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_acceptance_contract.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_benchmark_catalog.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_browser_verification.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_capability_discovery.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_cli.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_developer_review_report.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_discovery_memory.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_e2e_fake_provider.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_evaluation_harness.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_evaluation_matrix.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_evaluation_regression_evidence.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_functional_qualification.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_huge_monorepo_v070.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_migration_e2e_v070.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_model_routing.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_multilang_technical_review.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_multistack_devagent_e2e.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_multistack_qualification.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_packaging_metadata.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_plan_verification_normalization.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_preservation_contradiction.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_production_hardening.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_realworld_benchmark.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_requirement_compiler_v082.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_requirement_intelligence_v083.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_retrieval.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_runtime_sandbox.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_safety_workspace.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_source_control_publish.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_structural_devagent_e2e_v070.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_structural_operations.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_structured_provider_contract.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_tasking_state.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_v070_engineering_breadth.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_v080_autonomy.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_v080_provider_benchmark.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_v080_skills_automations.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_workspace_environment.py +0 -0
- {devagent_ai-0.8.3 → devagent_ai-0.8.4}/tests/test_worktree.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devagent-ai
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.4
|
|
4
4
|
Summary: Evidence-driven local autonomous software engineering agent
|
|
5
5
|
Author: Tom Ha
|
|
6
6
|
Maintainer: Tom Ha
|
|
@@ -152,6 +152,39 @@ reviewer → independently review final diff
|
|
|
152
152
|
|
|
153
153
|
The deterministic harness remains responsible for safety, tool execution, verification validity, acceptance adjudication, final status, reporting, and source-control publication regardless of which model handles a role.
|
|
154
154
|
|
|
155
|
+
#### Example: use multiple AI models in one DevAgent run
|
|
156
|
+
|
|
157
|
+
You do not have to use one AI model for every reasoning step. If you believe different models are better suited to different engineering roles, configure a default model plus any role-specific overrides. Roles that are not explicitly configured fall back to the default model.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Keep credentials in environment variables; DevAgent does not store the keys.
|
|
161
|
+
export OPENAI_API_KEY=...
|
|
162
|
+
export GEMINI_API_KEY=...
|
|
163
|
+
export ANTHROPIC_API_KEY=...
|
|
164
|
+
export XAI_API_KEY=...
|
|
165
|
+
|
|
166
|
+
# Default/fallback model.
|
|
167
|
+
devagent setup --provider openai --model YOUR_OPENAI_MODEL
|
|
168
|
+
|
|
169
|
+
# Optional per-role models.
|
|
170
|
+
devagent setup --role investigator --provider gemini --model YOUR_GEMINI_MODEL
|
|
171
|
+
devagent setup --role planner --provider anthropic --model YOUR_CLAUDE_MODEL
|
|
172
|
+
devagent setup --role implementer --provider openai --model YOUR_OPENAI_MODEL
|
|
173
|
+
devagent setup --role reviewer --provider xai --model YOUR_GROK_MODEL
|
|
174
|
+
|
|
175
|
+
# Inspect routing and optionally probe every configured cloud model.
|
|
176
|
+
devagent models
|
|
177
|
+
devagent doctor --live
|
|
178
|
+
|
|
179
|
+
# Run normally; saved role routing is applied automatically.
|
|
180
|
+
cd my-repo
|
|
181
|
+
devagent "Fix the checkout race condition and add regression coverage."
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
For example, a user may choose a fast or lower-cost model for repository investigation, a different model for planning, a preferred coding model for implementation, and another provider for independent review. This can be useful for cost, latency, provider diversity, or model-strength preferences, but it does not guarantee a better result. DevAgent still requires the same repository evidence, acceptance gates, deterministic verification, and publication rules.
|
|
185
|
+
|
|
186
|
+
When using saved role routing, run the task without run-level `--provider`, `--model`, or `--base-url` overrides. Supplying those flags explicitly selects one provider/model for that run instead of the saved per-role routing.
|
|
187
|
+
|
|
155
188
|
## Run
|
|
156
189
|
|
|
157
190
|
From the application repository:
|
|
@@ -121,6 +121,39 @@ reviewer → independently review final diff
|
|
|
121
121
|
|
|
122
122
|
The deterministic harness remains responsible for safety, tool execution, verification validity, acceptance adjudication, final status, reporting, and source-control publication regardless of which model handles a role.
|
|
123
123
|
|
|
124
|
+
#### Example: use multiple AI models in one DevAgent run
|
|
125
|
+
|
|
126
|
+
You do not have to use one AI model for every reasoning step. If you believe different models are better suited to different engineering roles, configure a default model plus any role-specific overrides. Roles that are not explicitly configured fall back to the default model.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Keep credentials in environment variables; DevAgent does not store the keys.
|
|
130
|
+
export OPENAI_API_KEY=...
|
|
131
|
+
export GEMINI_API_KEY=...
|
|
132
|
+
export ANTHROPIC_API_KEY=...
|
|
133
|
+
export XAI_API_KEY=...
|
|
134
|
+
|
|
135
|
+
# Default/fallback model.
|
|
136
|
+
devagent setup --provider openai --model YOUR_OPENAI_MODEL
|
|
137
|
+
|
|
138
|
+
# Optional per-role models.
|
|
139
|
+
devagent setup --role investigator --provider gemini --model YOUR_GEMINI_MODEL
|
|
140
|
+
devagent setup --role planner --provider anthropic --model YOUR_CLAUDE_MODEL
|
|
141
|
+
devagent setup --role implementer --provider openai --model YOUR_OPENAI_MODEL
|
|
142
|
+
devagent setup --role reviewer --provider xai --model YOUR_GROK_MODEL
|
|
143
|
+
|
|
144
|
+
# Inspect routing and optionally probe every configured cloud model.
|
|
145
|
+
devagent models
|
|
146
|
+
devagent doctor --live
|
|
147
|
+
|
|
148
|
+
# Run normally; saved role routing is applied automatically.
|
|
149
|
+
cd my-repo
|
|
150
|
+
devagent "Fix the checkout race condition and add regression coverage."
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
For example, a user may choose a fast or lower-cost model for repository investigation, a different model for planning, a preferred coding model for implementation, and another provider for independent review. This can be useful for cost, latency, provider diversity, or model-strength preferences, but it does not guarantee a better result. DevAgent still requires the same repository evidence, acceptance gates, deterministic verification, and publication rules.
|
|
154
|
+
|
|
155
|
+
When using saved role routing, run the task without run-level `--provider`, `--model`, or `--base-url` overrides. Supplying those flags explicitly selects one provider/model for that run instead of the saved per-role routing.
|
|
156
|
+
|
|
124
157
|
## Run
|
|
125
158
|
|
|
126
159
|
From the application repository:
|
|
@@ -4,10 +4,11 @@ import argparse
|
|
|
4
4
|
import importlib.util
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
|
+
import re
|
|
7
8
|
import shutil
|
|
8
9
|
import sys
|
|
9
10
|
from pathlib import Path
|
|
10
|
-
from typing import Sequence
|
|
11
|
+
from typing import Callable, Sequence
|
|
11
12
|
|
|
12
13
|
from devagent import __version__
|
|
13
14
|
from devagent.config import (
|
|
@@ -37,6 +38,84 @@ _LIVE_PROBE_SCHEMA = {
|
|
|
37
38
|
"additionalProperties": False,
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
_PROGRESS_STAGES: dict[str, tuple[int, str]] = {
|
|
42
|
+
"DISCOVER": (1, "DISCOVER / UNDERSTAND"),
|
|
43
|
+
"UNDERSTAND": (1, "DISCOVER / UNDERSTAND"),
|
|
44
|
+
"TASK_SPEC": (2, "REQUIREMENTS / PLAN"),
|
|
45
|
+
"BASELINE": (2, "REQUIREMENTS / PLAN"),
|
|
46
|
+
"PLAN": (2, "REQUIREMENTS / PLAN"),
|
|
47
|
+
"GATHER_CONTEXT": (2, "REQUIREMENTS / PLAN"),
|
|
48
|
+
"REPRODUCE": (2, "REQUIREMENTS / PLAN"),
|
|
49
|
+
"IMPLEMENT": (3, "IMPLEMENT"),
|
|
50
|
+
"VERIFY_TARGETED": (4, "VERIFY / REPAIR IF NEEDED"),
|
|
51
|
+
"VERIFY_BROAD": (4, "VERIFY / REPAIR IF NEEDED"),
|
|
52
|
+
"REVIEW": (5, "INDEPENDENT REVIEW"),
|
|
53
|
+
"QUALITY_CHECK": (6, "FINAL VERIFICATION"),
|
|
54
|
+
"FINAL_VERIFY": (6, "FINAL VERIFICATION"),
|
|
55
|
+
}
|
|
56
|
+
_STATE_LINE = re.compile(r"^\[([A-Z_]+)\]$")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class _ProgressStatus:
|
|
60
|
+
"""Render stable user-facing milestones while keeping full diagnostics opt-in."""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
sink: Callable[[str], None] = print,
|
|
65
|
+
*,
|
|
66
|
+
verbose: bool = False,
|
|
67
|
+
) -> None:
|
|
68
|
+
self.sink = sink
|
|
69
|
+
self.verbose = verbose
|
|
70
|
+
self._last_stage = 0
|
|
71
|
+
self._plan_seen = False
|
|
72
|
+
self._implement_seen = False
|
|
73
|
+
self._review_seen = False
|
|
74
|
+
|
|
75
|
+
def __call__(self, message: str) -> None:
|
|
76
|
+
if self.verbose:
|
|
77
|
+
self.sink(message)
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
match = _STATE_LINE.fullmatch(message)
|
|
81
|
+
if match is None:
|
|
82
|
+
return
|
|
83
|
+
state = match.group(1)
|
|
84
|
+
|
|
85
|
+
if state == "DIAGNOSE":
|
|
86
|
+
self.sink(" ↳ DIAGNOSE")
|
|
87
|
+
return
|
|
88
|
+
if state == "PLAN":
|
|
89
|
+
if self._plan_seen:
|
|
90
|
+
self.sink(" ↳ REPLAN")
|
|
91
|
+
return
|
|
92
|
+
self._plan_seen = True
|
|
93
|
+
if state == "IMPLEMENT":
|
|
94
|
+
if self._implement_seen:
|
|
95
|
+
label = "APPLY REVIEW FIXES" if self._review_seen else "APPLY CORRECTION"
|
|
96
|
+
self.sink(f" ↳ {label}")
|
|
97
|
+
return
|
|
98
|
+
self._implement_seen = True
|
|
99
|
+
if state == "REVIEW":
|
|
100
|
+
self._review_seen = True
|
|
101
|
+
|
|
102
|
+
stage = _PROGRESS_STAGES.get(state)
|
|
103
|
+
if stage is None:
|
|
104
|
+
return
|
|
105
|
+
number, label = stage
|
|
106
|
+
if number <= self._last_stage:
|
|
107
|
+
return
|
|
108
|
+
self._last_stage = number
|
|
109
|
+
self.sink(f"[{number}/7] {label}")
|
|
110
|
+
|
|
111
|
+
def report(self) -> None:
|
|
112
|
+
if self.verbose:
|
|
113
|
+
self.sink("[ENGINEERING_REPORT]")
|
|
114
|
+
return
|
|
115
|
+
if self._last_stage < 7:
|
|
116
|
+
self._last_stage = 7
|
|
117
|
+
self.sink("[7/7] ENGINEERING REPORT")
|
|
118
|
+
|
|
40
119
|
|
|
41
120
|
def _top_parser() -> argparse.ArgumentParser:
|
|
42
121
|
parser = argparse.ArgumentParser(prog="devagent", description="Evidence-driven local software engineering agent")
|
|
@@ -53,7 +132,11 @@ def _top_parser() -> argparse.ArgumentParser:
|
|
|
53
132
|
parser.add_argument("--provider", choices=_PROVIDER_CHOICES)
|
|
54
133
|
parser.add_argument("--model")
|
|
55
134
|
parser.add_argument("--base-url")
|
|
56
|
-
parser.add_argument(
|
|
135
|
+
parser.add_argument(
|
|
136
|
+
"--verbose",
|
|
137
|
+
action="store_true",
|
|
138
|
+
help="Show internal state transitions and diagnostics instead of concise progress stages",
|
|
139
|
+
)
|
|
57
140
|
parser.add_argument("--no-isolation", action="store_true", help="Work in place instead of creating a local detached worktree")
|
|
58
141
|
parser.add_argument(
|
|
59
142
|
"--publish",
|
|
@@ -337,11 +420,14 @@ def _run(argv: Sequence[str]) -> int:
|
|
|
337
420
|
from devagent.orchestrator import DevAgent
|
|
338
421
|
from devagent.report import recommendations_for, render_report
|
|
339
422
|
|
|
423
|
+
progress = _ProgressStatus(print, verbose=args.verbose)
|
|
340
424
|
result = DevAgent(
|
|
341
425
|
model_provider,
|
|
342
426
|
isolate=not args.no_isolation,
|
|
343
|
-
|
|
344
|
-
|
|
427
|
+
# Internal status events are always emitted. The progress reporter keeps normal
|
|
428
|
+
# CLI output concise and passes the full state/diagnostic stream only in --verbose.
|
|
429
|
+
verbose=True,
|
|
430
|
+
status=progress,
|
|
345
431
|
base_commit=publication_plan.base_commit if publication_plan else None,
|
|
346
432
|
).run(args.repo, requirement)
|
|
347
433
|
|
|
@@ -361,6 +447,7 @@ def _run(argv: Sequence[str]) -> int:
|
|
|
361
447
|
|
|
362
448
|
# The full engineering report is intentionally emitted before any Git commit/push.
|
|
363
449
|
result.recommendations = recommendations_for(result)
|
|
450
|
+
progress.report()
|
|
364
451
|
print(render_report(result))
|
|
365
452
|
|
|
366
453
|
if publish_requested:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devagent-ai
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.4
|
|
4
4
|
Summary: Evidence-driven local autonomous software engineering agent
|
|
5
5
|
Author: Tom Ha
|
|
6
6
|
Maintainer: Tom Ha
|
|
@@ -152,6 +152,39 @@ reviewer → independently review final diff
|
|
|
152
152
|
|
|
153
153
|
The deterministic harness remains responsible for safety, tool execution, verification validity, acceptance adjudication, final status, reporting, and source-control publication regardless of which model handles a role.
|
|
154
154
|
|
|
155
|
+
#### Example: use multiple AI models in one DevAgent run
|
|
156
|
+
|
|
157
|
+
You do not have to use one AI model for every reasoning step. If you believe different models are better suited to different engineering roles, configure a default model plus any role-specific overrides. Roles that are not explicitly configured fall back to the default model.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Keep credentials in environment variables; DevAgent does not store the keys.
|
|
161
|
+
export OPENAI_API_KEY=...
|
|
162
|
+
export GEMINI_API_KEY=...
|
|
163
|
+
export ANTHROPIC_API_KEY=...
|
|
164
|
+
export XAI_API_KEY=...
|
|
165
|
+
|
|
166
|
+
# Default/fallback model.
|
|
167
|
+
devagent setup --provider openai --model YOUR_OPENAI_MODEL
|
|
168
|
+
|
|
169
|
+
# Optional per-role models.
|
|
170
|
+
devagent setup --role investigator --provider gemini --model YOUR_GEMINI_MODEL
|
|
171
|
+
devagent setup --role planner --provider anthropic --model YOUR_CLAUDE_MODEL
|
|
172
|
+
devagent setup --role implementer --provider openai --model YOUR_OPENAI_MODEL
|
|
173
|
+
devagent setup --role reviewer --provider xai --model YOUR_GROK_MODEL
|
|
174
|
+
|
|
175
|
+
# Inspect routing and optionally probe every configured cloud model.
|
|
176
|
+
devagent models
|
|
177
|
+
devagent doctor --live
|
|
178
|
+
|
|
179
|
+
# Run normally; saved role routing is applied automatically.
|
|
180
|
+
cd my-repo
|
|
181
|
+
devagent "Fix the checkout race condition and add regression coverage."
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
For example, a user may choose a fast or lower-cost model for repository investigation, a different model for planning, a preferred coding model for implementation, and another provider for independent review. This can be useful for cost, latency, provider diversity, or model-strength preferences, but it does not guarantee a better result. DevAgent still requires the same repository evidence, acceptance gates, deterministic verification, and publication rules.
|
|
185
|
+
|
|
186
|
+
When using saved role routing, run the task without run-level `--provider`, `--model`, or `--base-url` overrides. Supplying those flags explicitly selects one provider/model for that run instead of the saved per-role routing.
|
|
187
|
+
|
|
155
188
|
## Run
|
|
156
189
|
|
|
157
190
|
From the application repository:
|
|
@@ -48,6 +48,7 @@ tests/test_benchmark_catalog.py
|
|
|
48
48
|
tests/test_browser_verification.py
|
|
49
49
|
tests/test_capability_discovery.py
|
|
50
50
|
tests/test_cli.py
|
|
51
|
+
tests/test_cli_progress.py
|
|
51
52
|
tests/test_developer_review_report.py
|
|
52
53
|
tests/test_discovery_memory.py
|
|
53
54
|
tests/test_e2e_fake_provider.py
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from devagent.cli import _ProgressStatus
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_default_progress_reports_only_stable_engineering_milestones() -> None:
|
|
7
|
+
output: list[str] = []
|
|
8
|
+
progress = _ProgressStatus(output.append)
|
|
9
|
+
|
|
10
|
+
events = [
|
|
11
|
+
"[PREFLIGHT]",
|
|
12
|
+
"[WORKTREE] source: /tmp/repo",
|
|
13
|
+
"[DISCOVER]",
|
|
14
|
+
"[DISCOVER] repository files: 120",
|
|
15
|
+
"[UNDERSTAND]",
|
|
16
|
+
"[RETRIEVAL] selected: src/service.py",
|
|
17
|
+
"[TASK_SPEC]",
|
|
18
|
+
"[BASELINE]",
|
|
19
|
+
"[PLAN]",
|
|
20
|
+
"[GATHER_CONTEXT]",
|
|
21
|
+
"[REPRODUCE]",
|
|
22
|
+
"[IMPLEMENT]",
|
|
23
|
+
"[VERIFY_TARGETED]",
|
|
24
|
+
"[DIAGNOSE]",
|
|
25
|
+
"[PLAN]",
|
|
26
|
+
"[GATHER_CONTEXT]",
|
|
27
|
+
"[IMPLEMENT]",
|
|
28
|
+
"[VERIFY_TARGETED]",
|
|
29
|
+
"[VERIFY_BROAD]",
|
|
30
|
+
"[REVIEW]",
|
|
31
|
+
"[QUALITY_CHECK]",
|
|
32
|
+
"[FINAL_VERIFY]",
|
|
33
|
+
"[REPORT]",
|
|
34
|
+
]
|
|
35
|
+
for event in events:
|
|
36
|
+
progress(event)
|
|
37
|
+
progress.report()
|
|
38
|
+
|
|
39
|
+
assert output == [
|
|
40
|
+
"[1/7] DISCOVER / UNDERSTAND",
|
|
41
|
+
"[2/7] REQUIREMENTS / PLAN",
|
|
42
|
+
"[3/7] IMPLEMENT",
|
|
43
|
+
"[4/7] VERIFY / REPAIR IF NEEDED",
|
|
44
|
+
" ↳ DIAGNOSE",
|
|
45
|
+
" ↳ REPLAN",
|
|
46
|
+
" ↳ APPLY CORRECTION",
|
|
47
|
+
"[5/7] INDEPENDENT REVIEW",
|
|
48
|
+
"[6/7] FINAL VERIFICATION",
|
|
49
|
+
"[7/7] ENGINEERING REPORT",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_review_correction_is_named_without_replaying_completed_stages() -> None:
|
|
54
|
+
output: list[str] = []
|
|
55
|
+
progress = _ProgressStatus(output.append)
|
|
56
|
+
|
|
57
|
+
for event in (
|
|
58
|
+
"[DISCOVER]",
|
|
59
|
+
"[TASK_SPEC]",
|
|
60
|
+
"[PLAN]",
|
|
61
|
+
"[IMPLEMENT]",
|
|
62
|
+
"[VERIFY_TARGETED]",
|
|
63
|
+
"[REVIEW]",
|
|
64
|
+
"[IMPLEMENT]",
|
|
65
|
+
"[VERIFY_TARGETED]",
|
|
66
|
+
"[REVIEW]",
|
|
67
|
+
"[FINAL_VERIFY]",
|
|
68
|
+
):
|
|
69
|
+
progress(event)
|
|
70
|
+
progress.report()
|
|
71
|
+
|
|
72
|
+
assert " ↳ APPLY REVIEW FIXES" in output
|
|
73
|
+
assert output.count("[3/7] IMPLEMENT") == 1
|
|
74
|
+
assert output.count("[4/7] VERIFY / REPAIR IF NEEDED") == 1
|
|
75
|
+
assert output.count("[5/7] INDEPENDENT REVIEW") == 1
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_verbose_progress_preserves_internal_state_and_diagnostics() -> None:
|
|
79
|
+
output: list[str] = []
|
|
80
|
+
progress = _ProgressStatus(output.append, verbose=True)
|
|
81
|
+
|
|
82
|
+
events = [
|
|
83
|
+
"[DISCOVER]",
|
|
84
|
+
"[WORKTREE] source: /tmp/repo",
|
|
85
|
+
"[RETRIEVAL] selected: src/service.py",
|
|
86
|
+
]
|
|
87
|
+
for event in events:
|
|
88
|
+
progress(event)
|
|
89
|
+
progress.report()
|
|
90
|
+
|
|
91
|
+
assert output == [*events, "[ENGINEERING_REPORT]"]
|
|
@@ -62,7 +62,7 @@ def test_release_version_is_semver_and_consistent() -> None:
|
|
|
62
62
|
version = match.group(1)
|
|
63
63
|
assert re.fullmatch(r"\d+\.\d+\.\d+", version)
|
|
64
64
|
assert version == __version__
|
|
65
|
-
assert version == "0.8.
|
|
65
|
+
assert version == "0.8.4"
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
def test_release_workflow_requires_green_exact_main_revision() -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|