semantic routing #5: added semantic classifier for complexity router + handlers changes - #5680
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (20)
🚧 Files skipped from review as they are similar to previous changes (18)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds semantic complexity routing with configurable exemplars, embedding-backed classification, vector-store warmup, lexical fallback, runtime status APIs, configuration validation, and frontend support. ChangesSemantic routing
Estimated code review effort: 4 (Complex) | ~60–90 minutes Mergeability Score: ⚪ Minimal · up to This PR adds semantic complexity routing and related configuration, API, and UI support; no actionable merge-blocking risk remains based on the supplied evidence. Sequence Diagram(s)sequenceDiagram
participant Client
participant GovernanceHandler
participant BifrostHTTPServer
participant GovernancePlugin
participant SemanticClassifier
participant VectorStore
Client->>GovernanceHandler: Update semantic analyzer configuration
GovernanceHandler->>BifrostHTTPServer: Validate normalized configuration
BifrostHTTPServer->>GovernancePlugin: ValidateComplexityAnalyzerConfig
GovernancePlugin->>SemanticClassifier: ValidateConfig
alt Configuration valid
GovernanceHandler->>GovernancePlugin: Persist and apply configuration
GovernancePlugin->>SemanticClassifier: Configure
SemanticClassifier->>VectorStore: Warm exemplar generation
else Configuration invalid
GovernanceHandler-->>Client: Return HTTP 400
end
Client->>GovernanceHandler: Get semantic status
GovernanceHandler->>BifrostHTTPServer: Request runtime status
BifrostHTTPServer->>GovernancePlugin: ComplexitySemanticStatus
GovernancePlugin->>SemanticClassifier: Status
SemanticClassifier-->>Client: Return readiness state and progress
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
ui/lib/store/apis/governanceApi.ts (1)
860-865: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueSemantic status is asynchronous — plan for refresh at the consumer.
The endpoint has no tag and no polling, so a component rendering warmup state will hold a stale
warming/failedvalue until remount. Either give it aComplexityAnalyzerConfig-adjacent tag or setpollingIntervalwhere the hook is used.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/lib/store/apis/governanceApi.ts` around lines 860 - 865, Update the getComplexitySemanticStatus query usage so consumers refresh asynchronous warming or failed states without requiring a remount. Prefer adding a pollingInterval where the generated getComplexitySemanticStatus hook is used, or add a tag adjacent to ComplexityAnalyzerConfig and invalidate it when status changes; preserve the existing endpoint request behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@ui/lib/store/apis/governanceApi.ts`:
- Around line 860-865: Update the getComplexitySemanticStatus query usage so
consumers refresh asynchronous warming or failed states without requiring a
remount. Prefer adding a pollingInterval where the generated
getComplexitySemanticStatus hook is used, or add a tag adjacent to
ComplexityAnalyzerConfig and invalidate it when status changes; preserve the
existing endpoint request behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: ef346c26-f999-4206-90b6-3457af91fe9b
📒 Files selected for processing (19)
core/schemas/bifrost.goframework/configstore/complexityconfig.goframework/configstore/complexityconfig_test.goplugins/governance/complexity/config.goplugins/governance/complexity/exemplars.goplugins/governance/complexity/exemplars_test.goplugins/governance/complexity/semanticclassifier.goplugins/governance/complexity/semanticclassifier_test.goplugins/governance/embedding.goplugins/governance/embedding_test.goplugins/governance/main.goplugins/governance/prerequesthookcomplexity_test.gotransports/bifrost-http/handlers/governance.gotransports/bifrost-http/handlers/governance_test.gotransports/bifrost-http/server/server.goui/app/workspace/complexity-router/page.tsxui/lib/store/apis/governanceApi.tsui/lib/types/complexityRouter.tsui/lib/types/logs.ts
383a002 to
7fc26f3
Compare
fad421f to
3747cee
Compare
7fc26f3 to
fde1d48
Compare
3747cee to
e755887
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ui/app/workspace/complexity-router/page.tsx (1)
379-385: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAttach the dependency to the field being validated, not the source field.
The validation on
medium_complexdepends on the value ofsimple_medium. Line 380 checksvalue <= simple_mediumwhenkey === "medium_complex". Whensimple_mediumchanges,medium_complexmust revalidate.The current code sets
depson thesimple_mediumregistration, not onmedium_complex. React Hook Form requiresdepsto be attached to the field that depends on other fields. Setdepsonmedium_complexto declare its dependency onsimple_medium:Proposed fix
- deps: key === "simple_medium" ? ["tier_boundaries.medium_complex"] : undefined, + deps: key === "medium_complex" ? ["tier_boundaries.simple_medium"] : undefined,This change ensures
medium_complexrevalidates whensimple_mediumchanges, preventing stale validity states between edits.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ui/app/workspace/complexity-router/page.tsx` around lines 379 - 385, Update the validation registration around the `key === "medium_complex"` branch so `deps` is assigned to the `medium_complex` field and references `simple_medium`. Remove the current dependency assignment from the `simple_medium` registration while preserving the existing validation logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ui/app/workspace/complexity-router/page.tsx`:
- Around line 102-114: Update the semantic schema’s timeout field in the visible
semantic object to validate a numeric millisecond wire value instead of a
string. Keep the field optional and preserve the validation behavior of the
other semantic properties so saved configurations continue through handleSubmit
when lexical fields are edited.
---
Outside diff comments:
In `@ui/app/workspace/complexity-router/page.tsx`:
- Around line 379-385: Update the validation registration around the `key ===
"medium_complex"` branch so `deps` is assigned to the `medium_complex` field and
references `simple_medium`. Remove the current dependency assignment from the
`simple_medium` registration while preserving the existing validation logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 676152c0-0ec0-4009-8552-ced677cf4e38
📒 Files selected for processing (19)
core/schemas/bifrost.goframework/configstore/complexityconfig.goframework/configstore/complexityconfig_test.goplugins/governance/complexity/config.goplugins/governance/complexity/exemplars.goplugins/governance/complexity/exemplars_test.goplugins/governance/complexity/semanticclassifier.goplugins/governance/complexity/semanticclassifier_test.goplugins/governance/embedding.goplugins/governance/embedding_test.goplugins/governance/main.goplugins/governance/prerequesthookcomplexity_test.gotransports/bifrost-http/handlers/governance.gotransports/bifrost-http/handlers/governance_test.gotransports/bifrost-http/server/server.goui/app/workspace/complexity-router/page.tsxui/lib/store/apis/governanceApi.tsui/lib/types/complexityRouter.tsui/lib/types/logs.ts
🚧 Files skipped from review as they are similar to previous changes (17)
- ui/lib/types/logs.ts
- plugins/governance/embedding_test.go
- plugins/governance/prerequesthookcomplexity_test.go
- plugins/governance/complexity/config.go
- ui/lib/store/apis/governanceApi.ts
- framework/configstore/complexityconfig_test.go
- plugins/governance/complexity/exemplars_test.go
- framework/configstore/complexityconfig.go
- transports/bifrost-http/handlers/governance_test.go
- transports/bifrost-http/server/server.go
- plugins/governance/complexity/exemplars.go
- transports/bifrost-http/handlers/governance.go
- plugins/governance/embedding.go
- plugins/governance/main.go
- plugins/governance/complexity/semanticclassifier_test.go
- plugins/governance/complexity/semanticclassifier.go
- ui/lib/types/complexityRouter.ts
fde1d48 to
b9eb6f3
Compare
e755887 to
5c018f4
Compare
ee0a136 to
b4d4b30
Compare
4cebab8 to
703229e
Compare
703229e to
7e09645
Compare
b4d4b30 to
2e66e15
Compare
7e09645 to
a8be3be
Compare
2e66e15 to
695c16f
Compare
a8be3be to
f8480f0
Compare
695c16f to
4beb42a
Compare
f8480f0 to
8e1e6e8
Compare
4beb42a to
1936bfc
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
plugins/governance/complexity/semanticclassifier.go (1)
538-539: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the always-true wrapper condition.
dimensionis assigned0on Line 538, so theif dimension == 0test on Line 539 is always true. The inner test on Line 569 carries the real meaning. Delete the outer condition and dedent the block to make the probe logic readable.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugins/governance/complexity/semanticclassifier.go` around lines 538 - 539, Remove the redundant outer dimension == 0 condition around the probe logic, since dimension is initialized to zero immediately beforehand. Dedent the enclosed block while preserving the inner test near line 569 and its existing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plugins/governance/complexity/semanticclassifier.go`:
- Around line 290-302: Add a closed state protected by c.mu and set it in Close
before releasing the lock, then update resetForCurrentConfigLocked and
requestWarmupLocked to return immediately when the classifier is closed. Ensure
post-Close Configure, SetConfiguredStore, and SetEmbeddingFunc calls cannot
restart warmup or reuse the closed ownedStore.
- Around line 556-580: Update the batch embedding handling in the
dimension-detection flow to reject a zero-length vector immediately after
receiving the batch result, before assigning dimension or advancing pending.
Return the existing dimension-detection error with the relevant exemplar
context, ensuring malformed empty probe vectors cannot reach the pending[0]
warmup probe in runWarmupWorker.
---
Nitpick comments:
In `@plugins/governance/complexity/semanticclassifier.go`:
- Around line 538-539: Remove the redundant outer dimension == 0 condition
around the probe logic, since dimension is initialized to zero immediately
beforehand. Dedent the enclosed block while preserving the inner test near line
569 and its existing behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: f1b69934-f781-4551-ba9a-58bd77d255b3
📒 Files selected for processing (6)
core/schemas/bifrost.goframework/configstore/complexityconfig.goframework/configstore/complexityconfig_test.goplugins/governance/complexity/semanticclassifier.goplugins/governance/complexity/semanticclassifier_test.goui/app/workspace/complexity-router/page.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- ui/app/workspace/complexity-router/page.tsx
- framework/configstore/complexityconfig.go
- framework/configstore/complexityconfig_test.go
8e1e6e8 to
96da3e9
Compare
1936bfc to
59a1b32
Compare
96da3e9 to
fa5884a
Compare
0facc99 to
8282f37
Compare
4974bc3 to
601d2b5
Compare
…+ handlers changes
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |

