agent-apprenticeship 0.1.6 → 0.1.8
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.
- package/bin/agent-apprenticeship.js +85 -37
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/agent_apprenticeship_trace/__init__.py +1 -1
- package/src/agent_apprenticeship_trace/actual_outputs_normalizer.py +104 -28
- package/src/agent_apprenticeship_trace/apprentice_adapters.py +3 -1
- package/src/agent_apprenticeship_trace/artifact_resolver.py +6 -0
- package/src/agent_apprenticeship_trace/bundle_exporter.py +132 -2
- package/src/agent_apprenticeship_trace/cli.py +1171 -262
- package/src/agent_apprenticeship_trace/codex_runner.py +89 -6
- package/src/agent_apprenticeship_trace/config.py +251 -32
- package/src/agent_apprenticeship_trace/ecosystem_r2.py +515 -0
- package/src/agent_apprenticeship_trace/env.py +5 -5
- package/src/agent_apprenticeship_trace/evaluator.py +127 -11
- package/src/agent_apprenticeship_trace/grader.py +12 -11
- package/src/agent_apprenticeship_trace/learning.py +270 -1
- package/src/agent_apprenticeship_trace/llm_output_normalizer.py +8 -7
- package/src/agent_apprenticeship_trace/loop.py +103 -4
- package/src/agent_apprenticeship_trace/loop_review.py +686 -0
- package/src/agent_apprenticeship_trace/mentor_checkpoints.py +49 -21
- package/src/agent_apprenticeship_trace/openai_structured.py +84 -14
- package/src/agent_apprenticeship_trace/package_exporter.py +1 -1
- package/src/agent_apprenticeship_trace/progress.py +2 -1
- package/src/agent_apprenticeship_trace/public_run.py +369 -57
- package/src/agent_apprenticeship_trace/public_sanitizer.py +37 -1
- package/src/agent_apprenticeship_trace/rubric_generation.py +11 -10
- package/src/agent_apprenticeship_trace/schemas.py +378 -3
- package/src/agent_apprenticeship_trace/task_intake.py +43 -9
- package/src/agent_apprenticeship_trace/tdo.py +2304 -0
- package/src/agent_apprenticeship_trace/trace_normalizer.py +351 -17
- package/src/agent_apprenticeship_trace/trace_prompt.py +38 -11
- package/src/agent_apprenticeship_trace/training_signals.py +1 -1
- package/src/agent_apprenticeship_trace/verifier.py +12 -6
|
@@ -9,13 +9,108 @@ from pathlib import Path
|
|
|
9
9
|
|
|
10
10
|
from .bundle_exporter import create_contribution_bundle
|
|
11
11
|
from .config import Settings, apprentice_agent_display_name, apprentice_agent_readiness_status, get_settings, settings_override
|
|
12
|
+
from .env import redact_secrets
|
|
12
13
|
from .io import read_json, write_json
|
|
13
14
|
from .loop import run_task
|
|
15
|
+
from .loop_review import record_followup_review_update, record_human_loop_feedback
|
|
14
16
|
from .mentor_checkpoints import write_mentor_checkpoints
|
|
15
17
|
from .progress import ProgressCallback, append_progress_event, update_run_status
|
|
16
18
|
from .recipes import WORKER_AGENT_RECIPES
|
|
17
19
|
from .schemas import RawTaskRecord
|
|
18
20
|
from .session_events import append_session_event, backfill_session_event_task_ids, next_followup_index
|
|
21
|
+
from .tdo import run_tdo_for_run, utc_now
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _write_failed_tdo_reports(run_root: Path, settings: Settings, error: str) -> None:
|
|
25
|
+
packages = sorted((run_root / "packages").glob("*")) if (run_root / "packages").exists() else []
|
|
26
|
+
for pkg in packages:
|
|
27
|
+
tdo_dir = pkg / "tdo"
|
|
28
|
+
tdo_dir.mkdir(parents=True, exist_ok=True)
|
|
29
|
+
safe_pkg = re.sub(r"[^A-Za-z0-9_]+", "_", pkg.name).strip("_") or "package"
|
|
30
|
+
report = {
|
|
31
|
+
"tdo_id": f"tdo_{safe_pkg}_failed",
|
|
32
|
+
"source_package_id": pkg.name,
|
|
33
|
+
"source_task_id": pkg.name,
|
|
34
|
+
"created_at": utc_now(),
|
|
35
|
+
"generator_mode": settings.worker_agent,
|
|
36
|
+
"tdo_judge_source": "apprentice_self_judge",
|
|
37
|
+
"mentor_audited": False,
|
|
38
|
+
"rounds_run": 0,
|
|
39
|
+
"stop_reason": "tdo_runtime_error",
|
|
40
|
+
"tdo_status": "failed",
|
|
41
|
+
"rows_generated_by_type": {},
|
|
42
|
+
"rows_accepted_by_type": {},
|
|
43
|
+
"rows_rejected_by_type": {},
|
|
44
|
+
"schema_validation_passed": False,
|
|
45
|
+
"sanitization_passed": False,
|
|
46
|
+
"weak_strong_proxy_available": False,
|
|
47
|
+
"grpo_suitability_distribution": {},
|
|
48
|
+
"omitted_outputs": ["experience_compiler_outputs"],
|
|
49
|
+
"generation_notes": [error],
|
|
50
|
+
"recommended_uses": [],
|
|
51
|
+
"metadata_json": {"failure_recorded_by": "runtime_guardrail"},
|
|
52
|
+
}
|
|
53
|
+
write_json(tdo_dir / "tdo_report.json", report)
|
|
54
|
+
write_json(tdo_dir / "tdo_manifest.json", {
|
|
55
|
+
"schema_version": "aa-tdo-v0.1",
|
|
56
|
+
"tdo_id": report["tdo_id"],
|
|
57
|
+
"tdo_status": "failed",
|
|
58
|
+
"source_package_id": pkg.name,
|
|
59
|
+
"source_task_id": pkg.name,
|
|
60
|
+
"tdo_output_refs": ["tdo/tdo_report.json", "tdo/tdo_manifest.json"],
|
|
61
|
+
"tdo_judge_source": "apprentice_self_judge",
|
|
62
|
+
"mentor_audited": False,
|
|
63
|
+
"rounds_run": 0,
|
|
64
|
+
"rows_by_type": {},
|
|
65
|
+
"created_at": report["created_at"],
|
|
66
|
+
})
|
|
67
|
+
compiler_dir = pkg / "experience_compiler"
|
|
68
|
+
compiler_dir.mkdir(parents=True, exist_ok=True)
|
|
69
|
+
write_json(compiler_dir / "compiler_report.json", {
|
|
70
|
+
"compiler_status": "failed",
|
|
71
|
+
"source_package_id": pkg.name,
|
|
72
|
+
"error": error,
|
|
73
|
+
"created_at": report["created_at"],
|
|
74
|
+
})
|
|
75
|
+
write_json(compiler_dir / "compiler_manifest.json", {
|
|
76
|
+
"schema_version": "aa-experience-compiler-v0.1",
|
|
77
|
+
"compiler_status": "failed",
|
|
78
|
+
"source_package_id": pkg.name,
|
|
79
|
+
"compiler_output_refs": ["experience_compiler/compiler_report.json", "experience_compiler/compiler_manifest.json"],
|
|
80
|
+
"created_at": report["created_at"],
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _safe_run_tdo_for_run(
|
|
85
|
+
run_root: Path,
|
|
86
|
+
settings: Settings,
|
|
87
|
+
*,
|
|
88
|
+
progress_callback: ProgressCallback | None = None,
|
|
89
|
+
followup_index: int | None = None,
|
|
90
|
+
record_only: bool = False,
|
|
91
|
+
) -> dict:
|
|
92
|
+
try:
|
|
93
|
+
return run_tdo_for_run(
|
|
94
|
+
run_root,
|
|
95
|
+
settings,
|
|
96
|
+
progress_callback=progress_callback,
|
|
97
|
+
followup_index=followup_index,
|
|
98
|
+
record_only=record_only,
|
|
99
|
+
)
|
|
100
|
+
except Exception as exc:
|
|
101
|
+
safe = redact_secrets(str(exc))[:500]
|
|
102
|
+
_write_failed_tdo_reports(run_root, settings, safe)
|
|
103
|
+
write_json(run_root / "tdo_status.json", {"tdo_status": "failed", "error": safe, "updated_at": utc_now()})
|
|
104
|
+
append_progress_event(
|
|
105
|
+
run_root,
|
|
106
|
+
"tdo_failed",
|
|
107
|
+
run_id=run_root.name,
|
|
108
|
+
message=f"Experience Compiler failed: {safe}",
|
|
109
|
+
phase="experience_compiler_failed",
|
|
110
|
+
metadata_json={"followup_index": followup_index} if followup_index else None,
|
|
111
|
+
callback=progress_callback,
|
|
112
|
+
)
|
|
113
|
+
return {"tdo_status": "failed", "error": safe}
|
|
19
114
|
|
|
20
115
|
|
|
21
116
|
class RunInterrupted(Exception):
|
|
@@ -152,14 +247,14 @@ def _checkpoint_auto_approve(settings: Settings) -> bool:
|
|
|
152
247
|
|
|
153
248
|
def _checkpoint_review_labels(settings: Settings, revision_requested: bool | None = None) -> tuple[str, str]:
|
|
154
249
|
if settings.mentor_mode == "hybrid":
|
|
155
|
-
pending = "
|
|
250
|
+
pending = "Expert-led model audit draft complete - human confirmation pending"
|
|
156
251
|
if revision_requested is None:
|
|
157
|
-
return pending, "
|
|
158
|
-
return pending, "
|
|
159
|
-
pending = "Expert
|
|
252
|
+
return pending, "Expert-led human confirmation complete"
|
|
253
|
+
return pending, "Expert-led human confirmation complete - revision requested" if revision_requested else "Expert-led human confirmation complete - finish selected"
|
|
254
|
+
pending = "Expert audit pending"
|
|
160
255
|
if revision_requested is None:
|
|
161
|
-
return pending, "Expert
|
|
162
|
-
return pending, "Expert
|
|
256
|
+
return pending, "Expert audit complete"
|
|
257
|
+
return pending, "Expert audit complete - revision requested" if revision_requested else "Expert audit complete - finish selected"
|
|
163
258
|
|
|
164
259
|
|
|
165
260
|
def _pre_attempt_checkpoint_callback(
|
|
@@ -170,6 +265,17 @@ def _pre_attempt_checkpoint_callback(
|
|
|
170
265
|
followup_index: int | None = None,
|
|
171
266
|
):
|
|
172
267
|
def _callback(_pkg: Path) -> None:
|
|
268
|
+
append_progress_event(
|
|
269
|
+
run_root,
|
|
270
|
+
"apprentice_task_spec_ready",
|
|
271
|
+
run_id=run_root.name,
|
|
272
|
+
message=("Follow-up %s Apprentice Agent updated task-intake/rubric draft" % followup_index if followup_index else "Apprentice Agent drafted task intake and rubric"),
|
|
273
|
+
current_loop=1,
|
|
274
|
+
maximum_improvement_loops=settings.max_improvement_loops,
|
|
275
|
+
phase="task_intake_rubric",
|
|
276
|
+
metadata_json={"followup_index": followup_index, "draft_author": "apprentice_agent"} if followup_index else {"draft_author": "apprentice_agent"},
|
|
277
|
+
callback=progress_callback,
|
|
278
|
+
)
|
|
173
279
|
if _human_checkpoint_mode(settings):
|
|
174
280
|
write_mentor_checkpoints(
|
|
175
281
|
run_root,
|
|
@@ -227,34 +333,40 @@ def _revision_decision_callback(
|
|
|
227
333
|
def _callback(pkg: Path) -> bool:
|
|
228
334
|
status, _reason = _session_status_for_package(pkg)
|
|
229
335
|
traced_steps, artifact_count, artifacts_path, operational_error = _package_progress_summary(run_root, pkg)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
336
|
+
if not state.get("apprentice_completed_emitted"):
|
|
337
|
+
append_progress_event(
|
|
338
|
+
run_root,
|
|
339
|
+
"apprentice_attempt_completed",
|
|
340
|
+
run_id=run_root.name,
|
|
341
|
+
message=("Apprentice attempt failed - operational error" if operational_error else ("Follow-up %s Apprentice attempt complete" % followup_index if followup_index else "Apprentice attempt complete")),
|
|
342
|
+
current_loop=1,
|
|
343
|
+
maximum_improvement_loops=settings.max_improvement_loops,
|
|
344
|
+
phase="apprentice_attempt_complete",
|
|
345
|
+
traced_steps=traced_steps,
|
|
346
|
+
artifact_count=artifact_count,
|
|
347
|
+
artifacts_path=artifacts_path,
|
|
348
|
+
operational_error=operational_error,
|
|
349
|
+
metadata_json={"followup_index": followup_index} if followup_index else None,
|
|
350
|
+
callback=progress_callback,
|
|
351
|
+
)
|
|
352
|
+
state["apprentice_completed_emitted"] = True
|
|
246
353
|
if operational_error:
|
|
247
354
|
return False
|
|
248
355
|
pending, _ = _checkpoint_review_labels(settings)
|
|
356
|
+
review_packet = pkg / "loops" / "iterations" / "001" / "review_packet.md"
|
|
249
357
|
append_progress_event(
|
|
250
358
|
run_root,
|
|
251
359
|
"mentor_review_started",
|
|
252
360
|
run_id=run_root.name,
|
|
253
|
-
message=pending,
|
|
361
|
+
message=f"{pending} - review packet ready",
|
|
254
362
|
current_loop=1,
|
|
255
363
|
maximum_improvement_loops=settings.max_improvement_loops,
|
|
256
364
|
phase="expert_review" if settings.mentor_mode == "expert_led" else "hybrid_human_approval",
|
|
257
|
-
metadata_json={
|
|
365
|
+
metadata_json={
|
|
366
|
+
**({"followup_index": followup_index} if followup_index else {}),
|
|
367
|
+
"review_packet_ref": str(review_packet.relative_to(pkg)) if review_packet.exists() else None,
|
|
368
|
+
"review_packet_path": str(review_packet) if review_packet.exists() else None,
|
|
369
|
+
},
|
|
258
370
|
callback=progress_callback,
|
|
259
371
|
)
|
|
260
372
|
update_run_status(
|
|
@@ -276,7 +388,15 @@ def _revision_decision_callback(
|
|
|
276
388
|
)
|
|
277
389
|
revision_path = run_root / "mentor_checkpoints" / "revision_checkpoint.json"
|
|
278
390
|
revision = read_json(revision_path) if revision_path.exists() else {}
|
|
391
|
+
evaluation_path = run_root / "mentor_checkpoints" / "evaluation_checkpoint.json"
|
|
392
|
+
evaluation = read_json(evaluation_path) if evaluation_path.exists() else {}
|
|
279
393
|
revision_requested = bool(revision.get("revision_should_run")) and settings.max_improvement_loops > 1
|
|
394
|
+
record_human_loop_feedback(
|
|
395
|
+
pkg,
|
|
396
|
+
iteration=1,
|
|
397
|
+
checkpoint={**evaluation, **revision, "evidence_refs": ["loops/iterations/001/review_packet.json", "loops/iterations/001/review_packet.md"]},
|
|
398
|
+
revision_requested=revision_requested,
|
|
399
|
+
)
|
|
280
400
|
_, complete = _checkpoint_review_labels(settings, revision_requested)
|
|
281
401
|
append_progress_event(
|
|
282
402
|
run_root,
|
|
@@ -435,6 +555,56 @@ def _package_progress_summary(run_root: Path, pkg: Path) -> tuple[int, int, Path
|
|
|
435
555
|
return traced_steps, artifact_count, artifacts_path, operational_error
|
|
436
556
|
|
|
437
557
|
|
|
558
|
+
def _attempt_complete_callback(
|
|
559
|
+
run_root: Path,
|
|
560
|
+
settings: Settings,
|
|
561
|
+
*,
|
|
562
|
+
progress_callback: ProgressCallback | None,
|
|
563
|
+
followup_index: int | None = None,
|
|
564
|
+
state: dict[str, bool] | None = None,
|
|
565
|
+
):
|
|
566
|
+
def _callback(pkg: Path, attempt_kind: str) -> None:
|
|
567
|
+
if attempt_kind != "baseline":
|
|
568
|
+
return
|
|
569
|
+
traced_steps, artifact_count, artifacts_path, operational_error = _package_progress_summary(run_root, pkg)
|
|
570
|
+
append_progress_event(
|
|
571
|
+
run_root,
|
|
572
|
+
"apprentice_attempt_completed",
|
|
573
|
+
run_id=run_root.name,
|
|
574
|
+
message=("Apprentice attempt failed - operational error" if operational_error else (f"Follow-up {followup_index} Apprentice attempt complete" if followup_index else "Apprentice attempt complete")),
|
|
575
|
+
current_loop=1,
|
|
576
|
+
maximum_improvement_loops=settings.max_improvement_loops,
|
|
577
|
+
phase="apprentice_attempt_complete",
|
|
578
|
+
traced_steps=traced_steps,
|
|
579
|
+
artifact_count=artifact_count,
|
|
580
|
+
artifacts_path=artifacts_path,
|
|
581
|
+
operational_error=operational_error,
|
|
582
|
+
metadata_json={"followup_index": followup_index} if followup_index else None,
|
|
583
|
+
callback=progress_callback,
|
|
584
|
+
)
|
|
585
|
+
if state is not None:
|
|
586
|
+
state["apprentice_completed_emitted"] = True
|
|
587
|
+
if not operational_error and not _human_checkpoint_mode(settings):
|
|
588
|
+
append_progress_event(
|
|
589
|
+
run_root,
|
|
590
|
+
"mentor_review_started",
|
|
591
|
+
run_id=run_root.name,
|
|
592
|
+
message=(f"Follow-up {followup_index} Mentor audit started" if followup_index else "Mentor audit started"),
|
|
593
|
+
current_loop=1,
|
|
594
|
+
maximum_improvement_loops=settings.max_improvement_loops,
|
|
595
|
+
phase="mentor_review",
|
|
596
|
+
traced_steps=traced_steps,
|
|
597
|
+
artifact_count=artifact_count,
|
|
598
|
+
artifacts_path=artifacts_path,
|
|
599
|
+
metadata_json={"followup_index": followup_index} if followup_index else None,
|
|
600
|
+
callback=progress_callback,
|
|
601
|
+
)
|
|
602
|
+
if state is not None:
|
|
603
|
+
state["mentor_review_started_emitted"] = True
|
|
604
|
+
|
|
605
|
+
return _callback
|
|
606
|
+
|
|
607
|
+
|
|
438
608
|
def run_prompt_task(
|
|
439
609
|
instruction: str,
|
|
440
610
|
assets: list[Path] | None = None,
|
|
@@ -444,6 +614,7 @@ def run_prompt_task(
|
|
|
444
614
|
create_bundle: bool = True,
|
|
445
615
|
progress_callback: ProgressCallback | None = None,
|
|
446
616
|
experience_pack_refs: list[dict] | None = None,
|
|
617
|
+
runtime_training_refs: list[dict] | None = None,
|
|
447
618
|
) -> tuple[Path, Path | None]:
|
|
448
619
|
settings = settings or get_settings()
|
|
449
620
|
run_id = run_id or make_run_id(instruction)
|
|
@@ -462,11 +633,13 @@ def run_prompt_task(
|
|
|
462
633
|
maximum_improvement_loops=settings.max_improvement_loops,
|
|
463
634
|
latest_message="Agent Apprenticeship run started.",
|
|
464
635
|
apprentice_agent=apprentice_agent_display(settings),
|
|
636
|
+
apprenticeship_mode=settings.apprenticeship_mode,
|
|
465
637
|
mentor_mode=settings.mentor_mode,
|
|
466
638
|
task_title=title,
|
|
467
639
|
task_workspace_path=str(run_root),
|
|
468
640
|
artifacts_path=str(public_artifacts),
|
|
469
641
|
**_experience_session_fields(experience_pack_refs),
|
|
642
|
+
**_runtime_training_session_fields(runtime_training_refs),
|
|
470
643
|
)
|
|
471
644
|
append_progress_event(
|
|
472
645
|
run_root,
|
|
@@ -478,6 +651,10 @@ def run_prompt_task(
|
|
|
478
651
|
phase="starting",
|
|
479
652
|
run_status="running",
|
|
480
653
|
task_status="running",
|
|
654
|
+
metadata_json={
|
|
655
|
+
"apprenticeship_mode": settings.apprenticeship_mode,
|
|
656
|
+
"mentor_mode": settings.mentor_mode,
|
|
657
|
+
},
|
|
481
658
|
callback=progress_callback,
|
|
482
659
|
)
|
|
483
660
|
(run_root / "task").mkdir(exist_ok=True)
|
|
@@ -544,11 +721,13 @@ def run_prompt_task(
|
|
|
544
721
|
"task_instruction": instruction,
|
|
545
722
|
"task_assets": asset_refs,
|
|
546
723
|
"mentor_mode": settings.mentor_mode,
|
|
724
|
+
"apprenticeship_mode": settings.apprenticeship_mode,
|
|
547
725
|
"sensitive_info_masking": settings.sensitive_info_masking,
|
|
548
726
|
"max_improvement_loops": settings.max_improvement_loops,
|
|
549
727
|
"apprentice_agent": apprentice_agent_display(settings),
|
|
550
728
|
"model_provider": settings.model_provider,
|
|
551
729
|
**_experience_session_fields(experience_pack_refs),
|
|
730
|
+
**_runtime_training_session_fields(runtime_training_refs),
|
|
552
731
|
},
|
|
553
732
|
)
|
|
554
733
|
_append_mentor_preparation_started(run_root, settings, progress_callback=progress_callback)
|
|
@@ -569,6 +748,12 @@ def run_prompt_task(
|
|
|
569
748
|
settings,
|
|
570
749
|
progress_callback=progress_callback,
|
|
571
750
|
),
|
|
751
|
+
attempt_complete_callback=_attempt_complete_callback(
|
|
752
|
+
run_root,
|
|
753
|
+
settings,
|
|
754
|
+
progress_callback=progress_callback,
|
|
755
|
+
state=checkpoint_state,
|
|
756
|
+
),
|
|
572
757
|
revision_decision_callback=revision_decider,
|
|
573
758
|
)
|
|
574
759
|
except KeyboardInterrupt as exc:
|
|
@@ -650,21 +835,22 @@ def run_prompt_task(
|
|
|
650
835
|
callback=progress_callback,
|
|
651
836
|
)
|
|
652
837
|
if should_run_mentor_review and not _human_checkpoint_mode(settings):
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
838
|
+
if not checkpoint_state.get("mentor_review_started_emitted"):
|
|
839
|
+
append_progress_event(
|
|
840
|
+
run_root,
|
|
841
|
+
"mentor_review_started",
|
|
842
|
+
run_id=run_id,
|
|
843
|
+
message="Mentor audit started",
|
|
844
|
+
current_loop=actual_iterations,
|
|
845
|
+
maximum_improvement_loops=settings.max_improvement_loops,
|
|
846
|
+
phase="mentor_review",
|
|
847
|
+
callback=progress_callback,
|
|
848
|
+
)
|
|
663
849
|
append_progress_event(
|
|
664
850
|
run_root,
|
|
665
851
|
"mentor_review_completed",
|
|
666
852
|
run_id=run_id,
|
|
667
|
-
message=f"Mentor
|
|
853
|
+
message=f"Mentor audit complete - task {run_status}",
|
|
668
854
|
current_loop=actual_iterations,
|
|
669
855
|
maximum_improvement_loops=settings.max_improvement_loops,
|
|
670
856
|
phase="mentor_review_complete",
|
|
@@ -681,6 +867,7 @@ def run_prompt_task(
|
|
|
681
867
|
auto_approve=_checkpoint_auto_approve(settings),
|
|
682
868
|
stages=("final_approval",),
|
|
683
869
|
)
|
|
870
|
+
_record_final_approval_loop_feedback(run_root, settings)
|
|
684
871
|
append_session_event(
|
|
685
872
|
run_root,
|
|
686
873
|
event_type="agent_attempt",
|
|
@@ -702,11 +889,13 @@ def run_prompt_task(
|
|
|
702
889
|
"latest_package": str(pkg.relative_to(run_root)),
|
|
703
890
|
"latest_attempt_id": manifest.get("selected_attempt_id"),
|
|
704
891
|
"mentor_mode": settings.mentor_mode,
|
|
892
|
+
"apprenticeship_mode": settings.apprenticeship_mode,
|
|
705
893
|
"sensitive_info_masking": settings.sensitive_info_masking,
|
|
706
894
|
"max_improvement_loops": settings.max_improvement_loops,
|
|
707
895
|
"apprentice_agent": apprentice_agent_display(settings),
|
|
708
896
|
"model_provider": settings.model_provider,
|
|
709
897
|
**_experience_session_fields(experience_pack_refs),
|
|
898
|
+
**_runtime_training_session_fields(runtime_training_refs),
|
|
710
899
|
}
|
|
711
900
|
if partial_reason:
|
|
712
901
|
session_data["status_reason"] = partial_reason
|
|
@@ -716,6 +905,20 @@ def run_prompt_task(
|
|
|
716
905
|
)
|
|
717
906
|
bundle = None
|
|
718
907
|
if create_bundle:
|
|
908
|
+
append_progress_event(
|
|
909
|
+
run_root,
|
|
910
|
+
"task_outputs_ready",
|
|
911
|
+
run_id=run_id,
|
|
912
|
+
message=f"Task {run_status}. Artifacts are available at: {artifacts_path}",
|
|
913
|
+
current_loop=actual_iterations,
|
|
914
|
+
maximum_improvement_loops=settings.max_improvement_loops,
|
|
915
|
+
phase="task_outputs_ready",
|
|
916
|
+
traced_steps=traced_steps,
|
|
917
|
+
artifact_count=artifact_count,
|
|
918
|
+
artifacts_path=artifacts_path,
|
|
919
|
+
callback=progress_callback,
|
|
920
|
+
)
|
|
921
|
+
_safe_run_tdo_for_run(run_root, settings, progress_callback=progress_callback)
|
|
719
922
|
if _human_checkpoint_mode(settings) and not should_run_mentor_review:
|
|
720
923
|
write_mentor_checkpoints(
|
|
721
924
|
run_root,
|
|
@@ -723,23 +926,24 @@ def run_prompt_task(
|
|
|
723
926
|
auto_approve=_checkpoint_auto_approve(settings),
|
|
724
927
|
stages=("final_approval",),
|
|
725
928
|
)
|
|
929
|
+
_record_final_approval_loop_feedback(run_root, settings)
|
|
726
930
|
append_progress_event(
|
|
727
931
|
run_root,
|
|
728
932
|
"contribution_bundle_started",
|
|
729
933
|
run_id=run_id,
|
|
730
|
-
message="
|
|
934
|
+
message="Experience Compilation packaging started",
|
|
731
935
|
current_loop=actual_iterations,
|
|
732
936
|
maximum_improvement_loops=settings.max_improvement_loops,
|
|
733
937
|
phase="contribution_bundle",
|
|
734
938
|
callback=progress_callback,
|
|
735
939
|
)
|
|
736
940
|
bundle = create_contribution_bundle(run_root, settings=settings)
|
|
737
|
-
_update_bundle_experience_metadata(bundle, experience_pack_refs)
|
|
941
|
+
_update_bundle_experience_metadata(bundle, experience_pack_refs, runtime_training_refs)
|
|
738
942
|
append_progress_event(
|
|
739
943
|
run_root,
|
|
740
944
|
"contribution_bundle_completed",
|
|
741
945
|
run_id=run_id,
|
|
742
|
-
message="
|
|
946
|
+
message="Experience Compilation ready",
|
|
743
947
|
current_loop=actual_iterations,
|
|
744
948
|
maximum_improvement_loops=settings.max_improvement_loops,
|
|
745
949
|
phase="contribution_bundle_complete",
|
|
@@ -763,6 +967,7 @@ def run_prompt_task(
|
|
|
763
967
|
operational_error=operational_error,
|
|
764
968
|
callback=progress_callback,
|
|
765
969
|
)
|
|
970
|
+
update_run_status(run_root, **_runtime_training_session_fields(runtime_training_refs))
|
|
766
971
|
return run_root, bundle
|
|
767
972
|
|
|
768
973
|
|
|
@@ -781,22 +986,61 @@ def _experience_session_fields(experience_pack_refs: list[dict] | None) -> dict:
|
|
|
781
986
|
}
|
|
782
987
|
|
|
783
988
|
|
|
784
|
-
def
|
|
785
|
-
|
|
989
|
+
def _runtime_training_session_fields(runtime_training_refs: list[dict] | None) -> dict:
|
|
990
|
+
refs = runtime_training_refs or []
|
|
991
|
+
if not refs:
|
|
992
|
+
return {
|
|
993
|
+
"runtime_training_used": False,
|
|
994
|
+
"installed_skill_refs": [],
|
|
995
|
+
"installed_skill_ids": [],
|
|
996
|
+
}
|
|
997
|
+
return {
|
|
998
|
+
"runtime_training_used": True,
|
|
999
|
+
"installed_skill_refs": refs,
|
|
1000
|
+
"installed_skill_ids": [ref.get("installed_skill_id") for ref in refs if ref.get("installed_skill_id")],
|
|
1001
|
+
"runtime_training_selection_reason": "enabled installed runtime training matched this task or was explicitly requested",
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
def _update_json_experience_metadata(path: Path, experience_pack_refs: list[dict] | None, runtime_training_refs: list[dict] | None = None) -> None:
|
|
1006
|
+
if not (experience_pack_refs or runtime_training_refs) or not path.exists():
|
|
786
1007
|
return
|
|
787
1008
|
data = read_json(path)
|
|
788
1009
|
if not isinstance(data, dict):
|
|
789
1010
|
return
|
|
790
|
-
|
|
791
|
-
|
|
1011
|
+
if experience_pack_refs:
|
|
1012
|
+
data.update(_experience_session_fields(experience_pack_refs))
|
|
1013
|
+
data["experience_learning_status"] = "experience_pack_applied"
|
|
1014
|
+
if runtime_training_refs:
|
|
1015
|
+
data.update(_runtime_training_session_fields(runtime_training_refs))
|
|
792
1016
|
write_json(path, data)
|
|
793
1017
|
|
|
794
1018
|
|
|
795
|
-
def
|
|
796
|
-
if not
|
|
1019
|
+
def _update_trace_experience_metadata(path: Path, experience_pack_refs: list[dict] | None, runtime_training_refs: list[dict] | None = None) -> None:
|
|
1020
|
+
if not (experience_pack_refs or runtime_training_refs) or not path.exists():
|
|
1021
|
+
return
|
|
1022
|
+
data = read_json(path)
|
|
1023
|
+
if not isinstance(data, dict):
|
|
1024
|
+
return
|
|
1025
|
+
metadata = data.setdefault("metadata_json", {})
|
|
1026
|
+
if not isinstance(metadata, dict):
|
|
1027
|
+
metadata = {}
|
|
1028
|
+
data["metadata_json"] = metadata
|
|
1029
|
+
if experience_pack_refs:
|
|
1030
|
+
metadata.update(_experience_session_fields(experience_pack_refs))
|
|
1031
|
+
metadata["experience_learning_status"] = "experience_pack_applied"
|
|
1032
|
+
if runtime_training_refs:
|
|
1033
|
+
metadata.update(_runtime_training_session_fields(runtime_training_refs))
|
|
1034
|
+
write_json(path, data)
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
def _update_bundle_experience_metadata(bundle: Path | None, experience_pack_refs: list[dict] | None, runtime_training_refs: list[dict] | None = None) -> None:
|
|
1038
|
+
if not bundle or not (experience_pack_refs or runtime_training_refs):
|
|
797
1039
|
return
|
|
798
1040
|
for rel in ("contribution_manifest.json", "session_metadata.json"):
|
|
799
|
-
_update_json_experience_metadata(bundle / rel, experience_pack_refs)
|
|
1041
|
+
_update_json_experience_metadata(bundle / rel, experience_pack_refs, runtime_training_refs)
|
|
1042
|
+
for trace_path in bundle.glob("attempts/*/agent_trace.json"):
|
|
1043
|
+
_update_trace_experience_metadata(trace_path, experience_pack_refs, runtime_training_refs)
|
|
800
1044
|
|
|
801
1045
|
|
|
802
1046
|
def _latest_attempt_id(run_root: Path) -> str | None:
|
|
@@ -810,6 +1054,43 @@ def _latest_attempt_id(run_root: Path) -> str | None:
|
|
|
810
1054
|
return None
|
|
811
1055
|
|
|
812
1056
|
|
|
1057
|
+
def _latest_package(run_root: Path) -> Path | None:
|
|
1058
|
+
packages = sorted((run_root / "packages").glob("*")) if (run_root / "packages").exists() else []
|
|
1059
|
+
return packages[-1] if packages else None
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
def _record_final_approval_loop_feedback(run_root: Path, settings: Settings) -> None:
|
|
1063
|
+
if not _human_checkpoint_mode(settings):
|
|
1064
|
+
return
|
|
1065
|
+
pkg = _latest_package(run_root)
|
|
1066
|
+
if not pkg:
|
|
1067
|
+
return
|
|
1068
|
+
final_path = run_root / "mentor_checkpoints" / "final_approval_checkpoint.json"
|
|
1069
|
+
if not final_path.exists():
|
|
1070
|
+
return
|
|
1071
|
+
try:
|
|
1072
|
+
final = read_json(final_path)
|
|
1073
|
+
except Exception:
|
|
1074
|
+
return
|
|
1075
|
+
manifest_path = pkg / "loops" / "loop_manifest.json"
|
|
1076
|
+
if not manifest_path.exists():
|
|
1077
|
+
return
|
|
1078
|
+
manifest = read_json(manifest_path)
|
|
1079
|
+
iterations = [item for item in manifest.get("iterations") or [] if isinstance(item, dict)]
|
|
1080
|
+
if not iterations:
|
|
1081
|
+
return
|
|
1082
|
+
iteration = max(int(item.get("loop_iteration") or 0) for item in iterations)
|
|
1083
|
+
if iteration <= 0:
|
|
1084
|
+
return
|
|
1085
|
+
review_refs = [
|
|
1086
|
+
f"loops/iterations/{iteration:03d}/review_packet.json",
|
|
1087
|
+
f"loops/iterations/{iteration:03d}/review_packet.md",
|
|
1088
|
+
]
|
|
1089
|
+
final_with_refs = {**final, "evidence_refs": review_refs}
|
|
1090
|
+
approved = bool(final.get("approved_for_local_bundle", True))
|
|
1091
|
+
record_human_loop_feedback(pkg, iteration=iteration, checkpoint=final_with_refs, revision_requested=not approved)
|
|
1092
|
+
|
|
1093
|
+
|
|
813
1094
|
def _session_task_id(run_root: Path) -> str | None:
|
|
814
1095
|
session_path = run_root / "session.json"
|
|
815
1096
|
if session_path.exists():
|
|
@@ -938,6 +1219,13 @@ def continue_session(
|
|
|
938
1219
|
progress_callback=progress_callback,
|
|
939
1220
|
followup_index=followup_index,
|
|
940
1221
|
),
|
|
1222
|
+
attempt_complete_callback=_attempt_complete_callback(
|
|
1223
|
+
run_root,
|
|
1224
|
+
settings,
|
|
1225
|
+
progress_callback=progress_callback,
|
|
1226
|
+
followup_index=followup_index,
|
|
1227
|
+
state=checkpoint_state,
|
|
1228
|
+
),
|
|
941
1229
|
revision_decision_callback=revision_decider,
|
|
942
1230
|
)
|
|
943
1231
|
manifest = read_json(pkg / "package_manifest.json") if (pkg / "package_manifest.json").exists() else {}
|
|
@@ -1009,7 +1297,7 @@ def continue_session(
|
|
|
1009
1297
|
run_root,
|
|
1010
1298
|
"mentor_review_completed",
|
|
1011
1299
|
run_id=run_root.name,
|
|
1012
|
-
message=f"Follow-up {followup_index} mentor
|
|
1300
|
+
message=f"Follow-up {followup_index} mentor audit complete",
|
|
1013
1301
|
current_loop=actual_iterations,
|
|
1014
1302
|
maximum_improvement_loops=settings.max_improvement_loops,
|
|
1015
1303
|
phase="mentor_review_complete",
|
|
@@ -1027,6 +1315,7 @@ def continue_session(
|
|
|
1027
1315
|
auto_approve=_checkpoint_auto_approve(settings),
|
|
1028
1316
|
stages=("final_approval",),
|
|
1029
1317
|
)
|
|
1318
|
+
_record_final_approval_loop_feedback(run_root, settings)
|
|
1030
1319
|
append_session_event(
|
|
1031
1320
|
run_root,
|
|
1032
1321
|
event_type="agent_attempt",
|
|
@@ -1068,16 +1357,25 @@ def continue_session(
|
|
|
1068
1357
|
final_artifact_count = None
|
|
1069
1358
|
final_operational_error = None
|
|
1070
1359
|
record_only_message = "Follow-up recorded. No Apprentice Agent loop was run. Use --run-loop to continue work."
|
|
1071
|
-
|
|
1360
|
+
record_followup_review_update(
|
|
1361
|
+
run_root,
|
|
1362
|
+
followup_index=followup_index,
|
|
1363
|
+
record_only=True,
|
|
1364
|
+
note=record_only_message,
|
|
1365
|
+
)
|
|
1366
|
+
if run_loop:
|
|
1367
|
+
record_followup_review_update(
|
|
1368
|
+
run_root,
|
|
1369
|
+
followup_index=followup_index,
|
|
1370
|
+
record_only=False,
|
|
1371
|
+
note=f"Follow-up {followup_index} ran a new Apprentice Agent loop and produced a new review packet.",
|
|
1372
|
+
)
|
|
1373
|
+
_safe_run_tdo_for_run(
|
|
1072
1374
|
run_root,
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
maximum_improvement_loops=settings.max_improvement_loops,
|
|
1078
|
-
phase="contribution_bundle",
|
|
1079
|
-
metadata_json={"followup_index": followup_index},
|
|
1080
|
-
callback=progress_callback,
|
|
1375
|
+
settings,
|
|
1376
|
+
progress_callback=progress_callback,
|
|
1377
|
+
followup_index=followup_index,
|
|
1378
|
+
record_only=not run_loop,
|
|
1081
1379
|
)
|
|
1082
1380
|
if run_loop and _human_checkpoint_mode(settings):
|
|
1083
1381
|
write_mentor_checkpoints(
|
|
@@ -1087,12 +1385,24 @@ def continue_session(
|
|
|
1087
1385
|
stages=("final_approval",),
|
|
1088
1386
|
preserve_interactive=False,
|
|
1089
1387
|
)
|
|
1388
|
+
_record_final_approval_loop_feedback(run_root, settings)
|
|
1389
|
+
append_progress_event(
|
|
1390
|
+
run_root,
|
|
1391
|
+
"contribution_bundle_started",
|
|
1392
|
+
run_id=run_root.name,
|
|
1393
|
+
message="Experience Compilation update started",
|
|
1394
|
+
current_loop=1,
|
|
1395
|
+
maximum_improvement_loops=settings.max_improvement_loops,
|
|
1396
|
+
phase="contribution_bundle",
|
|
1397
|
+
metadata_json={"followup_index": followup_index},
|
|
1398
|
+
callback=progress_callback,
|
|
1399
|
+
)
|
|
1090
1400
|
bundle = create_contribution_bundle(run_root, settings=settings)
|
|
1091
1401
|
append_progress_event(
|
|
1092
1402
|
run_root,
|
|
1093
1403
|
"contribution_bundle_completed",
|
|
1094
1404
|
run_id=run_root.name,
|
|
1095
|
-
message="
|
|
1405
|
+
message="Experience Compilation updated",
|
|
1096
1406
|
current_loop=1,
|
|
1097
1407
|
maximum_improvement_loops=settings.max_improvement_loops,
|
|
1098
1408
|
phase="contribution_bundle_complete",
|
|
@@ -1121,7 +1431,7 @@ def continue_session(
|
|
|
1121
1431
|
return run_root, bundle
|
|
1122
1432
|
|
|
1123
1433
|
|
|
1124
|
-
def finish_session(run_id: str, settings: Settings | None = None) -> tuple[Path, Path]:
|
|
1434
|
+
def finish_session(run_id: str, settings: Settings | None = None, progress_callback: ProgressCallback | None = None) -> tuple[Path, Path]:
|
|
1125
1435
|
settings = settings or get_settings()
|
|
1126
1436
|
run_root = run_root_for(run_id, settings)
|
|
1127
1437
|
if not run_root.exists():
|
|
@@ -1155,6 +1465,8 @@ def finish_session(run_id: str, settings: Settings | None = None) -> tuple[Path,
|
|
|
1155
1465
|
auto_approve=_checkpoint_auto_approve(settings),
|
|
1156
1466
|
stages=("final_approval",),
|
|
1157
1467
|
)
|
|
1468
|
+
_record_final_approval_loop_feedback(run_root, settings)
|
|
1469
|
+
_safe_run_tdo_for_run(run_root, settings, progress_callback=progress_callback)
|
|
1158
1470
|
bundle = create_contribution_bundle(run_root, settings=settings)
|
|
1159
1471
|
append_progress_event(
|
|
1160
1472
|
run_root,
|