agent-apprenticeship 0.1.6 → 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.
- 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
|
@@ -13,12 +13,57 @@ from .contract_diagnostics import build_contract_diagnostics, diagnostics_text
|
|
|
13
13
|
from .trace_normalizer import TraceNormalizationContext, repair_agent_trace_file, TraceNormalizationReport
|
|
14
14
|
from .actual_outputs_normalizer import ActualOutputsNormalizationContext, repair_actual_outputs_file, write_actual_outputs_normalization
|
|
15
15
|
from .public_sanitizer import classify_provider_failure, public_error_summary
|
|
16
|
+
from .progress import utc_now
|
|
16
17
|
|
|
17
18
|
class AttemptResult(dict): pass
|
|
18
19
|
|
|
19
20
|
CODEX_TRUST_RETRY_MESSAGE = "Codex refused to run because the workspace is not a trusted Git directory. Retrying with --skip-git-repo-check if supported."
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
def _safe_agent_config(settings, runner_kind: str, attempt_kind: str) -> dict:
|
|
24
|
+
return {
|
|
25
|
+
"apprentice_agent_id": settings.worker_agent,
|
|
26
|
+
"apprentice_agent_name": settings.custom_worker_display_name if settings.worker_agent == "custom" else settings.worker_agent,
|
|
27
|
+
"apprenticeship_mode": getattr(settings, "apprenticeship_mode", None),
|
|
28
|
+
"mentor_mode": settings.mentor_mode,
|
|
29
|
+
"mentor_model_provider": settings.model_provider,
|
|
30
|
+
"max_improvement_loops": settings.max_improvement_loops,
|
|
31
|
+
"attempt_kind": attempt_kind,
|
|
32
|
+
"runner_kind": runner_kind,
|
|
33
|
+
"sensitive_info_masking": settings.sensitive_info_masking,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _enrich_runtime_trace(
|
|
38
|
+
trace: AgentTrace,
|
|
39
|
+
actual: ActualOutputs,
|
|
40
|
+
package_root: Path,
|
|
41
|
+
attempt_kind: str,
|
|
42
|
+
runner_kind: str,
|
|
43
|
+
started_at: str | None,
|
|
44
|
+
ended_at: str | None,
|
|
45
|
+
) -> AgentTrace:
|
|
46
|
+
settings = get_settings()
|
|
47
|
+
trace.run_id = package_root.parent.parent.name if package_root.parent.parent.name else None
|
|
48
|
+
trace.package_id = package_root.name
|
|
49
|
+
trace.started_at = trace.started_at or started_at
|
|
50
|
+
trace.ended_at = trace.ended_at or ended_at
|
|
51
|
+
trace.agent_config = trace.agent_config or _safe_agent_config(settings, runner_kind, attempt_kind)
|
|
52
|
+
trace.actual_outputs_ref = f"attempts/{attempt_kind}/actual_outputs.json"
|
|
53
|
+
trace.input_artifact_refs = list(dict.fromkeys(actual.input_artifact_refs or trace.input_artifact_refs or []))
|
|
54
|
+
trace.artifact_refs = list(dict.fromkeys((actual.artifact_refs or actual.files_created or []) + (trace.artifact_refs or [])))
|
|
55
|
+
trace.deliverable_refs = list(dict.fromkeys((actual.deliverable_refs or []) + (trace.deliverable_refs or [])))
|
|
56
|
+
trace.output_summary = trace.output_summary or actual.output_summary
|
|
57
|
+
trace.final_output_summary = trace.final_output_summary or actual.output_summary
|
|
58
|
+
trace.environment_domain = trace.environment_domain or (
|
|
59
|
+
"mixed"
|
|
60
|
+
if len({s.environment_domain for s in trace.steps if s.environment_domain and s.environment_domain != "unknown"}) > 1
|
|
61
|
+
else next(iter({s.environment_domain for s in trace.steps if s.environment_domain and s.environment_domain != "unknown"}), "unknown")
|
|
62
|
+
)
|
|
63
|
+
trace.metadata_json.setdefault("runtime_metadata_populated", True)
|
|
64
|
+
return trace
|
|
65
|
+
|
|
66
|
+
|
|
22
67
|
def _run_with_process_group_timeout(command, *, cwd: Path, timeout: int | None, shell: bool = False) -> subprocess.CompletedProcess:
|
|
23
68
|
process = subprocess.Popen(
|
|
24
69
|
command,
|
|
@@ -53,6 +98,19 @@ def _attempt_dir(package_root: Path, attempt_kind: str) -> Path:
|
|
|
53
98
|
(p/'input').mkdir(parents=True, exist_ok=True)
|
|
54
99
|
return p
|
|
55
100
|
|
|
101
|
+
|
|
102
|
+
def _recover_misplaced_contract_files(d: Path) -> dict[str, str]:
|
|
103
|
+
"""Recover contract files agents sometimes place under ./artifacts/."""
|
|
104
|
+
recovered: dict[str, str] = {}
|
|
105
|
+
for name in ("agent_trace.json", "actual_outputs.json"):
|
|
106
|
+
dst = d / name
|
|
107
|
+
src = d / "artifacts" / name
|
|
108
|
+
if dst.exists() or not src.exists() or not src.is_file():
|
|
109
|
+
continue
|
|
110
|
+
shutil.copy2(src, dst)
|
|
111
|
+
recovered[name] = f"artifacts/{name}"
|
|
112
|
+
return recovered
|
|
113
|
+
|
|
56
114
|
def _copy_attempt_inputs(package_root: Path, attempt_dir: Path) -> list[str]:
|
|
57
115
|
src=package_root/'input'; dst=attempt_dir/'input'
|
|
58
116
|
dst.mkdir(parents=True, exist_ok=True)
|
|
@@ -101,9 +159,11 @@ def _fallback_actual(spec: TaskIntakeSpec, attempt_kind: str, error_type: str, e
|
|
|
101
159
|
|
|
102
160
|
def _apprentice_operational_error(error: object | None, stdout: str = "", stderr: str = "", returncode: int | None = None) -> str | None:
|
|
103
161
|
text = f"{error or ''}\n{stdout or ''}\n{stderr or ''}".lower()
|
|
162
|
+
if error is None and returncode == 0:
|
|
163
|
+
return None
|
|
104
164
|
if isinstance(error, FileNotFoundError) or "no such file or directory: 'codex'" in text or "no such file or directory: codex" in text:
|
|
105
165
|
return "Apprentice Agent command not found: codex"
|
|
106
|
-
if isinstance(error, subprocess.TimeoutExpired) or "timed out" in text or "timeout" in text:
|
|
166
|
+
if isinstance(error, subprocess.TimeoutExpired) or "timed out" in text or "timeout expired" in text or "command timed out" in text:
|
|
107
167
|
return "Apprentice Agent timed out while running Codex."
|
|
108
168
|
if _is_codex_workspace_trust_error(stdout, stderr, error):
|
|
109
169
|
return "Codex workspace trust error: Codex refused to run because the workspace is not a trusted Git directory. Use a Codex CLI with --skip-git-repo-check support or run from a trusted Git repository."
|
|
@@ -191,7 +251,7 @@ def _fallback_trace(spec: TaskIntakeSpec, attempt_kind: str, prompt: str, actual
|
|
|
191
251
|
error_type=cls.get('error_type') or error_type
|
|
192
252
|
steps=[
|
|
193
253
|
AgentTraceStep(step=1, turn=1, actor='user', action='user_message', input=spec.normalized_instruction, message_role='direct_request'),
|
|
194
|
-
AgentTraceStep(step=2, turn=1, actor=actor, action='error', operation='other', tool='codex_cli', observation='Codex attempt ended without a valid agent_trace.json or actual_outputs.json.', input='Validate required output contract for ./agent_trace.json and ./actual_outputs.json.', output=safe, state_change='A minimal failure trace and failed actual_outputs.json were written by the runner.', reasoning='The package must preserve failure evidence without fabricating a successful detailed trace.', caused_by=[1], causal_type='dependency_on_tool_result', success=False, step_outcome='failed', error_type=error_type, error_message=safe, artifact_refs=[f'attempts/{attempt_kind}/prompt.md', f'attempts/{attempt_kind}/stdout.txt', f'attempts/{attempt_kind}/stderr.txt', f'attempts/{attempt_kind}/final_message.txt']),
|
|
254
|
+
AgentTraceStep(step=2, turn=1, actor=actor, action='error', operation='other', tool='codex_cli', environment_domain='terminal', execution_mode='serial', observation='Codex attempt ended without a valid agent_trace.json or actual_outputs.json.', input='Validate required output contract for ./agent_trace.json and ./actual_outputs.json.', input_source={'source':'runtime_contract_check'}, output=safe, state_change='A minimal failure trace and failed actual_outputs.json were written by the runner.', reasoning='The package must preserve failure evidence without fabricating a successful detailed trace.', caused_by=[1], causal_type='dependency_on_tool_result', success=False, step_outcome='failed', error_type=error_type, error_message=safe, artifact_refs=[f'attempts/{attempt_kind}/prompt.md', f'attempts/{attempt_kind}/stdout.txt', f'attempts/{attempt_kind}/stderr.txt', f'attempts/{attempt_kind}/final_message.txt']),
|
|
195
255
|
]
|
|
196
256
|
return AgentTrace(trace_id=f'trace_{attempt_id}_fallback', collection_id=None, trace_mode='live', task=spec.normalized_instruction, task_id=spec.task_id, attempt_id=attempt_id, attempt_kind=attempt_kind if attempt_kind in ['baseline','revised'] else 'other', agent_tools=['codex_cli','Bash','python','file_read','file_write'], system_prompt=prompt, system_prompt_hash=None, skills=['agent_trace_skill'], learning='When a live agent cannot write outputs, preserve logs and create a minimal failure trace.', termination_reason='agent_blocked', steps=steps, actual_outputs=actual, artifacts=[], metadata_json={'trace_valid':False,'fallback_trace_created':True,'codex_sandbox':codex_sandbox, **cls})
|
|
197
257
|
|
|
@@ -202,6 +262,7 @@ def _write_fallback_report(d: Path, spec: TaskIntakeSpec, attempt_kind: str, rea
|
|
|
202
262
|
|
|
203
263
|
def ensure_attempt_outputs(package_root: Path, spec: TaskIntakeSpec, attempt_kind: str, prompt: str, codex_sandbox: str, validation_error: Exception | None=None) -> tuple[AgentTrace, ActualOutputs, bool]:
|
|
204
264
|
d=_attempt_dir(package_root, attempt_kind)
|
|
265
|
+
recovered_contract_files = _recover_misplaced_contract_files(d)
|
|
205
266
|
actual_path=d/'actual_outputs.json'; trace_path=d/'agent_trace.json'; raw_path=d/'agent_trace.raw.json'
|
|
206
267
|
err = validation_error or FileNotFoundError('agent_trace.json missing or invalid')
|
|
207
268
|
required_artifacts=_deliverables(RawTaskRecord(raw_task_id=spec.task_id, source_kind='normalized_spec', raw_title=spec.normalized_title, raw_description=spec.normalized_instruction, raw_payload={'expected_deliverable': spec.expected_agent_deliverable}), spec)
|
|
@@ -225,7 +286,11 @@ def ensure_attempt_outputs(package_root: Path, spec: TaskIntakeSpec, attempt_kin
|
|
|
225
286
|
write_json(d/'agent_trace.normalized.json', result.normalized_trace)
|
|
226
287
|
write_json(d/'agent_trace.json', result.normalized_trace)
|
|
227
288
|
write_json(d/'trace_normalization_report.json', result.report)
|
|
228
|
-
|
|
289
|
+
trace = AgentTrace.model_validate(result.normalized_trace)
|
|
290
|
+
if recovered_contract_files:
|
|
291
|
+
trace.metadata_json["contract_files_recovered_from"] = recovered_contract_files
|
|
292
|
+
actual.metadata_json.setdefault("contract_files_recovered_from", recovered_contract_files)
|
|
293
|
+
return trace, actual, bool(result.report.trace_schema_valid)
|
|
229
294
|
reason=result.parse_error or 'parseable trace contained no steps'
|
|
230
295
|
final=(d/'final_message.txt').read_text(errors='ignore') if (d/'final_message.txt').exists() else ''
|
|
231
296
|
stderr=(d/'stderr.txt').read_text(errors='ignore') if (d/'stderr.txt').exists() else ''
|
|
@@ -243,6 +308,7 @@ def ensure_attempt_outputs(package_root: Path, spec: TaskIntakeSpec, attempt_kin
|
|
|
243
308
|
return trace, actual, False
|
|
244
309
|
|
|
245
310
|
def deterministic_attempt(package_root: Path, raw: RawTaskRecord, spec: TaskIntakeSpec, attempt_kind='baseline', feedback: str | None=None) -> AttemptResult:
|
|
311
|
+
started_at = utc_now()
|
|
246
312
|
attempt_id=f'{spec.task_id}_{attempt_kind}'
|
|
247
313
|
d=_attempt_dir(package_root, attempt_kind)
|
|
248
314
|
input_files=_copy_attempt_inputs(package_root, d)
|
|
@@ -258,18 +324,22 @@ def deterministic_attempt(package_root: Path, raw: RawTaskRecord, spec: TaskInta
|
|
|
258
324
|
fname=name if '.' in name and '/' not in name else name.lower().replace(' ','_') + '.txt'
|
|
259
325
|
(d/'artifacts'/fname).write_text(f'{attempt_kind} deterministic artifact for {name}\n')
|
|
260
326
|
files.append(f'attempts/{attempt_kind}/artifacts/{fname}')
|
|
261
|
-
actual=ActualOutputs(task_id=spec.task_id, attempt_id=attempt_id, attempt_kind=attempt_kind, status='success', output_summary=f'Deterministic {attempt_kind} outputs for {spec.normalized_title}', primary_output_ref=files[0] if files else None, deliverable_refs=files, final_message_ref=f'attempts/{attempt_kind}/final_message.txt', artifact_refs=files, files_created=files, files_modified=[], files_deleted=[], stdout_ref=f'attempts/{attempt_kind}/stdout.txt', stderr_ref=f'attempts/{attempt_kind}/stderr.txt', raw_log_refs=[f'attempts/{attempt_kind}/stdout.txt', f'attempts/{attempt_kind}/stderr.txt'], error_type=None, error_message=None, metadata_json={'runner':'deterministic','expected_deliverable_items':deliverables,'produced_deliverable_items':[Path(f).name for f in files]})
|
|
327
|
+
actual=ActualOutputs(task_id=spec.task_id, attempt_id=attempt_id, attempt_kind=attempt_kind, status='success', output_summary=f'Deterministic {attempt_kind} outputs for {spec.normalized_title}', primary_output_ref=files[0] if files else None, input_artifact_refs=[f'input/{name}' for name in input_files], deliverable_refs=files, final_message_ref=f'attempts/{attempt_kind}/final_message.txt', artifact_refs=files, files_created=files, files_modified=[], files_deleted=[], stdout_ref=f'attempts/{attempt_kind}/stdout.txt', stderr_ref=f'attempts/{attempt_kind}/stderr.txt', raw_log_refs=[f'attempts/{attempt_kind}/stdout.txt', f'attempts/{attempt_kind}/stderr.txt'], error_type=None, error_message=None, metadata_json={'runner':'deterministic','expected_deliverable_items':deliverables,'produced_deliverable_items':[Path(f).name for f in files]})
|
|
262
328
|
steps=[
|
|
263
329
|
AgentTraceStep(step=1, turn=1, actor='user', action='user_message', input=spec.normalized_instruction, message_role='direct_request'),
|
|
264
|
-
AgentTraceStep(step=2, turn=1, actor=f'agent:{"reviser" if attempt_kind=="revised" else "worker"}', action='agent_step', operation='plan', tool=None, observation='Task instructions, ./input files, and worker-visible rubric are available.', input='Review task and required deliverables.', output='Plan created.', state_change='The attempt plan identified required artifacts.', reasoning='A short plan reduces missed deliverables.', caused_by=[1], causal_type='user_request', success=True, step_outcome='progress'),
|
|
265
|
-
AgentTraceStep(step=3, turn=1, actor=f'agent:{"reviser" if attempt_kind=="revised" else "worker"}', action='agent_step', operation='write', tool='file_write', observation='Deliverable names are known.', input=', '.join(files), output='Artifacts written.', state_change='Required deterministic artifacts were created under ./artifacts.', reasoning='Writing explicit files satisfies the artifact contract.', caused_by=[2], causal_type='execution_of_plan', success=True, step_outcome='completed', artifact_refs=files),
|
|
330
|
+
AgentTraceStep(step=2, turn=1, actor=f'agent:{"reviser" if attempt_kind=="revised" else "worker"}', action='agent_step', operation='plan', tool=None, environment_domain='file', execution_mode='serial', observation='Task instructions, ./input files, and worker-visible rubric are available.', input='Review task and required deliverables.', input_source={'source':'task_packet'}, output='Plan created.', state_change='The attempt plan identified required artifacts.', reasoning='A short plan reduces missed deliverables.', caused_by=[1], causal_type='user_request', success=True, step_outcome='progress', artifact_refs=[f'input/{name}' for name in input_files]),
|
|
331
|
+
AgentTraceStep(step=3, turn=1, actor=f'agent:{"reviser" if attempt_kind=="revised" else "worker"}', action='agent_step', operation='write', tool='file_write', environment_domain='file', execution_mode='serial', observation='Deliverable names are known.', input=', '.join(files), input_source={'source':'planned_deliverables'}, output='Artifacts written.', state_change='Required deterministic artifacts were created under ./artifacts.', reasoning='Writing explicit files satisfies the artifact contract.', caused_by=[2], causal_type='execution_of_plan', success=True, step_outcome='completed', artifact_refs=files),
|
|
266
332
|
]
|
|
333
|
+
ended_at = utc_now()
|
|
267
334
|
trace=AgentTrace(trace_id=f'trace_{attempt_id}', collection_id=None, trace_mode='live', task=spec.normalized_instruction, task_id=spec.task_id, attempt_id=attempt_id, attempt_kind=attempt_kind if attempt_kind in ['baseline','revised'] else 'other', agent_tools=['deterministic_runner','file_write'], system_prompt=prompt, system_prompt_hash=None, skills=['agent_trace_skill'], learning='Materialize required artifacts and keep evaluation outside the trace.', termination_reason='task_complete', steps=steps, actual_outputs=actual, artifacts=[], metadata_json={'trace_valid': True})
|
|
335
|
+
trace = _enrich_runtime_trace(trace, actual, package_root, attempt_kind, 'deterministic', started_at, ended_at)
|
|
268
336
|
write_json(d/'actual_outputs.json', actual)
|
|
269
337
|
actual_ctx=ActualOutputsNormalizationContext(task_id=spec.task_id, attempt_id=attempt_id, attempt_kind=attempt_kind, package_root=package_root, required_artifacts=deliverables)
|
|
270
338
|
actual_result=repair_actual_outputs_file(d/'actual_outputs.json', actual_ctx)
|
|
271
339
|
write_actual_outputs_normalization(d, actual_result)
|
|
272
340
|
actual=ActualOutputs.model_validate(actual_result.actual_outputs)
|
|
341
|
+
trace.actual_outputs = actual
|
|
342
|
+
trace = _enrich_runtime_trace(trace, actual, package_root, attempt_kind, 'deterministic', started_at, ended_at)
|
|
273
343
|
write_json(d/'agent_trace.raw.json', trace); write_json(d/'agent_trace.normalized.json', trace); write_json(d/'agent_trace.json', trace)
|
|
274
344
|
report=TraceNormalizationReport(task_id=spec.task_id, attempt_id=attempt_id, attempt_kind=attempt_kind, raw_trace_ref='agent_trace.raw.json', normalized_trace_ref='agent_trace.normalized.json', canonical_trace_ref='agent_trace.json', trace_schema_valid=True, trace_normalized=False, trace_lossless=True, fallback_trace=False, raw_step_count=len(steps), normalized_step_count=len(steps), discarded_step_count=0)
|
|
275
345
|
write_json(d/'trace_normalization_report.json', report)
|
|
@@ -300,6 +370,7 @@ def codex_command(
|
|
|
300
370
|
return cmd
|
|
301
371
|
|
|
302
372
|
def run_codex_attempt(package_root: Path, raw: RawTaskRecord, spec: TaskIntakeSpec, attempt_kind='baseline', timeout=900) -> AttemptResult:
|
|
373
|
+
started_at = utc_now()
|
|
303
374
|
d=_attempt_dir(package_root, attempt_kind)
|
|
304
375
|
input_files=_copy_attempt_inputs(package_root, d)
|
|
305
376
|
deliverables=_deliverables(raw, spec)
|
|
@@ -350,22 +421,29 @@ def run_codex_attempt(package_root: Path, raw: RawTaskRecord, spec: TaskIntakeSp
|
|
|
350
421
|
except Exception as e:
|
|
351
422
|
run_error=e
|
|
352
423
|
(d/'stdout.txt').write_text(''); (d/'stderr.txt').write_text(redact_secrets(str(e))); (d/'final_message.txt').write_text('Codex run failed before producing validated trace.')
|
|
424
|
+
recovered_contract_files = _recover_misplaced_contract_files(d)
|
|
353
425
|
contract_diagnostics = None
|
|
354
426
|
if not (d/'agent_trace.json').exists() or not (d/'actual_outputs.json').exists():
|
|
355
427
|
contract_diagnostics = build_contract_diagnostics(d, command=cmd, working_directory=d, agent_display_name='Codex', prompt=prompt)
|
|
356
428
|
with (d/'final_message.txt').open('a') as f:
|
|
357
429
|
f.write('\n\n' + diagnostics_text(contract_diagnostics))
|
|
358
430
|
trace, actual, trace_valid = ensure_attempt_outputs(package_root, spec, attempt_kind, prompt, sandbox, run_error)
|
|
431
|
+
ended_at = utc_now()
|
|
432
|
+
trace = _enrich_runtime_trace(trace, actual, package_root, attempt_kind, 'codex', started_at, ended_at)
|
|
359
433
|
trace.metadata_json['codex_sandbox']=sandbox
|
|
360
434
|
trace.metadata_json['codex_command']=[part if part != prompt else '<prompt>' for part in cmd]
|
|
361
435
|
trace.metadata_json['codex_skip_git_repo_check_supported']=skip_supported
|
|
362
436
|
trace.metadata_json['codex_skip_git_repo_check_used']='--skip-git-repo-check' in cmd
|
|
363
437
|
trace.metadata_json['trace_valid']=trace_valid
|
|
438
|
+
if recovered_contract_files:
|
|
439
|
+
trace.metadata_json['contract_files_recovered_from'] = recovered_contract_files
|
|
364
440
|
if contract_diagnostics:
|
|
365
441
|
trace.metadata_json['apprentice_agent_contract_diagnostics']=contract_diagnostics
|
|
366
442
|
write_json(d/'agent_trace.json', trace)
|
|
367
443
|
if actual.metadata_json is None: actual.metadata_json={}
|
|
368
444
|
actual.metadata_json['codex_sandbox']=sandbox
|
|
445
|
+
if recovered_contract_files:
|
|
446
|
+
actual.metadata_json['contract_files_recovered_from'] = recovered_contract_files
|
|
369
447
|
if contract_diagnostics:
|
|
370
448
|
actual.metadata_json['apprentice_agent_contract_diagnostics']=contract_diagnostics
|
|
371
449
|
op_error = _apprentice_operational_error(run_error, stdout, stderr, returncode)
|
|
@@ -393,6 +471,7 @@ def run_codex_attempt(package_root: Path, raw: RawTaskRecord, spec: TaskIntakeSp
|
|
|
393
471
|
|
|
394
472
|
|
|
395
473
|
def run_custom_attempt(package_root: Path, raw: RawTaskRecord, spec: TaskIntakeSpec, attempt_kind='baseline', timeout: int | None=None) -> AttemptResult:
|
|
474
|
+
started_at = utc_now()
|
|
396
475
|
settings=get_settings()
|
|
397
476
|
d=_attempt_dir(package_root, attempt_kind)
|
|
398
477
|
input_files=_copy_attempt_inputs(package_root, d)
|
|
@@ -411,6 +490,8 @@ def run_custom_attempt(package_root: Path, raw: RawTaskRecord, spec: TaskIntakeS
|
|
|
411
490
|
with (d/'final_message.txt').open('a') as f:
|
|
412
491
|
f.write('\n\n' + diagnostics_text(contract_diagnostics))
|
|
413
492
|
trace, actual, trace_valid=ensure_attempt_outputs(package_root, spec, attempt_kind, prompt, 'custom', err)
|
|
493
|
+
ended_at = utc_now()
|
|
494
|
+
trace = _enrich_runtime_trace(trace, actual, package_root, attempt_kind, 'custom', started_at, ended_at)
|
|
414
495
|
if actual.metadata_json is None:
|
|
415
496
|
actual.metadata_json = {}
|
|
416
497
|
actual.metadata_json['apprentice_agent_contract_diagnostics'] = contract_diagnostics
|
|
@@ -449,6 +530,8 @@ def run_custom_attempt(package_root: Path, raw: RawTaskRecord, spec: TaskIntakeS
|
|
|
449
530
|
with (d/'final_message.txt').open('a') as f:
|
|
450
531
|
f.write('\n\n' + diagnostics_text(contract_diagnostics))
|
|
451
532
|
trace, actual, trace_valid=ensure_attempt_outputs(package_root, spec, attempt_kind, prompt, 'custom', run_error)
|
|
533
|
+
ended_at = utc_now()
|
|
534
|
+
trace = _enrich_runtime_trace(trace, actual, package_root, attempt_kind, 'custom', started_at, ended_at)
|
|
452
535
|
trace.metadata_json['custom_worker_display_name']=settings.custom_worker_display_name
|
|
453
536
|
trace.metadata_json['custom_worker_command_template']=template
|
|
454
537
|
trace.metadata_json['trace_valid']=trace_valid
|