Summary
Adds semantic complexity routing to the Governance plugin. Instead of relying solely on lexical keyword matching, requests can now be classified by embedding the latest user message and finding its nearest labelled exemplar in a VectorStore. This enables more accurate tier assignment for requests that don't contain explicit keywords but are semantically similar to known simple, medium, or complex prompts.
Changes
SemanticClassifier: New component that manages asynchronous exemplar warmup, generation lifecycle (fingerprinted namespaces), and nearest-neighbour classification via a VectorStore. Supports embedded (private Chromem), auto (prefer configured store), and external (require configured store) modes.defaultSimpleExemplars,defaultMediumExemplars, anddefaultComplexExemplars. These are merged with the existing lexical keyword lists so both classifiers share one phrase list.generateEmbeddingssends multi-input requests during warmup and falls back to single-input calls when a provider signalsErrBatchEmbeddingsUnsupported. Response index reordering is handled explicitly.MaxComplexitySemanticPhrases(500) andMaxComplexitySemanticPhraseCharacters(2000).applyRoutingRulesattempts semantic classification first; on success it recordsMechanismSemanticand the cosine similarity score. On failure or unavailability it falls back to lexical or skips based on the configuredfallbackfield.ComplexityVectorStoreSetterinterface: Allows the HTTP server to wire Bifrost's configured shared VectorStore into the Governance plugin at bootstrap and on plugin reload.GET /api/governance/complexity-analyzer-statusreturns the non-persisted semantic classifier readiness (disabled,warming,ready,failed) so UI clients can distinguish a saved config from a ready one.PUT /api/governance/complexity-analyzer-configvalidation: Runtime dependency checks (e.g. external VectorStore availability) now run before the config is persisted.BifrostContextKeyGovernanceComplexityMechanismnow documents"semantic"as a valid value;BifrostContextKeyGovernanceComplexityScoredescription updated to reflect cosine similarity.SemanticConfig,SemanticStatusInfo, anduseGetComplexitySemanticStatusQueryadded. The complexity router form schema preserves thesemanticblock on save. Keyword list labels updated to "tier phrases" to reflect dual lexical/semantic use.MergeComplexityAnalyzerConfigfix: Both merge paths now normalize before validating, ensuring semantic phrase validation sees the same canonical form that will be stored.Type of change
Affected areas
How to test
To exercise semantic routing end-to-end:
complexity_tiercondition.semanticblock to the complexity analyzer config pointing at an OpenAI-compatible embedding model.complexity_mechanism: "semantic"and the matched tier appear in the routing engine logs.fallback: "lexical") and confirm the request falls back to lexical classification withcomplexity_mechanism: "lexical".Breaking changes
Security considerations
Checklist