(template: TaskTemplateSpec, draft: TaskDraftSpec)
| 202 | |
| 203 | |
| 204 | def _validate_draft(template: TaskTemplateSpec, draft: TaskDraftSpec) -> None: |
| 205 | slot_specs = {slot.slot_name: slot for slot in template.slots} |
| 206 | seen_counts: dict[str, int] = {} |
| 207 | |
| 208 | if not draft.base_variation_instruction.strip(): |
| 209 | raise ValueError("Base variation instruction cannot be empty.") |
| 210 | if draft.primary_goal_relation not in template.allowed_relations: |
| 211 | raise ValueError(f"Primary goal relation '{draft.primary_goal_relation}' is not allowed by template.") |
| 212 | if draft.container_slot is not None and draft.container_slot not in slot_specs: |
| 213 | raise ValueError(f"Unknown container slot '{draft.container_slot}'.") |
| 214 | |
| 215 | for relation in draft.fail_relations: |
| 216 | if relation not in template.allowed_relations and relation not in ("on",): |
| 217 | raise ValueError(f"Fail relation '{relation}' is not supported by template.") |
| 218 | |
| 219 | for draft_object in draft.objects: |
| 220 | slot = slot_specs.get(draft_object.slot_name) |
| 221 | if slot is None: |
| 222 | raise ValueError(f"Draft references unknown slot '{draft_object.slot_name}'.") |
| 223 | seen_counts[draft_object.slot_name] = seen_counts.get(draft_object.slot_name, 0) + 1 |
| 224 | if draft_object.group_hint not in _ALLOWED_GROUP_HINTS: |
| 225 | raise ValueError(f"Unsupported group hint '{draft_object.group_hint}'.") |
| 226 | if slot.group_hint != draft_object.group_hint: |
| 227 | raise ValueError( |
| 228 | f"Slot '{draft_object.slot_name}' expects group '{slot.group_hint}', got '{draft_object.group_hint}'." |
| 229 | ) |
| 230 | _validate_closed_range("mass_range", draft_object.mass_range) |
| 231 | _validate_closed_range("target_size_range", draft_object.target_size_range) |
| 232 | if not draft_object.semantic_name.strip(): |
| 233 | raise ValueError(f"Slot '{draft_object.slot_name}' has empty semantic_name.") |
| 234 | if not draft_object.retrieval_query.strip(): |
| 235 | raise ValueError(f"Slot '{draft_object.slot_name}' has empty retrieval_query.") |
| 236 | |
| 237 | for slot_name, slot in slot_specs.items(): |
| 238 | count = seen_counts.get(slot_name, 0) |
| 239 | if count < slot.min_count or count > slot.max_count: |
| 240 | raise ValueError( |
| 241 | f"Slot '{slot_name}' expects count in [{slot.min_count}, {slot.max_count}], got {count}." |
| 242 | ) |
| 243 | |
| 244 | if draft.container_slot is None: |
| 245 | raise ValueError("Current task compiler requires container_slot to be set.") |
| 246 | |
| 247 | |
| 248 | def _validate_closed_range(name: str, values: tuple[float, float]) -> None: |
no test coverage detected