agent-apprenticeship 0.1.5 → 0.1.7

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.
Files changed (34) hide show
  1. package/README.md +0 -197
  2. package/bin/agent-apprenticeship.js +85 -37
  3. package/package.json +1 -1
  4. package/pyproject.toml +1 -1
  5. package/src/agent_apprenticeship_trace/__init__.py +1 -1
  6. package/src/agent_apprenticeship_trace/actual_outputs_normalizer.py +104 -28
  7. package/src/agent_apprenticeship_trace/apprentice_adapters.py +3 -1
  8. package/src/agent_apprenticeship_trace/artifact_resolver.py +6 -0
  9. package/src/agent_apprenticeship_trace/bundle_exporter.py +132 -2
  10. package/src/agent_apprenticeship_trace/cli.py +1229 -269
  11. package/src/agent_apprenticeship_trace/codex_runner.py +89 -6
  12. package/src/agent_apprenticeship_trace/config.py +251 -32
  13. package/src/agent_apprenticeship_trace/ecosystem_r2.py +515 -0
  14. package/src/agent_apprenticeship_trace/env.py +5 -5
  15. package/src/agent_apprenticeship_trace/evaluator.py +127 -11
  16. package/src/agent_apprenticeship_trace/grader.py +12 -11
  17. package/src/agent_apprenticeship_trace/learning.py +270 -1
  18. package/src/agent_apprenticeship_trace/llm_output_normalizer.py +8 -7
  19. package/src/agent_apprenticeship_trace/loop.py +103 -4
  20. package/src/agent_apprenticeship_trace/loop_review.py +686 -0
  21. package/src/agent_apprenticeship_trace/mentor_checkpoints.py +49 -21
  22. package/src/agent_apprenticeship_trace/openai_structured.py +84 -14
  23. package/src/agent_apprenticeship_trace/package_exporter.py +1 -1
  24. package/src/agent_apprenticeship_trace/progress.py +2 -1
  25. package/src/agent_apprenticeship_trace/public_run.py +369 -57
  26. package/src/agent_apprenticeship_trace/public_sanitizer.py +40 -3
  27. package/src/agent_apprenticeship_trace/rubric_generation.py +11 -10
  28. package/src/agent_apprenticeship_trace/schemas.py +378 -3
  29. package/src/agent_apprenticeship_trace/task_intake.py +43 -9
  30. package/src/agent_apprenticeship_trace/tdo.py +2304 -0
  31. package/src/agent_apprenticeship_trace/trace_normalizer.py +351 -17
  32. package/src/agent_apprenticeship_trace/trace_prompt.py +38 -11
  33. package/src/agent_apprenticeship_trace/training_signals.py +1 -1
  34. package/src/agent_apprenticeship_trace/verifier.py +12 -6
@@ -6,10 +6,12 @@ import re
6
6
  from pathlib import Path
7
7
  from typing import Any
8
8
 
9
- from .config import Settings, get_settings, normalize_mentor_mode
9
+ from .config import Settings, apprenticeship_mode_display, get_settings, normalize_apprenticeship_mode, normalize_mentor_mode
10
10
  from .io import append_jsonl, read_json, read_jsonl, write_json
11
11
  from .public_sanitizer import sanitize_public_obj, sanitize_public_text
12
12
  from .release_exporter import create_release
13
+ from .tdo import tdo_manifest_fields_from_report
14
+ from .loop_review import summarize_loop_reviews
13
15
 
14
16
 
15
17
  def _count_jsonl(path: Path) -> int:
@@ -96,7 +98,7 @@ def contribution_counts(release_root: Path) -> dict[str, int]:
96
98
 
97
99
  def _write_card(bundle_root: Path) -> None:
