5656PROMPT_DIR = HERE / "agent" / "prompts"
5757SYSTEM_PROMPT_PATH = PROMPT_DIR / "system.md"
5858ROUTER_PROMPT_PATH = PROMPT_DIR / "router.md"
59+ PROMPT_TARGET_NAMES = ("system_prompt" , "router_prompt" )
5960DEFAULT_RUNS_DIR = HERE / "runs"
6061DEFAULT_SEED = 7
6162DEFAULT_MAX_SECONDS = 180.0
@@ -279,19 +280,12 @@ def validate_prompt_artifacts(artifacts: list[dict[str, Any]], label: str) -> No
279280 candidate_path = REPO_ROOT / candidate_path
280281 if candidate_path .is_file () and candidate_path .read_text (encoding = "utf-8" ) != content :
281282 reject (f"{ label } prompt artifact content does not match the referenced file" )
282- source_path = Path (artifact ["source_path" ])
283- if not source_path .is_absolute ():
284- source_path = REPO_ROOT / source_path
285- if source_path .is_file ():
286- source_text = source_path .read_text (encoding = "utf-8" )
287- if artifact ["diff" ] != prompt_diff (source_text , content , artifact ["name" ]):
288- reject (f"{ label } prompt artifact diff does not match source and candidate content" )
289283
290284 for summary_name in ("train" , "optimizer_dev" , "validation" , "final_validation" ):
291285 reject_duplicate_cases (baseline [summary_name ], f"baseline.{ summary_name } " )
292286 validate_evaluation_summary (baseline [summary_name ], f"baseline.{ summary_name } " )
293287 validate_prompt_artifacts (baseline ["prompt_artifacts" ], "baseline" )
294- baseline_prompt_names = {artifact ["name" ] for artifact in baseline ["prompt_artifacts" ]}
288+ baseline_prompts_by_name = {artifact ["name" ]: artifact for artifact in baseline ["prompt_artifacts" ]}
295289
296290 if report ["failure_attribution" ] != attribution_for (baseline ["validation" ]):
297291 reject ("top-level failure attribution does not match baseline validation failures" )
@@ -313,6 +307,34 @@ def validate_prompt_artifacts(artifacts: list[dict[str, Any]], label: str) -> No
313307 reject ("evaluation config hash does not match the normalized snapshot" )
314308 expected_judge_multiplier = judge_calls_per_agent_call (evaluation_snapshot )
315309 config_paths = config_snapshot ["paths" ]
310+ expected_prompt_names = set (PROMPT_TARGET_NAMES )
311+ prompt_targets = config_snapshot ["prompt_targets" ]
312+ if set (prompt_targets ) != expected_prompt_names :
313+ reject ("prompt target manifest must contain exactly the registered target names" )
314+ if set (baseline_prompts_by_name ) != expected_prompt_names :
315+ reject ("baseline prompt artifacts must match the registered target names" )
316+ for name in PROMPT_TARGET_NAMES :
317+ target = prompt_targets [name ]
318+ baseline_artifact = baseline_prompts_by_name [name ]
319+ expected_source_path = config_paths [name ]
320+ if target ["source_path" ] != expected_source_path :
321+ reject (f"prompt target source path does not match config paths: { name } " )
322+ if report ["artifacts" ].get (name ) != expected_source_path :
323+ reject (f"prompt source path does not match report artifacts: { name } " )
324+ if baseline_artifact ["source_path" ] != expected_source_path :
325+ reject (f"baseline prompt source path does not match target manifest: { name } " )
326+ if target ["sha256" ] != baseline_artifact ["sha256" ]:
327+ reject (f"prompt target hash does not match baseline content: { name } " )
328+ if baseline_artifact ["diff" ] != prompt_diff (baseline_artifact ["content" ], baseline_artifact ["content" ], name ):
329+ reject (f"baseline prompt diff does not match embedded baseline content: { name } " )
330+ source_path = Path (expected_source_path )
331+ if not source_path .is_absolute ():
332+ source_path = REPO_ROOT / source_path
333+ if not source_path .is_file ():
334+ reject (f"referenced prompt source artifact must exist: { name } " )
335+ source_text = source_path .read_text (encoding = "utf-8" )
336+ if sha256_text (source_text ) != target ["sha256" ] or source_text != baseline_artifact ["content" ]:
337+ reject (f"prompt target manifest does not match the referenced source artifact: { name } " )
316338 expected_optimizer_config_path = config_paths ["optimizer_config" ]
317339 if report ["artifacts" ].get ("optimizer_config" ) != expected_optimizer_config_path :
318340 reject ("optimizer config path does not match report artifacts" )
@@ -375,6 +397,8 @@ def validate_prompt_artifacts(artifacts: list[dict[str, Any]], label: str) -> No
375397 reject ("optimization round identifiers must be unique" )
376398 for round_record in report ["optimization_rounds" ]:
377399 prompt_keys = set (round_record ["prompt_paths" ])
400+ if not prompt_keys .issubset (expected_prompt_names ):
401+ reject ("optimization round contains an unknown prompt target" )
378402 if prompt_keys != set (round_record ["prompt_sha256" ]) or prompt_keys != set (round_record ["prompt_contents" ]):
379403 reject ("optimization round prompt path, hash, and content keys must match" )
380404 for name in prompt_keys :
@@ -460,8 +484,21 @@ def validate_prompt_artifacts(artifacts: list[dict[str, Any]], label: str) -> No
460484 if candidate_audit ["config_sha256" ] != expected_optimizer_config_hash :
461485 reject (f"candidate audit config hash does not match config snapshot: { candidate_id } " )
462486 validate_prompt_artifacts (candidate ["prompt_artifacts" ], f"candidate { candidate_id } " )
463- if {artifact ["name" ] for artifact in candidate ["prompt_artifacts" ]} != baseline_prompt_names :
487+ candidate_prompts_by_name = {artifact ["name" ]: artifact for artifact in candidate ["prompt_artifacts" ]}
488+ if set (candidate_prompts_by_name ) != expected_prompt_names :
464489 reject (f"candidate prompt artifact names must match baseline targets: { candidate_id } " )
490+ for name in PROMPT_TARGET_NAMES :
491+ candidate_artifact = candidate_prompts_by_name [name ]
492+ baseline_artifact = baseline_prompts_by_name [name ]
493+ if candidate_artifact ["source_path" ] != prompt_targets [name ]["source_path" ]:
494+ reject (f"candidate prompt source path must match target manifest: { candidate_id } /{ name } " )
495+ expected_diff = prompt_diff (
496+ baseline_artifact ["content" ],
497+ candidate_artifact ["content" ],
498+ name ,
499+ )
500+ if candidate_artifact ["diff" ] != expected_diff :
501+ reject (f"candidate prompt diff does not match embedded baseline: { candidate_id } /{ name } " )
465502 pipeline_cost = cost ["estimated_total" ]
466503 audit_cost = candidate_audit ["cost" ]
467504 if audit_cost ["known" ] is not (pipeline_cost is not None ) or audit_cost ["estimated" ] != pipeline_cost :
@@ -888,35 +925,6 @@ def _prompt_sort_key(item: tuple[Any, Any]) -> tuple[str, str]:
888925 return type (name ).__name__ , repr (name )
889926
890927
891- def _normalized_prompt_artifact_key (
892- name : Any ,
893- used_names : set [str ],
894- ) -> tuple [str , bool , bool ]:
895- if isinstance (name , str ) and name in {"system_prompt" , "router_prompt" }:
896- used_names .add (name )
897- return name , False , False
898- if isinstance (name , str ):
899- normalized_name = Path (name ).name
900- normalized_name = re .sub (r'[<>:"/\\|?*\x00-\x1f]' , "_" , normalized_name )
901- normalized_name = normalized_name .strip (" ." )
902- else :
903- normalized_name = f"prompt_{ type (name ).__name__ } "
904- if not normalized_name or normalized_name in {"." , ".." }:
905- normalized_name = "prompt"
906- if _is_windows_reserved_name (normalized_name ):
907- normalized_name = f"prompt_{ normalized_name } "
908-
909- base_name = normalized_name
910- suffix = 2
911- casefold_collision = False
912- used_casefold_names = {used_name .casefold () for used_name in used_names }
913- while normalized_name .casefold () in used_casefold_names :
914- casefold_collision = True
915- normalized_name = f"{ base_name } __{ suffix } "
916- suffix += 1
917- return normalized_name , normalized_name != name , casefold_collision
918-
919-
920928def write_optimizer_round_artifacts (
921929 * ,
922930 run_dir : Path ,
@@ -958,25 +966,13 @@ def write_optimizer_round_artifacts(
958966 prompt_reasons .append ("candidate_prompts was not a mapping and was normalized to an empty mapping" )
959967 raw_candidate_prompts = {}
960968 raw_prompt_items = sorted (raw_candidate_prompts .items (), key = _prompt_sort_key )
961- used_prompt_names = {
962- raw_name
963- for raw_name , _ in raw_prompt_items
964- if isinstance (raw_name , str ) and raw_name in {"system_prompt" , "router_prompt" }
965- }
966969 for raw_name , raw_content in raw_prompt_items :
967- name , name_was_normalized , casefold_collision = _normalized_prompt_artifact_key (
968- raw_name ,
969- used_prompt_names ,
970- )
971- used_prompt_names .add (name )
972- if name_was_normalized :
973- invalid_prompt_evidence = True
974- if "prompt artifact key was normalized safely" not in prompt_reasons :
975- prompt_reasons .append ("prompt artifact key was normalized safely" )
976- if casefold_collision :
970+ if not isinstance (raw_name , str ) or raw_name not in PROMPT_TARGET_NAMES :
977971 invalid_prompt_evidence = True
978- if "prompt filenames collided case-insensitively" not in prompt_reasons :
979- prompt_reasons .append ("prompt filenames collided case-insensitively and were disambiguated" )
972+ if "unknown prompt target was dropped" not in prompt_reasons :
973+ prompt_reasons .append ("unknown prompt target was dropped" )
974+ continue
975+ name = raw_name
980976 if isinstance (raw_content , str ):
981977 content = raw_content
982978 else :
@@ -1605,6 +1601,16 @@ def read_source_prompts(system_prompt: Path, router_prompt: Path) -> dict[str, t
16051601 }
16061602
16071603
1604+ def build_prompt_target_manifest (
1605+ source_prompts : Mapping [str , tuple [Path , str ]],
1606+ ) -> dict [str , dict [str , str ]]:
1607+ return {
1608+ name : {"source_path" : str (source_path ), "sha256" : sha256_text (source_text )}
1609+ for name in PROMPT_TARGET_NAMES
1610+ for source_path , source_text in [source_prompts [name ]]
1611+ }
1612+
1613+
16081614def offline_candidate_prompts (
16091615 source_prompts : dict [str , tuple [Path , str ]],
16101616 candidate_id : str ,
@@ -3124,6 +3130,7 @@ async def build_offline_report(
31243130 "evaluation_sha256" : sha256_json (evaluation_snapshot ),
31253131 "evaluation_metrics_sha256" : sha256_json_file (metrics_path ),
31263132 "optimizer_config_sha256" : sha256_json_file (optimizer_config ),
3133+ "prompt_targets" : build_prompt_target_manifest (source_prompts ),
31273134 "evalsets" : build_evalset_manifests (train_evalset , optimizer_dev_evalset , val_evalset ),
31283135 "paths" : {
31293136 "train_evalset" : str (train_evalset ),
@@ -3669,9 +3676,7 @@ async def counted_optimizer_call_agent(query: str) -> str:
36693676 run_dir = run_dir ,
36703677 candidate_id = "baseline" ,
36713678 source_prompts = source_prompts ,
3672- candidate_prompts = dict (
3673- getattr (result , "baseline_prompts" , {}) or {name : text for name , (_ , text ) in source_prompts .items ()}
3674- ),
3679+ candidate_prompts = {name : text for name , (_ , text ) in source_prompts .items ()},
36753680 summary = "Source prompts before AgentOptimizer.optimize." ,
36763681 source_written = False ,
36773682 )
@@ -3770,6 +3775,7 @@ async def counted_optimizer_call_agent(query: str) -> str:
37703775 "evaluation_sha256" : sha256_json (evaluation_snapshot ),
37713776 "evaluation_metrics_sha256" : sha256_json_file (metrics_path ),
37723777 "optimizer_config_sha256" : sha256_json_file (runtime_optimizer_path ),
3778+ "prompt_targets" : build_prompt_target_manifest (source_prompts ),
37733779 "evalsets" : build_evalset_manifests (train_path , optimizer_dev_path , val_path ),
37743780 "paths" : {
37753781 "train_evalset" : str (train_path ),
0 commit comments