build-small-hackathon/microfactory-lab
2
1"""Post-job reflection — the compression step (the thesis).2 3Reimplements hubAgent.ts `reviewOutcome()` (pattern-review.md §4), re-keyed4from routing-confidence to environment + geometry. A finished job + a5HUMAN-REPORTED outcome becomes one durable, env-keyed LessonEntry. The model6NEVER judges its own outcome — the outcome is always passed in from the manual7button.8"""9 10from __future__ import annotations11 12from datetime import datetime, timezone13 14from . import llm15from .ledger import LedgerManager16from .models import Environment, Job, LessonEntry, PrintSettings17from .prompts import REFLECT_SYSTEM, build_reflect_prompt18 19 20def _settings_summary(s: PrintSettings) -> str:21 return (22 f"nozzle {s.nozzle_temp:.0f}°C, bed {s.bed_temp:.0f}°C, "23 f"retraction {s.retraction_mm:.1f}mm, fan {s.fan_pct:.0f}%, "24 f"first-layer fan {s.first_layer_fan_pct:.0f}%"25 )26 27 28def _fallback_lesson(job: Job, env: Environment, s: PrintSettings, outcome: str) -> str:29 verdict = {30 "success": "held up",31 "failed_sag": "sagged",32 "failed_stringing": "strung",33 }.get(outcome, outcome)34 return (35 f"{job.material} {job.geometry_type} at {env.temp:.0f}°C/{env.humidity:.0f}% RH "36 f"{verdict} with {_settings_summary(s)}."37 )38 39 40def reflect_on_job(41 job: Job,42 env: Environment,43 settings: PrintSettings,44 outcome: str,45 ledger: LedgerManager,46 job_id: str | None = None,47) -> LessonEntry:48 """Distill outcome → lesson, append as an 'earned' entry, return it."""49 raw = llm.chat_json(REFLECT_SYSTEM, build_reflect_prompt(job, env, _settings_summary(settings), outcome))50 lesson = (raw or {}).get("lesson") if isinstance(raw, dict) else None51 if not lesson:52 lesson = _fallback_lesson(job, env, settings, outcome)53 54 entry = LessonEntry(55 job_id=job_id or f"job-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}",56 material=job.material,57 geometry_type=job.geometry_type,58 env_temp=env.temp,59 env_humidity=env.humidity,60 outcome=outcome,61 lesson=lesson,62 source="earned",63 timestamp=datetime.now(timezone.utc).isoformat(),64 )65 ledger.append(entry)66 return entry67 