Tier 2: Rule-Based Routing
Purpose and Scope
Tier 2 implements deterministic, rule-based routing for the Universal Router. It executes after Tier 0 (user overrides, see #9.2) and Tier 1 (cache lookup, see #9.3) fail to produce a routing decision. Tier 2 consists of three sequential sub-strategies that match incoming requests against workspace-configured routing rules, trigger subscriptions, and intent patterns. For LLM-based classification when all rules fail, see Tier 3: LLM Classification.
Tier 2 provides workspace administrators with explicit control over routing behavior through:
Tier 2a: Source pattern matching against
RoutingRuletable entriesTier 2b: Jira trigger subscriptions via
TriggerSubscriptiontable (Composio integration)Tier 2c: Keyword-based intent classification with fallback to rules
All three sub-tiers query database tables filtered by workspace_id to enforce multi-tenancy isolation.
Tier 2 Architecture Overview
Sources: orchestrator/core/routing/engine.py:78-144
Tier 2a: Routing Rules (Source Pattern Matching)
Overview
Tier 2a queries the RoutingRule table to find explicit routing rules configured by workspace administrators. Rules are matched based on the request's source channel and can route to either agents or workflows.
Matching Logic
Sources: orchestrator/core/routing/engine.py:182-214
Implementation Details
The _tier2a_rules method executes the following query pattern:
Query RoutingRule table filtered by
workspace_idandis_active = TrueOrder by priority (descending) to ensure higher-priority rules are evaluated first
Iterate through rules and check
source_patternmatch:If
rule.source_patternisNoneor empty, the rule matches any sourceOtherwise,
rule.source_patternmust exactly matchenvelope.source.value
Return first match with
confidence=0.9and reasoning that includes rule ID
Sources: orchestrator/core/routing/engine.py:182-214
RoutingRule Table Schema
id
int
Primary key
workspace_id
UUID
Workspace isolation
is_active
bool
Enable/disable rule without deletion
priority
int
Higher values evaluated first
source_pattern
str (optional)
Channel source to match (e.g., "slack", "email"). None = match all
target_agent_id
int (optional)
Route to this agent if matched
target_workflow_id
int (optional)
Route to this workflow if matched
intent_keywords
list[str]
Keywords for Tier 2c intent matching
Sources: orchestrator/core/routing/engine.py:183-214, orchestrator/core/models/routing.py
Example Routing Rule Configurations
Sources: orchestrator/core/routing/engine.py:182-214
Tier 2b: Trigger Subscriptions (Jira Integration)
Overview
Tier 2b handles routing for requests originating from Composio trigger subscriptions, specifically Jira webhooks. This tier only executes when envelope.source == ChannelSource.JIRA_TRIGGER.
Resolution Flow
Sources: orchestrator/core/routing/engine.py:220-278
Implementation Details
The _tier2b_trigger_subscription method implements a two-step resolution:
Step 1: Resolve Workspace → Entity
Query
ComposioEntitytable to find the entity associated with the workspaceEach workspace has a unique Composio entity for OAuth connections and trigger subscriptions
Step 2: Find Active Trigger Subscription
Query
TriggerSubscriptiontable filtered byentity_idandis_active = TrueIf
envelope.metadata["trigger_name"]is present, attempt to find an exact matchFalls back to the first active subscription if no exact match
Step 3: Return Routing Decision
Uses
subscription.agent_idorsubscription.workflow_idas the targetReturns
confidence=0.95(higher than Tier 2a rules)Reasoning includes subscription ID and trigger name
Sources: orchestrator/core/routing/engine.py:220-278
TriggerSubscription Table Schema
id
int
Primary key
entity_id
int
Foreign key to ComposioEntity
trigger_name
str
Composio trigger identifier (e.g., "JIRA_NEW_ISSUE_CREATED")
agent_id
int (optional)
Route to this agent
workflow_id
int (optional)
Route to this workflow
is_active
bool
Enable/disable subscription
Sources: orchestrator/core/routing/engine.py:236-278, orchestrator/core/models/composio.py
Tier 2c: Intent Classification
Overview
Tier 2c uses keyword-based intent classification as a fallback when explicit source pattern matching fails. The IntentClassifier analyzes the request content to determine its intent category, then matches that category against routing rules configured with intent_keywords.
Intent Classification Flow
Sources: orchestrator/core/routing/engine.py:284-326
Implementation Details
Step 1: Intent Classification
IntentClassifier.classify(envelope.content)returns{category: str, confidence: float}If
confidence < 0.4, classification is considered too uncertain andNoneis returned
Step 2: Match Against Rule Keywords
Queries the same
RoutingRuletable as Tier 2aFor each rule, checks if
rule.intent_keywordscontains the classified category (case-insensitive match)Returns the first matching rule with the classification's confidence (not hardcoded 0.9)
Step 3: Reasoning
Reasoning string includes the intent category and matched rule ID
Example:
"Intent 'bug_report' matched rule #42 keywords"
Sources: orchestrator/core/routing/engine.py:284-326
IntentClassifier Integration
The IntentClassifier performs lightweight, non-LLM intent detection using keyword matching and pattern recognition. It is initialized once per UniversalRouter instance:
Classification returns:
category: String identifier (e.g.,"bug_report","feature_request","support")confidence: Float between 0 and 1
Sources: orchestrator/core/routing/engine.py:72, orchestrator/core/services/intent_classifier.py
Example Intent Keyword Configuration
Sources: orchestrator/core/routing/engine.py:284-326
Tier 2 Confidence Levels
Each Tier 2 sub-strategy returns a different confidence level to reflect the strength of the match:
Tier 2a
0.9
Explicit source pattern match — high confidence but allows for LLM override if needed
Tier 2b
0.95
Trigger subscription is the most explicit form of routing configuration — highest rule-based confidence
Tier 2c
Variable
Uses IntentClassifier confidence (minimum 0.4), reflecting uncertainty in keyword-based classification
These confidence values affect whether the router proceeds to Tier 3 LLM classification or terminates early. See Tier 3: LLM Classification for threshold-based orchestration logic.
Sources: orchestrator/core/routing/engine.py:204-276, orchestrator/core/routing/engine.py:314-324
Execution Order and Fallthrough
Sources: orchestrator/core/routing/engine.py:108-128
Decision Logging
All successful Tier 2 routing decisions are logged to the RoutingDecisionRecord table for analytics and debugging:
This enables:
Analytics: Track which rules are used most frequently
Debugging: Understand why specific routing decisions were made
Auditing: Compliance and security review of routing behavior
Sources: orchestrator/core/routing/engine.py:561-586
Managing Routing Rules
Creating Routing Rules
Routing rules are created via the Routing API (see /api/routing endpoints):
Sources: orchestrator/api/routing.py
Rule Priority and Ordering
Rules are evaluated in descending priority order (highest first). Best practices:
Assign high priorities (
90-100) to specific, narrow rulesAssign medium priorities (
50-70) to category-based intent rulesAssign low priorities (
10-30) to broad fallback rulesUse
priority=0for disabled-but-kept rules
Sources: orchestrator/core/routing/engine.py:191
Activating and Deactivating Rules
Toggle is_active to enable/disable rules without deletion:
This preserves historical routing decisions and allows easy re-activation.
Sources: orchestrator/core/routing/engine.py:188
Unrouted Events
When all Tier 2 sub-strategies (and Tier 3) fail to produce a routing decision, the request is logged as an UnroutedEvent for later analysis:
Workspace admins can review UnroutedEvent records to identify gaps in routing configuration and create new rules accordingly.
Sources: orchestrator/core/routing/engine.py:539-555
Integration with Tier 1 Cache
Tier 2 decisions are cached by Tier 1 for future requests. After a successful Tier 2 match, the decision is stored in RoutingCache (Redis) with a configurable TTL:
This reduces database queries for repeated requests. See Tier 1: Cache Lookup for cache invalidation and TTL configuration.
Sources: orchestrator/core/routing/engine.py:403-409
Configuration Reference
Tier 2 behavior is controlled by environment variables and database configuration:
ROUTING_CACHE_TTL_HOURS
int
24
Cache TTL for routing decisions (affects Tier 1 caching of Tier 2 results)
ROUTING_LLM_CONFIDENCE_THRESHOLD
float
0.5
Threshold for Tier 3 LLM decisions (not directly used by Tier 2, but affects fallthrough)
Sources: orchestrator/config.py:143-144
Summary
Tier 2 provides deterministic, rule-based routing through three sequential strategies:
Tier 2a: Matches
source_patternagainst workspace routing rules (confidence0.9)Tier 2b: Resolves Jira trigger subscriptions via Composio integration (confidence
0.95)Tier 2c: Uses intent classification with keyword matching against rules (variable confidence
≥0.4)
When all Tier 2 strategies fail, the router falls through to Tier 3 LLM classification. All decisions are logged to RoutingDecisionRecord for analytics, and successful matches are cached for future Tier 1 hits.
Sources: orchestrator/core/routing/engine.py:78-144
Last updated

