agentic-dev-loop 0.12.2__py3-none-any.whl → 0.13.0__py3-none-any.whl

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.
@@ -206,6 +206,71 @@ def _run_copilot_models(argv: list[str]) -> int:
206
206
  return 0
207
207
 
208
208
 
209
+ def _report_parser() -> argparse.ArgumentParser:
210
+ parser = argparse.ArgumentParser(
211
+ prog="agentic-dev-loop report",
212
+ description="Report accumulated agentic-dev-loop run history as "
213
+ "read-only markdown.")
214
+ parser.add_argument("run_id", nargs="?", default=None,
215
+ help="12-hex run dir name for a deep dive "
216
+ "(default: aggregate report)")
217
+ parser.add_argument("--since", default=None,
218
+ help="only threads starting at or after this ISO "
219
+ "datetime")
220
+ parser.add_argument("--until", default=None,
221
+ help="only threads starting before this ISO datetime")
222
+ parser.add_argument("--status", action="append", default=None,
223
+ help="filter by status (success/failed/interrupted/"
224
+ "running); repeatable or comma-separated")
225
+ parser.add_argument("--runs-root", default=None,
226
+ help="runs root (default: $AGENTIC_DEV_LOOP_RUNS_ROOT "
227
+ "or ~/.agentic-dev-loop/runs)")
228
+ parser.add_argument("--audit-dir", "--state-dir", dest="audit_dir",
229
+ default=None,
230
+ help="sandbox audit dir (default: "
231
+ "$AGENTIC_DEV_LOOP_STATE_DIR or "
232
+ "~/.agentic-dev-loop/state)")
233
+ return parser
234
+
235
+
236
+ def _run_report(argv: list[str]) -> int:
237
+ from agentic_dev_loop.reporting import (
238
+ apply_filters, build_run_records, discover, find_run_dir,
239
+ pure_metrics, read_audit, read_dir, render_markdown, runs_root)
240
+
241
+ args = _report_parser().parse_args(argv)
242
+ root = runs_root(args.runs_root)
243
+ notice = None
244
+ if args.run_id is not None:
245
+ run_dir = find_run_dir(args.run_id, root)
246
+ if run_dir is None:
247
+ print(f"report: unknown run id: {args.run_id}", file=sys.stderr)
248
+ return 1
249
+ dirs = [run_dir]
250
+ else:
251
+ dirs = discover(root)
252
+ if not root.is_dir():
253
+ notice = f"runs root not found: {root}"
254
+ audit_pool = read_audit(args.audit_dir)
255
+ records = build_run_records([read_dir(path) for path in dirs], audit_pool)
256
+ filters = {key: getattr(args, key)
257
+ for key in ("since", "until", "status") if getattr(args, key)}
258
+ try:
259
+ records = apply_filters(
260
+ records, since=args.since, until=args.until,
261
+ statuses=args.status)
262
+ except ValueError as exc:
263
+ print(f"report: {exc}", file=sys.stderr)
264
+ return 1
265
+ if not records and notice is None:
266
+ notice = "no runs recorded" if not dirs else "no runs matched filters"
267
+ metrics = pure_metrics(records)
268
+ sys.stdout.write(render_markdown(
269
+ records, metrics, deep_dive=args.run_id is not None,
270
+ filters=filters, notice=notice))
271
+ return 0
272
+
273
+
209
274
  def build_parser(cfg_path) -> argparse.ArgumentParser:
210
275
  """The full parser for one pipeline: core flags + loader-contributed."""
211
276
  registry, _ = _registry_for(cfg_path)
@@ -226,6 +291,8 @@ def main(argv: list[str] | None = None, *, keep_alive: bool = True) -> int:
226
291
  return _run_copilot_login(argv[1:])
227
292
  if argv and argv[0] == "copilot-models":
228
293
  return _run_copilot_models(argv[1:])
294
+ if argv and argv[0] == "report":
295
+ return _run_report(argv[1:])
229
296
  if argv and argv[0] == "run-status":
230
297
  from .run_status import _run_status
231
298
  return _run_status(argv[1:])
@@ -27,6 +27,7 @@ from .hostboundary import (check_orchestrator_install,
27
27
  from .isolation import startup_sandbox
28
28
  from .llm import build_llm
29
29
  from .loaders import resolve_docs
30
+ from .provider_wire import provider_name
30
31
  from .secrets import resolve_secrets, scan_env_files
31
32
  from .registry import (Registry, default_registry, load_extensions,
32
33
  validate_action_mounts_egress, validate_action_network)
@@ -291,7 +292,7 @@ def _run_pipeline(cfg, base, registry, state_dir, max_attempts, args, viz_bus,
291
292
  httpd, _thread = viz.serve_viz(
292
293
  bus, topology["mermaid"], start_state["subject"],
293
294
  args.viz_port, topology["nodes"], topology["flow"],
294
- topology["edges"])
295
+ topology["edges"], provider_name(cfg.llm.base_url))
295
296
  bound = httpd.server_address[1]
296
297
  url = f"http://127.0.0.1:{bound}"
297
298
  if args.viz_port and bound != args.viz_port:
@@ -40,6 +40,13 @@ def adapter_for(base_url: str | None) -> WireAdapter | None:
40
40
  return WIRE_ADAPTERS.get(base_url.rstrip("/"))
41
41
 
42
42
 
43
+ def provider_name(base_url: str | None) -> str:
44
+ """Display name of the LLM provider behind a base URL."""
45
+ if base_url is not None and base_url.rstrip("/") == COPILOT_BASE_URL:
46
+ return "Copilot"
47
+ return "OpenAI"
48
+
49
+
43
50
  class WireShapeError(RuntimeError):
44
51
  """A surfaced or outgoing wire shape that cannot carry a tool call.
45
52
 
@@ -0,0 +1,43 @@
1
+ """Read-only run-history reporting (unit 12)."""
2
+
3
+ from .metrics import Metric, apply_filters, pure_metrics
4
+ from .render import render_markdown
5
+ from .sources import (
6
+ AuditRecord,
7
+ Attempt,
8
+ DirData,
9
+ ProseFacts,
10
+ RunRecord,
11
+ StepVerdict,
12
+ audit_dir,
13
+ build_run_records,
14
+ discover,
15
+ find_run_dir,
16
+ is_test_command,
17
+ parse_ts,
18
+ read_audit,
19
+ read_dir,
20
+ runs_root,
21
+ )
22
+
23
+ __all__ = [
24
+ "AuditRecord",
25
+ "Attempt",
26
+ "DirData",
27
+ "Metric",
28
+ "ProseFacts",
29
+ "RunRecord",
30
+ "StepVerdict",
31
+ "apply_filters",
32
+ "audit_dir",
33
+ "build_run_records",
34
+ "discover",
35
+ "find_run_dir",
36
+ "is_test_command",
37
+ "parse_ts",
38
+ "pure_metrics",
39
+ "read_audit",
40
+ "read_dir",
41
+ "render_markdown",
42
+ "runs_root",
43
+ ]