Skip to content

Specialist routing

The Router class in src/pipeline/router.py determines which specialist enrichment strategies apply to a given extraction result, plans their execution order, and assigns relevant context items to each specialist.

How routing works

The router receives an ExtractionResult and a UserTableSchema. It builds a compact summary of the extraction data — table roles, headers, row counts, sample cell values, context types, context_ids, and content snippets — and sends it to the advanced Gemini model (gemini-3.1-pro-preview) with the ROUTER prompt. Gemini returns a GeminiRoutingResult containing strategies, execution order, context assignments, and reasoning.

def route(self, extraction_result, schema) -> GeminiRoutingResult:
    summary = self._build_summary(extraction_result, schema)
    result = self.gemini.request(summary, GeminiRoutingResult, model=ModelType.ADVANCED)
    return result

The summary includes sample cell values from the first three rows of each main table (up to five columns) and the context_id of each context item. This allows the router to detect patterns like compound references (GL-03/GMT-01) and to assign specific context items to strategies by ID.

The five strategy types

Each strategy type maps to a specialist prompt and a specific enrichment approach. The router selects a strategy only when clear evidence exists in the extraction data.

Strategy Prompt constant Task Evidence required
auxiliary_table AUXILIARY_TABLE_ENRICHMENT Match reference codes to auxiliary table rows At least one AUXILIARY table with rows
text_rule TEXT_RULE_ENRICHMENT Apply general notes, code requirements, and performance specs Text context with actionable rules or conditional statements
image_legend LEGEND_ENRICHMENT Match style codes to legend diagram interpretations Image context with style codes, operability types, or configurations
dimension_card DIMENSION_ENRICHMENT Extract dimensions from item cards and detail drawings Image context with specific measurements or dimensions
multi_label MULTI_LABEL_ENRICHMENT Resolve compound references and shared item cards Cell values with / or , separators, or image context with multiple type mark labels

T1: Auxiliary table enrichment

The auxiliary table specialist handles cross-referencing between the main schedule and auxiliary reference tables. It matches reference codes (e.g., GL-03, HW-05) from main schedule columns to auxiliary table rows and pulls matching data into the target schema columns. For compound references like GL-03/GMT-01, it resolves the primary component and notes secondaries in Special Notes.

T2: Text rule enrichment

The text rule specialist applies document-level rules extracted as text context items. These include IBC code requirements (e.g., "tempered glass within 24 inches of a door"), performance specifications (U-value, STC, SHGC targets), material requirements, and general notes with conditional statements. Results appear primarily in Special Notes.

T3: Legend enrichment

The legend specialist matches style codes or type designations from the main schedule to legend diagram interpretations in image context. It fills operability (using constrained enum values for WindowOperabilityType / DoorOperabilityType), glass arrangement configuration, and panel attributes. It supports subtype inheritance — when a row like P1a has no direct legend match, it inherits from the base type P1.

T4: Dimension enrichment

The dimension specialist extracts Width, Height, Rough Opening Measurements, Glass Arrangement Configuration, and other dimensional values from item card diagrams and detail drawings in image context. It matches drawings to schedule rows via type marks or labels. Panel layout data (panel heights, types, counts) is extracted into the Glass Arrangement Configuration column rather than Special Notes.

T5: Multi-label enrichment

The multi-label specialist handles two patterns:

  1. Compound cell values — Main schedule cells containing / or , separating multiple reference codes (e.g., GL-03/GMT-01). The specialist determines primary vs. secondary components using construction domain knowledge (GL- prefix is typically primary for fenestration).
  2. Shared item cards — A single image context diagram that labels multiple schedule items (e.g., W39A-PTHP / W39B-NO PTHP). The specialist maps variant-specific attributes to the correct rows by matching card labels to __row_id__ values.

Execution planning

The router determines not only which strategies to run but in what order. The GeminiRoutingResult includes three key fields:

  • strategies — the list of selected strategy types
  • execution_order — an ordered list of stages, where each stage is a list of strategies that can safely run in parallel. Strategies in later stages may depend on output from earlier stages.
  • context_assignments — a dict mapping each strategy name to a list of context_id values relevant to that strategy

Execution order

The router reasons about dependencies between strategies for the specific document. For example:

  • If text_rule needs resolved reference values from auxiliary_table to apply conditional rules correctly, auxiliary_table runs in an earlier stage.
  • multi_label always runs in the final stage so it can work with fully resolved data.
  • If no dependencies exist, all strategies (except multi_label) run in a single parallel stage.

Example with dependencies:

[["auxiliary_table"], ["text_rule", "image_legend", "dimension_card"], ["multi_label"]]

Example without dependencies:

[["auxiliary_table", "text_rule", "image_legend", "dimension_card"], ["multi_label"]]

Context assignments

The router assigns specific context items to each strategy using their context_id values. Default assignment rules:

Strategy Default context assignment
auxiliary_table No context items (reads auxiliary tables only)
text_rule Text context items only (TextContextModel)
image_legend Legend image context items only
dimension_card Item card / elevation drawing image context items
multi_label Same image context items as dimension_card

A context item can be assigned to multiple strategies if relevant to both. The router overrides defaults when document evidence suggests a different assignment.

Model tier

The router uses ModelType.ADVANCED (Gemini Pro). The router's expanded responsibilities — dependency analysis, context assignment, and execution planning — justify the advanced model tier. Specialists are demoted to ModelType.FAST (Gemini Flash) since they receive pre-filtered, pre-assigned payloads.

Monolithic fallback

When the router returns an empty strategy list — meaning no specialist has clear supporting evidence — the enricher falls back to the monolithic ENRICHMENT prompt. This single Gemini call receives all tables, context, and schema, and attempts to fill every column from any available source in one pass. Unlike specialist mode, this path does not use FIELD_AUTHORITY_MATRIX resolution across multiple strategy outputs.

Routing decision flow

The following diagram shows, via an example run, how the router's output determines the enrichment path.

flowchart TB
    ER["ExtractionResult + Schema"] --> ROUTER["Router<br/>(Gemini Pro)"]
    ROUTER --> CHECK{strategies<br/>returned?}

    CHECK -->|empty| MONO["Monolithic ENRICHMENT<br/>(single Gemini Pro call)"]
    MONO --> OUT["list[EnrichedRow]"]

    CHECK -->|non-empty| PLAN["Staged execution plan"]
    PLAN --> STAGE1["Stage 1: [auxiliary_table]<br/>(Gemini Flash)"]
    STAGE1 --> MERGE1["MergeResolver<br/>(all completed outputs)"]
    MERGE1 --> STAGE2["Stage 2: [text_rule, image_legend, dimension_card]<br/>(Gemini Flash, concurrent)"]
    STAGE2 --> MERGE2["MergeResolver<br/>(all completed outputs)"]
    MERGE2 --> STAGE3["Stage 3: [multi_label]<br/>(Gemini Flash)"]
    STAGE3 --> MERGE3["MergeResolver"]
    MERGE3 --> ADJ["SpecialNotesAdjudicator<br/>(semantic bullets)"]
    ADJ --> VALID["Enum validation<br/>(Other: ... fallback)"]
    VALID --> OUT

Not every specialist runs on every document. The router only selects strategies with clear evidence, so a typical run activates two to three specialists. The number of stages depends on whether dependencies exist between the selected strategies.