feat: refocus on drawings — code/ADA gated off, drawing-integrity wave, Brain-directed clarification
- ENABLE_CODE_REVIEW flag (default off): skips code/ADA/jurisdiction review path in both pipelines; nothing deleted, one env flag to restore. - Per-sheet Drawing Integrity QA wave (agent + classic, default on): dangling refs, on-sheet contradictions, dimension sanity, missing sheet essentials, tag hygiene. New DrawingIntegrityAgent + classic stage. - Broadened conflict critic: intra-sheet + same-discipline contradictions, not just cross-discipline. - Wave 6.5 Brain-directed clarification (bounded hub-and-spoke): Brain names uncertain findings, verify_evidence requests route through the wave-5b verifier; refuted findings suppressed. One planning call + capped verifies, single iteration. Shared _build_verify_scopes across 5b and 6.5. - Config knobs, .env.example, frontend copy, tests (182 passing).
This commit is contained in:
+51
-4
@@ -12,6 +12,15 @@ load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env"))
|
||||
|
||||
_BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
_TRUTHY = ("1", "true", "yes", "on")
|
||||
|
||||
|
||||
def _flag(name: str, default: str) -> bool:
|
||||
"""Parse a boolean env knob. Accepts 1/true/yes/on (case-insensitive) so a
|
||||
knob set to "1" behaves the same as one set to "true" — mixing bare
|
||||
`== "true"` comparisons with this set silently disabled features."""
|
||||
return os.getenv(name, default).strip().lower() in _TRUTHY
|
||||
|
||||
# -- AI Backend (OpenRouter) ----------------------------------------
|
||||
# One multimodal model does both extraction (Stage 1) and conflict
|
||||
# reasoning (Stage 3). Override MODEL per-stage if you ever split them.
|
||||
@@ -47,6 +56,33 @@ AGENT_CONFLICT_CONCURRENCY = int(os.getenv("AGENT_CONFLICT_CONCURRENCY", "4"))
|
||||
AGENT_SPECIALIST_CONCURRENCY = int(os.getenv("AGENT_SPECIALIST_CONCURRENCY", "4"))
|
||||
AGENT_RFI_CONCURRENCY = int(os.getenv("AGENT_RFI_CONCURRENCY", "4"))
|
||||
|
||||
# -- Review focus toggles -------------------------------------------
|
||||
# ENABLE_CODE_REVIEW gates the code/ADA/jurisdiction review path in BOTH
|
||||
# pipelines. Default OFF: the product's focus is drawing-integrity and
|
||||
# cross-discipline coordination, not code/accessibility compliance. When
|
||||
# False the CodeAgent wave (agent) and the Code/ADA stage (classic) are
|
||||
# skipped entirely, by_stage.code reports 0, and nothing in the ADA corpus
|
||||
# or jurisdiction meta is deleted so the path can be re-enabled with one env
|
||||
# flag. Set ENABLE_CODE_REVIEW=1 to restore code/ADA findings.
|
||||
ENABLE_CODE_REVIEW = _flag("ENABLE_CODE_REVIEW", "false")
|
||||
|
||||
# Per-sheet Drawing Integrity QA wave (agent + classic). This is the
|
||||
# drawing-focused pass: it reads ONE sheet's own objects + image + text layer
|
||||
# and flags problems internal to that sheet -- dangling detail/callout/keynote
|
||||
# references, schedule-vs-plan or legend disagreements on the same sheet,
|
||||
# dimension strings that do not sum, missing title-block/scale/north-arrow,
|
||||
# and notes that contradict each other. It complements (does not replace) the
|
||||
# cross-sheet conflict critic. Default ON.
|
||||
ENABLE_DRAWING_INTEGRITY = _flag("ENABLE_DRAWING_INTEGRITY", "true")
|
||||
AGENT_INTEGRITY_MODEL = os.getenv("AGENT_INTEGRITY_MODEL", "") or MODEL
|
||||
AGENT_INTEGRITY_CONCURRENCY = int(os.getenv("AGENT_INTEGRITY_CONCURRENCY", "4"))
|
||||
AGENT_INTEGRITY_MAX_IMAGES = int(os.getenv("AGENT_INTEGRITY_MAX_IMAGES", "1"))
|
||||
AGENT_INTEGRITY_MAX_ASSERTIONS = int(os.getenv("AGENT_INTEGRITY_MAX_ASSERTIONS", "80"))
|
||||
INTEGRITY_MAX_TOKENS = int(os.getenv("INTEGRITY_MAX_TOKENS", "16384"))
|
||||
# Skip sheets with fewer than this many extracted objects -- too sparse for a
|
||||
# meaningful internal-consistency pass (avoids burning a call on near-empty pages).
|
||||
INTEGRITY_MIN_ASSERTIONS = int(os.getenv("INTEGRITY_MIN_ASSERTIONS", "3"))
|
||||
|
||||
# Wave 5b evidence verification (vision fact-check of cited sheet text)
|
||||
AGENT_VERIFY_MODEL = os.getenv("AGENT_VERIFY_MODEL", "") or MODEL
|
||||
AGENT_VERIFY_CONCURRENCY = int(os.getenv("AGENT_VERIFY_CONCURRENCY", "4"))
|
||||
@@ -59,6 +95,17 @@ AGENT_VERIFY_SEVERITIES = {
|
||||
AGENT_VERIFY_REASONING_EFFORT = os.getenv("AGENT_VERIFY_REASONING_EFFORT", "low").strip()
|
||||
VERIFY_MAX_TOKENS = int(os.getenv("VERIFY_MAX_TOKENS", "8192"))
|
||||
|
||||
# Wave 6.5 Brain-directed clarification. After the Brain merge, the Brain may
|
||||
# name findings it is unsure about and emit typed clarification requests; v1
|
||||
# executes verify_evidence requests by routing them back through the wave-5b
|
||||
# EvidenceVerifierAgent (fresh page images + hi-DPI evidence crops + text-layer
|
||||
# oracle). Bounded: one planning call, at most BRAIN_CLARIFY_MAX_REQUESTS
|
||||
# verifications, a single iteration. Reuses AGENT_VERIFY_* / VERIFY_* knobs for
|
||||
# the verification calls. Default ON.
|
||||
ENABLE_BRAIN_CLARIFY = _flag("ENABLE_BRAIN_CLARIFY", "true")
|
||||
BRAIN_CLARIFY_MAX_REQUESTS = int(os.getenv("BRAIN_CLARIFY_MAX_REQUESTS", "8"))
|
||||
BRAIN_CLARIFY_MAX_TOKENS = int(os.getenv("BRAIN_CLARIFY_MAX_TOKENS", "4096"))
|
||||
|
||||
# -- Text-layer grounding (deterministic PDF text layer via PyMuPDF) ----
|
||||
# The vector text layer is extracted once per job and grounds the extractor,
|
||||
# rescues misquoted-but-real values in the grounding guard, and serves the
|
||||
@@ -118,8 +165,8 @@ EXTRACT_REASONING_MAX_TOKENS = int(os.getenv("EXTRACT_REASONING_MAX_TOKENS", "20
|
||||
# structuring pass (rung 2), then deterministic text-layer fallback stubs
|
||||
# (rung 3) so no text-bearing page goes dark.
|
||||
EXTRACT_COVERAGE_FLOOR = float(os.getenv("EXTRACT_COVERAGE_FLOOR", "0.6"))
|
||||
EXTRACT_TEXT_RETRY_ENABLED = os.getenv("EXTRACT_TEXT_RETRY_ENABLED", "true").lower() == "true"
|
||||
EXTRACT_FALLBACK_ENABLED = os.getenv("EXTRACT_FALLBACK_ENABLED", "true").lower() == "true"
|
||||
EXTRACT_TEXT_RETRY_ENABLED = _flag("EXTRACT_TEXT_RETRY_ENABLED", "true")
|
||||
EXTRACT_FALLBACK_ENABLED = _flag("EXTRACT_FALLBACK_ENABLED", "true")
|
||||
EXTRACT_FALLBACK_MAX_OBJECTS = int(os.getenv("EXTRACT_FALLBACK_MAX_OBJECTS", "200"))
|
||||
REASON_MAX_TOKENS = int(os.getenv("REASON_MAX_TOKENS", "4096"))
|
||||
|
||||
@@ -191,5 +238,5 @@ SMTP_PORT = int(os.getenv("SMTP_PORT", "587"))
|
||||
SMTP_USER = os.getenv("SMTP_USER", "")
|
||||
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD", "")
|
||||
SMTP_FROM = os.getenv("SMTP_FROM", "")
|
||||
SMTP_USE_TLS = os.getenv("SMTP_USE_TLS", "true").lower() == "true"
|
||||
SMTP_USE_SSL = os.getenv("SMTP_USE_SSL", "false").lower() == "true"
|
||||
SMTP_USE_TLS = _flag("SMTP_USE_TLS", "true")
|
||||
SMTP_USE_SSL = _flag("SMTP_USE_SSL", "false")
|
||||
|
||||
Reference in New Issue
Block a user