98
100
  (bundle_root / "contribution_card.md").write_text(
99
- "# Agent Apprenticeship Contribution Bundle\n\n"
101
+ "# Agent Apprenticeship Agent Experience Package\n\n"
100
102
  "This local bundle packages an apprenticeship session for public ecosystem contribution. "
101
103
  "It includes session events, task instructions, traces, actual outputs, evaluation results, "
102
104
  "and learning-data views when available.\n\n"
@@ -110,6 +112,15 @@ def _session_mentor_mode(session: dict[str, Any], settings: Settings) -> str:
110
112
  return normalize_mentor_mode(session.get("mentor_mode") or session.get("evaluation_mode") or settings.mentor_mode)
111
113
 
112
114
 
115
+ def _session_apprenticeship_mode(session: dict[str, Any], settings: Settings) -> str:
116
+ return normalize_apprenticeship_mode(
117
+ session.get("apprenticeship_mode")
118
+ or session.get("mentor_mode")
119
+ or session.get("evaluation_mode")
120
+ or settings.apprenticeship_mode
121
+ )
122
+
123
+
113
124
  def _clean_session_metadata(session: dict[str, Any], settings: Settings) -> dict[str, Any]:
114
125
  allowed = {
115
126
  "run_id",
@@ -128,6 +139,8 @@ def _clean_session_metadata(session: dict[str, Any], settings: Settings) -> dict
128
139
  "session_status",
129
140
  }
130
141
  clean = {k: v for k, v in session.items() if k in allowed and v is not None}
142
+ clean["apprenticeship_mode"] = _session_apprenticeship_mode(session, settings)
143
+ clean["apprenticeship_mode_display"] = apprenticeship_mode_display(clean["apprenticeship_mode"])
131
144
  clean["mentor_mode"] = _session_mentor_mode(session, settings)
132
145
  return clean
133
146
 
@@ -141,6 +154,8 @@ def _copy_session_files(run_root: Path, bundle_root: Path, settings: Settings) -
141
154
  shutil.copytree(run_root / "task", bundle_root / "task", dirs_exist_ok=True)
142
155
  if (run_root / "mentor_checkpoints").exists():
143
156
  shutil.copytree(run_root / "mentor_checkpoints", bundle_root / "mentor_checkpoints", dirs_exist_ok=True)
157
+ if (run_root / "loops").exists():
158
+ shutil.copytree(run_root / "loops", bundle_root / "loops", dirs_exist_ok=True)
144
159
 
145
160
 
146
161
  def _copy_clean_bundle_files(release_root: Path, bundle_root: Path, include_debug: bool) -> None:
@@ -153,6 +168,9 @@ def _copy_clean_bundle_files(release_root: Path, bundle_root: Path, include_debu
153
168
  _copy_jsonl_if_nonempty(release_root / "actual_outputs.jsonl", bundle_root / "outputs" / "actual_outputs.jsonl")
154
169
  _copy_json_if_exists(release_root / "artifacts_index.json", bundle_root / "outputs" / "artifacts_index.json")
155
170
  _copy_indexed_package_files(release_root, bundle_root)
171
+ _copy_tdo_outputs(release_root, bundle_root)
172
+ _copy_experience_compiler_outputs(release_root, bundle_root)
173
+ _copy_loop_review_outputs(release_root, bundle_root)
156
174
 
157
175
  for name in [
158
176
  "grader_results.jsonl",
@@ -214,6 +232,42 @@ def _copy_indexed_package_files(release_root: Path, bundle_root: Path) -> None:
214
232
  write_json(bundle_root / "outputs" / "artifacts_index.json", rewritten)
215
233
 
216
234
 
235
+ def _copy_tdo_outputs(release_root: Path, bundle_root: Path) -> None:
236
+ package_tdo_dirs = sorted(path for path in (release_root / "packages").glob("*/tdo") if path.is_dir())
237
+ if not package_tdo_dirs:
238
+ return
239
+ if len(package_tdo_dirs) == 1:
240
+ shutil.copytree(package_tdo_dirs[0], bundle_root / "tdo", dirs_exist_ok=True)
241
+ return
242
+ for src in package_tdo_dirs:
243
+ target = bundle_root / "tdo" / src.parent.name
244
+ shutil.copytree(src, target, dirs_exist_ok=True)
245
+
246
+
247
+ def _copy_experience_compiler_outputs(release_root: Path, bundle_root: Path) -> None:
248
+ package_dirs = sorted(path for path in (release_root / "packages").glob("*/experience_compiler") if path.is_dir())
249
+ if not package_dirs:
250
+ return
251
+ if len(package_dirs) == 1:
252
+ shutil.copytree(package_dirs[0], bundle_root / "experience_compiler", dirs_exist_ok=True)
253
+ return
254
+ for src in package_dirs:
255
+ target = bundle_root / "experience_compiler" / src.parent.name
256
+ shutil.copytree(src, target, dirs_exist_ok=True)
257
+
258
+
259
+ def _copy_loop_review_outputs(release_root: Path, bundle_root: Path) -> None:
260
+ package_dirs = sorted(path for path in (release_root / "packages").glob("*/loops") if path.is_dir())
261
+ if not package_dirs:
262
+ return
263
+ if len(package_dirs) == 1:
264
+ shutil.copytree(package_dirs[0], bundle_root / "loops", dirs_exist_ok=True)
265
+ return
266
+ for src in package_dirs:
267
+ target = bundle_root / "loops" / src.parent.name
268
+ shutil.copytree(src, target, dirs_exist_ok=True)
269
+
270
+
217
271
  def is_unsafe_bundle_ref(ref: str) -> bool:
218
272
  path = Path(ref)
219
273
  return path.is_absolute() or ".." in path.parts
@@ -263,6 +317,8 @@ def _bundle_metadata_shape(bundle_root: Path, release_root: Path, settings: Sett
263
317
  "agent_apprentice_role": role,
264
318
  "expected_economic_value": task.get("expected_economic_value"),
265
319
  "expected_economic_value_for_agent_apprentice": task.get("expected_economic_value_for_agent_apprentice"),
320
+ "apprenticeship_mode": _session_apprenticeship_mode(session, settings),
321
+ "apprenticeship_mode_display": apprenticeship_mode_display(_session_apprenticeship_mode(session, settings)),
266
322
  "mentor_mode": _session_mentor_mode(session, settings),
267
323
  "task_status": task_status,
268
324
  "run_status": run_status,
@@ -280,9 +336,83 @@ def _write_manifest(bundle_root: Path, release_root: Path, settings: Settings, i
280
336
  manifest["status_reason"] = session["status_reason"]
281
337
  if include_internal_schema:
282
338
  manifest["source_release_schema_version"] = release_manifest.get("schema_version")
339
+ manifest.update(_tdo_manifest_shape(release_root))
340
+ manifest.update(_loop_manifest_shape(release_root))
283
341
  write_json(bundle_root / "contribution_manifest.json", manifest)
284
342
 
285
343
 
344
+ def _loop_manifest_shape(release_root: Path) -> dict[str, Any]:
345
+ summary = summarize_loop_reviews(release_root)
346
+ return {
347
+ "has_loop_review_packets": summary.get("has_loop_review_packets"),
348
+ "loop_iteration_count": summary.get("loop_iteration_count"),
349
+ "loop_reviewer_types": summary.get("reviewer_types") or [],
350
+ "final_loop_verdict": summary.get("final_loop_verdict"),
351
+ "loop_review_refs": summary.get("loop_review_refs") or [],
352
+ }
353
+
354
+
355
+ def _tdo_manifest_shape(release_root: Path) -> dict[str, Any]:
356
+ reports = []
357
+ for path in sorted((release_root / "packages").glob("*/tdo/tdo_report.json")):
358
+ try:
359
+ reports.append(read_json(path))
360
+ except Exception:
361
+ continue
362
+ if not reports:
363
+ return {
364
+ "tdo_enabled": False,
365
+ "tdo_status": "not_run",
366
+ "tdo_output_refs": [],
367
+ "experience_compiler_enabled": False,
368
+ "experience_compiler_status": "not_run",
369
+ "experience_compiler_output_refs": [],
370
+ }
371
+ latest = reports[-1]
372
+ output_refs: list[str] = []
373
+ package_tdo_dirs = sorted(path for path in (release_root / "packages").glob("*/tdo") if path.is_dir())
374
+ if len(package_tdo_dirs) == 1:
375
+ for child in sorted(package_tdo_dirs[0].iterdir()):
376
+ if child.is_file():
377
+ output_refs.append(f"tdo/{child.name}")
378
+ else:
379
+ for src in package_tdo_dirs:
380
+ for child in sorted(src.iterdir()):
381
+ if child.is_file():
382
+ output_refs.append(f"tdo/{src.parent.name}/{child.name}")
383
+ fields = tdo_manifest_fields_from_report(latest)
384
+ fields["tdo_output_refs"] = output_refs
385
+ fields.update(_experience_compiler_manifest_shape(release_root, latest))
386
+ if len(reports) > 1:
387
+ fields["tdo_package_count"] = len(reports)
388
+ return fields
389
+
390
+
391
+ def _experience_compiler_manifest_shape(release_root: Path, latest_report: dict[str, Any]) -> dict[str, Any]:
392
+ compiler_dirs = sorted(path for path in (release_root / "packages").glob("*/experience_compiler") if path.is_dir())
393
+ refs: list[str] = []
394
+ if len(compiler_dirs) == 1:
395
+ for child in sorted(compiler_dirs[0].rglob("*")):
396
+ if child.is_file():
397
+ refs.append(f"experience_compiler/{child.relative_to(compiler_dirs[0]).as_posix()}")
398
+ else:
399
+ for src in compiler_dirs:
400
+ for child in sorted(src.rglob("*")):
401
+ if child.is_file():
402
+ refs.append(f"experience_compiler/{src.parent.name}/{child.relative_to(src).as_posix()}")
403
+ return {
404
+ "experience_compiler_enabled": bool(compiler_dirs),
405
+ "experience_compiler_status": latest_report.get("tdo_status"),
406
+ "experience_compiler_id": str(latest_report.get("tdo_id") or "").replace("tdo_", "compiler_", 1),
407
+ "experience_compiler_output_refs": refs,
408
+ "experience_compiler_rows_by_type": latest_report.get("rows_accepted_by_type") or {},
409
+ "experience_compiler_rounds_run": latest_report.get("rounds_run"),
410
+ "experience_compiler_average_quality_score": latest_report.get("average_quality_score"),
411
+ "experience_compiler_average_reuse_value_score": latest_report.get("average_reuse_value_score"),
412
+ "experience_compiler_judge_source": latest_report.get("tdo_judge_source"),
413
+ }
414
+
415
+
286
416
  def create_contribution_bundle(
287
417
  run_root: Path,
288
418
  bundle_root: Path | None = None,