File size: 4,610 Bytes
e1ced8e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""State schema for the Code Compliance Bot β€” extends drawing_reader patterns."""
from __future__ import annotations

import operator
from typing import Annotated, TypedDict

from langgraph.graph import add_messages

# ---------------------------------------------------------------------------
# Reusable types from drawing_reader (re-declared here to stay self-contained)
# ---------------------------------------------------------------------------


class ImageRef(TypedDict):
    """Lightweight reference to an image stored on disk."""
    id: str
    path: str
    label: str
    page_num: int
    crop_type: str       # "full_page" | "crop" | "annotated"
    width: int
    height: int


class CropTask(TypedDict):
    """A single crop+annotate instruction."""
    page_num: int
    crop_instruction: str
    annotate: bool
    annotation_prompt: str
    label: str
    priority: int


class PageMetadata(TypedDict):
    """Structured description of a single PDF page."""
    page_num: int
    sheet_id: str
    sheet_title: str
    discipline: str
    page_type: str
    description: str
    key_elements: list[str]
    spatial_coverage: str


# ---------------------------------------------------------------------------
# New types for code compliance
# ---------------------------------------------------------------------------


class CodeQuery(TypedDict):
    """A single code lookup request produced by the planner or analyst."""
    query: str              # Natural language query for ChromaDB semantic search
    focus_area: str         # e.g., "egress", "fire_protection", "occupancy"
    context: str            # Why this lookup is needed
    priority: int           # 0 = critical, 1 = supplementary


class CodeSection(TypedDict):
    """A retrieved code section from ChromaDB."""
    section_full: str       # e.g., "1005.1"
    code_type: str          # e.g., "Building"
    parent_major: str       # e.g., "10"
    text: str               # Full section text
    relevance: str          # Why this section was retrieved


class AgentMessage(TypedDict):
    """A single message in the inter-agent discussion log."""
    timestamp: str
    agent: str              # "planner" | "code_analyst" | "compliance_analyst" | "reviewer"
    action: str             # "plan" | "search_code" | "analyze" | "request_more" | "review" | "verdict"
    summary: str            # One-line summary for collapsed UI view
    detail: str             # Full content for expanded view
    evidence_refs: list[str]  # Image crop IDs or code section IDs referenced


# ---------------------------------------------------------------------------
# Main state
# ---------------------------------------------------------------------------


class ComplianceState(TypedDict):
    """Full state for the code compliance LangGraph workflow."""

    # -- Conversation --
    messages: Annotated[list, add_messages]
    question: str

    # -- Document (set at ingest time) --
    pdf_path: str
    page_image_dir: str
    num_pages: int

    # -- Page Metadata --
    page_metadata_json: str       # JSON string of per-page metadata

    # -- Planning (from compliance_planner) --
    legend_pages: list[int]
    target_pages: list[int]
    crop_tasks: list[CropTask]
    code_queries: list[CodeQuery]

    # -- Images (additive reducer β€” new refs are appended, never replaced) --
    image_refs: Annotated[list[ImageRef], operator.add]

    # -- Code Lookup Results (additive reducer) --
    code_sections: Annotated[list[CodeSection], operator.add]
    code_report: str
    code_chapters_fetched: list[str]

    # -- Analysis --
    compliance_analysis: str
    reviewer_analysis: str
    final_verdict: str

    # -- Discussion Log (additive reducer β€” the "agents talking" feature) --
    discussion_log: Annotated[list[AgentMessage], operator.add]

    # -- Investigation Loop Control --
    additional_crop_tasks: list[CropTask]
    additional_code_queries: list[CodeQuery]
    needs_more_investigation: bool
    investigation_round: int
    max_rounds: int

    # -- Settings --
    enable_consensus: bool
    enable_annotation: bool

    # -- Status (additive reducer β€” parallel nodes can both write status updates) --
    status_message: Annotated[list[str], operator.add]


# Alias so that copied drawing_reader nodes (cropper, annotator) which import
# ``DrawingReaderState`` keep working β€” ComplianceState is a superset.
DrawingReaderState = ComplianceState