diff --git a/backend/prompts.py b/backend/prompts.py index 916fd37..2a201a5 100644 --- a/backend/prompts.py +++ b/backend/prompts.py @@ -281,6 +281,30 @@ If the sheet has no extractable objects, return an empty objects array. Optional sheet hint: {sheet_hint}""" +# --------------------------------------------------------------------------- +# Stage 2b - text-only structuring (extraction retry ladder, rung 2) +# --------------------------------------------------------------------------- + +TEXT_STRUCTURING_SYSTEM_PROMPT = """You are a construction document structuring engine. +You receive the deterministic text layer extracted from one drawing sheet. It is complete and authoritative. +Your ONLY job is to segment it into structured objects. You are NOT reading an image. You must NOT invent, complete, or correct any text. +Rules: +- Every numbered note, schedule row, callout, tag, legend entry, and title-block field becomes its own object. +- source_text must be copied VERBATIM from the input, character-for-character. Never paraphrase. +- Cover the ENTIRE input. Omitting a note is a failure. When unsure of an object's type, use general_note with confidence low. +- Numbers, model numbers, dimensions, and tags must appear in source_text exactly as in the input. +Respond only with valid JSON.""" + +TEXT_STRUCTURING_USER_INSTRUCTION = """Segment this sheet's text layer into structured construction objects. +Every note, schedule row, callout, tag, and title-block field in the text layer must become an object - omit nothing. +Respond ONLY with a valid JSON object - no markdown fences: +{ "sheet": { "sheet_number": "string or null", "sheet_title": "string or null", "discipline": "string or null", "drawing_type": "string or null", "level": "string or null", "scale": "string or null" }, "objects": [ { "object_id": "string", "object_type": "room | door | window | wall | finish | ceiling | dimension | grid | callout | keynote | general_note | equipment | plumbing_fixture | mechanical_equipment | electrical_device | lighting_fixture | structural_element | schedule_reference | symbol | abbreviation", "category": "architectural | structural | mechanical | electrical | plumbing | code | general", "tag": "string or null", "name": "string or null", "description": "string or null", "attributes": { "attribute_name": "attribute_value" }, "location_key": { "room_number": "string or null", "grid": "string or null", "detail_reference": "string or null" }, "source_text": "VERBATIM text copied from the input", "graphical_basis": null, "review_uses": [ "schedule_comparison", "cross_discipline_coordination", "code_review", "constructability_review" ], "confidence": "high | medium | low" } ], "unresolved_items": [] } +Optional sheet hint: {sheet_hint} + +TEXT LAYER (segment ALL of it): +{text_layer}""" + + # --------------------------------------------------------------------------- # Stage 3a - assertion normalization (WIRED: normalizer.py) # --------------------------------------------------------------------------- diff --git a/tests/agents/test_extraction_ladder.py b/tests/agents/test_extraction_ladder.py new file mode 100644 index 0000000..33ea10c --- /dev/null +++ b/tests/agents/test_extraction_ladder.py @@ -0,0 +1,6 @@ +from backend.prompts import TEXT_STRUCTURING_SYSTEM_PROMPT, TEXT_STRUCTURING_USER_INSTRUCTION + +def test_text_structuring_prompt_demands_verbatim_and_completeness(): + assert "verbatim" in TEXT_STRUCTURING_USER_INSTRUCTION.lower() + assert "every" in TEXT_STRUCTURING_USER_INSTRUCTION.lower() + assert "{text_layer}" in TEXT_STRUCTURING_USER_INSTRUCTION