Skip to content

refactor: move model-catalog provider resolution into a modelcatalogresolver PreRequestHook plugin - #3934

Merged
akshaydeo merged 1 commit into
devfrom
06-01-feat_add_model_catalog_router_plugin
Jun 9, 2026
Merged

refactor: move model-catalog provider resolution into a modelcatalogresolver PreRequestHook plugin#3934
akshaydeo merged 1 commit into
devfrom
06-01-feat_add_model_catalog_router_plugin

Conversation

@Pratham-Mishra04

@Pratham-Mishra04 Pratham-Mishra04 commented May 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR refactors provider resolution for unprefixed model strings out of the integration router and into a dedicated modelcatalogresolver built-in plugin. Previously, each integration route used a GetRequestModel callback and inline model catalog logic to resolve a provider before the request reached the core pipeline. Now, that responsibility is centralized in a PreRequestHook plugin that runs as the last routing layer, after governance routing rules and load balancing plugins have had a chance to set a provider.

Additionally, PreRequestHook errors are made non-blocking: instead of failing the request immediately on any plugin error, errors are now logged as warnings and the pipeline continues to the next plugin — matching the existing semantics of RunLLMPreHooks.

Changes

  • New plugins/modelcatalogresolver package: A built-in LLMPlugin that implements PreRequestHook to resolve req.Provider from the model catalog when no provider was specified. It prefers the integration's canonical provider (via BifrostContextKeyIntegrationType) when the catalog returns multiple candidates. Registered at position 9 in the built-in plugin order, after all other routing plugins.
  • RunPreRequestHooks made non-blocking: Plugin errors are now accumulated in p.preHookErrors and logged as warnings rather than short-circuiting the pipeline and returning a BifrostError. The Bifrost.RunPreRequestHooks method signature changes from returning *schemas.BifrostError to void.
  • Removed CheckAndSetDefaultProvider: The providerUtils.CheckAndSetDefaultProvider helper and its associated context keys (BifrostContextKeyAvailableProviders, BifrostContextKeySkipModelCatalogProviderSelection) are removed. All call sites in provider packages (anthropic, bedrock, cohere, gemini, openai, vertex) now pass the static default provider directly to schemas.ParseModelString.
  • Removed GetRequestModel from RouteConfig: The per-route model getter callbacks and the inline model catalog resolution block in GenericRouter.createHandler are removed. The RouteConfigTypeToProvider map and RequestModelGetter type are also removed.
  • Simplified resolveModelAndProvider in inference handler: The function no longer performs catalog lookups or returns errors for missing providers; it only parses the model string. Provider validation is deferred to handleRequest/handleStreamRequest.
  • WebSocket realtime handler: Removed the error-handling branch for RunPreRequestHooks since it no longer returns an error.
  • Integration routers (anthropic, bedrock, cohere, genai, openai): All *ModelGetter functions and their references in route configs are removed. The checkAnthropicPassthrough function no longer sets BifrostContextKeySkipModelCatalogProviderSelection.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./...
  • Send a request with an unprefixed model string (e.g., "model": "claude-sonnet-4") through an OpenAI, Anthropic, GenAI, Bedrock, or Cohere integration route and verify the provider is resolved correctly via the model catalog.
  • Send a request with a prefixed model string (e.g., "model": "anthropic/claude-sonnet-4") and verify the explicit provider is respected without catalog lookup.
  • Verify that a PreRequestHook plugin returning an error does not fail the request — the warning should appear in logs and the pipeline should continue.
  • Verify that when no provider can be resolved (empty catalog, no prefix), the request returns a 400 with a clear error about an unresolved provider.

Breaking changes

  • Yes
  • No

Bifrost.RunPreRequestHooks no longer returns *schemas.BifrostError. Any callers outside this repo that check its return value must be updated to remove that check. The LLMPlugin.PreRequestHook contract changes: errors are now non-blocking warnings rather than request-terminating failures.

The BifrostContextKeyAvailableProviders and BifrostContextKeySkipModelCatalogProviderSelection context keys are removed. Any plugins or middleware that set or read these keys must be updated.

Related issues

Security considerations

No new auth, secrets, or PII handling introduced. The model catalog resolver only reads from an in-memory catalog and writes to the request's provider field.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Summary by CodeRabbit

  • New Features

    • Added a model-catalog resolver plugin that deterministically selects a provider for unprefixed model names and can populate fallback choices.
  • Refactor

    • Centralized provider/model resolution: routing now defers implicit provider selection to pre-request hooks/plugins.
    • Unified model-string parsing across providers for more consistent interpretation of model identifiers.
  • Tests/Chores

    • Adjusted/removed tests tied to prior provider-selection behavior.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Pratham-Mishra04, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 27 minutes and 36 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 81358fc8-901c-4277-991d-b0a18c8ca748

📥 Commits

Reviewing files that changed from the base of the PR and between 5ec0e17 and d803fb5.

⛔ Files ignored due to path filters (2)
  • plugins/modelcatalogresolver/go.sum is excluded by !**/*.sum
  • transports/go.sum is excluded by !**/*.sum
📒 Files selected for processing (53)
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/text.go
  • core/providers/bedrock/invoke.go
  • core/providers/bedrock/rerank.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/text.go
  • core/providers/cohere/chat.go
  • core/providers/cohere/count_tokens.go
  • core/providers/cohere/embedding.go
  • core/providers/cohere/rerank.go
  • core/providers/gemini/embedding.go
  • core/providers/gemini/images.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/speech.go
  • core/providers/gemini/transcription.go
  • core/providers/gemini/videos.go
  • core/providers/openai/chat.go
  • core/providers/openai/embedding.go
  • core/providers/openai/images.go
  • core/providers/openai/responses.go
  • core/providers/openai/speech.go
  • core/providers/openai/text.go
  • core/providers/openai/transcription.go
  • core/providers/openai/videos.go
  • core/providers/utils/utils.go
  • core/providers/utils/utils_test.go
  • core/providers/vertex/rerank.go
  • core/schemas/bifrost.go
  • plugins/governance/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/go.mod
  • plugins/modelcatalogresolver/main.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/realtime_client_secrets.go
  • transports/bifrost-http/handlers/webrtc_realtime.go
  • transports/bifrost-http/handlers/webrtc_realtime_test.go
  • transports/bifrost-http/handlers/wsrealtime.go
  • transports/bifrost-http/handlers/wsresponses_test.go
  • transports/bifrost-http/integrations/anthropic.go
  • transports/bifrost-http/integrations/bedrock.go
  • transports/bifrost-http/integrations/bedrock_test.go
  • transports/bifrost-http/integrations/cohere.go
  • transports/bifrost-http/integrations/genai.go
  • transports/bifrost-http/integrations/openai.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/integrations/router_test.go
  • transports/bifrost-http/integrations/utils.go
  • transports/bifrost-http/integrations/utils_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/server/plugins.go
  • transports/go.mod
📝 Walkthrough

Walkthrough

Centralizes provider selection in a new modelcatalogresolver PreRequestHook, removes ctx-driven defaulting from converters and router model-getters, updates transports to defer resolution to hooks, and aligns tests and schema/context keys.

Changes

Provider resolution refactor

Layer / File(s) Summary
Remove context-dependent provider defaults from converters
core/providers/*, core/providers/utils/*, core/schemas/bifrost.go
Converters now call schemas.ParseModelString(..., "") or use explicit provider constants instead of CheckAndSetDefaultProvider; CheckAndSetDefaultProvider removed and ModelMatchesDenylist added.
Add modelcatalogresolver plugin
plugins/modelcatalogresolver/*, transports/bifrost-http/server/plugins.go, transports/go.mod
New plugin deterministically resolves a provider from ModelCatalog in PreRequestHook, sets req.Provider/fallbacks and appends routing metadata; plugin registered as builtin when configured.
Remove routing-layer model extraction callbacks
transports/bifrost-http/integrations/*, transports/bifrost-http/integrations/router.go
Removed RequestModelGetter/GetRequestModel hooks and the router-side available-provider computation; route construction no longer pre-extracts models to populate available-provider context.
Update handlers to defer provider resolution
transports/bifrost-http/handlers/*, transports/bifrost-http/lib/ctx.go
resolveModelAndProvider simplified to parse-only; realtime and client-secret flows call ResolveProviderFromCatalog when needed; websocket upgrade now returns explicit 400 when provider unresolved; added EmitModelCatalogRoutingLog.
Stop filtering fallbacks by available providers
transports/bifrost-http/integrations/utils.go, transports/bifrost-http/lib/config.go
Fallback parsing no longer filters by available providers; HandlerStore.GetProvidersForModel removed from interface and Config.
Update test infrastructure and fallbacks
transports/.../*_test.go, plugins/governance/*, core/providers/utils/utils_test.go
Removed/updated tests that relied on available-provider/resolved-provider context keys; added sendStreamError and ApplyBifrostResponseHeaders tests for error mapping and header propagation.

Sequence Diagram(s)

sequenceDiagram
  participant Router
  participant PreRequestHooks
  participant ModelCatalogResolver
  participant ModelCatalog
  Router->>PreRequestHooks: Run pre request hooks
  PreRequestHooks->>ModelCatalogResolver: Resolve provider from model
  ModelCatalogResolver->>ModelCatalog: Query providers for model
  ModelCatalog-->>ModelCatalogResolver: Candidate providers
  ModelCatalogResolver-->>PreRequestHooks: Selected provider and fallbacks
  PreRequestHooks-->>Router: Continue routing with provider
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related issues

Possibly related PRs

  • maximhq/bifrost#3930: Overlaps with removal of CheckAndSetDefaultProvider and resolved-provider context handling.
  • maximhq/bifrost#3924: Intersects with available-providers removal and fallback filtering changes.
  • maximhq/bifrost#4074: Related to governance/provider scoping and available-providers behavior.

Suggested reviewers

  • danpiths
  • akshaydeo

A rabbit hops through refactored code,
I nudge the model-catalog road,
No more defaults whispered from the air,
The plugin picks providers fair,
Hooray — tidy hops, and clean debug mode! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main refactoring change: moving model-catalog provider resolution logic into a dedicated PreRequestHook plugin.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 06-01-feat_add_model_catalog_router_plugin

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 3/5

The refactor is architecturally sound but ships two unresolved issues from prior reviews plus a new plugin with no unit tests, making it risky to merge as-is.

The governance loadBalanceProvider no longer sets BifrostContextKeyAvailableProviders, so when all VK-scoped providers are filtered out, the modelcatalogresolver resolves from the raw catalog without any VK constraint knowledge. The checkAnthropicPassthrough change silently breaks Anthropic-prefixed model requests on catalog-less deployments. Neither issue is fixed in this diff, and the new modelcatalogresolver package ships with zero unit tests.

plugins/modelcatalogresolver/main.go (no tests; explicit-empty fallbacks not distinguished from unset), transports/bifrost-http/integrations/anthropic.go (prefix-strip without catalog fallback), plugins/governance/main.go (VK provider constraint no longer enforced against catalog resolver)

Important Files Changed

Filename Overview
plugins/modelcatalogresolver/main.go New built-in PreRequestHook plugin for model-catalog provider resolution; missing unit tests, and the len(existingFallbacks)==0 guard cannot distinguish nil from explicit empty, silently overriding caller-supplied empty fallback lists
core/schemas/bifrost.go Removes BifrostContextKeyAvailableProviders, BifrostContextKeyResolvedProvider, and BifrostContextKeySkipModelCatalogProviderSelection keys; RunPreRequestHooks signature changed to void (non-blocking errors)
plugins/governance/httptransportprehook_test.go Six tests covering VK-constrained provider selection deleted without replacement tests for the new modelcatalogresolver flow
plugins/governance/main.go Removes BifrostContextKeyAvailableProviders tracking from loadBalanceProvider; provider filtering logic itself unchanged but the context signal that constrained catalog lookups is gone
transports/bifrost-http/handlers/wsrealtime.go Correctly adds empty-provider error path after RunPreRequestHooks; resolveRealtimeTarget no longer does inline catalog lookup
transports/bifrost-http/handlers/inference.go resolveModelAndProvider simplified to only call ParseModelString; removes empty-model early validation, causing misleading error message when model field is missing
core/providers/utils/utils.go Removes CheckAndSetDefaultProvider and its dependency on removed context keys; straightforward deletion
transports/bifrost-http/integrations/router.go Removes GetRequestModel callback, RouteConfigTypeToProvider map, and 75-line inline catalog resolution block; integration-type context key still set correctly
transports/bifrost-http/handlers/webrtc_realtime.go Three inline catalog lookups replaced with ResolveProviderFromCatalog(nil, ...) calls; nil ctx correctly skips integration-type hint, equivalent to old behavior
transports/bifrost-http/integrations/anthropic.go Removes anthropicModelGetter; checkAnthropicPassthrough no longer sets skip-catalog flag, creating a regression for catalog-less deployments using anthropic/-prefixed models
transports/go.mod Adds explicit require for plugins/modelcatalogresolver; addresses the previously flagged missing require entry

Reviews (12): Last reviewed commit: "feat: add model catalog router plugin" | Re-trigger Greptile

Comment thread transports/bifrost-http/server/plugins.go
Comment thread plugins/modelcatalogresolver/main.go Outdated
Comment thread plugins/modelcatalogresolver/main.go Outdated
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_governance_routing_moved_to_prerequesthook branch from d255fc5 to 94645c5 Compare June 4, 2026 20:49
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_add_model_catalog_router_plugin branch from 15f03b5 to 05c2bc9 Compare June 4, 2026 20:49
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_governance_routing_moved_to_prerequesthook branch from 94645c5 to dd5e71c Compare June 5, 2026 09:48
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_add_model_catalog_router_plugin branch from 05c2bc9 to d3f5a32 Compare June 5, 2026 09:48
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_governance_routing_moved_to_prerequesthook branch from dd5e71c to 59a92e7 Compare June 7, 2026 07:25
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_add_model_catalog_router_plugin branch from d3f5a32 to 3010c2b Compare June 7, 2026 07:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
core/providers/bedrock/rerank.go (1)

130-130: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Optional: Consider removing unused context parameter.

The ctx *schemas.BifrostContext parameter is no longer used after removing the CheckAndSetDefaultProvider call. If this signature is not part of a shared interface or pattern, consider removing it in a follow-up cleanup.

🤖 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 `@core/providers/bedrock/rerank.go` at line 130, The method signature for
ToBifrostRerankRequest on BedrockRerankRequest still accepts an unused ctx
*schemas.BifrostContext parameter; update the signature to remove the unused
parameter (change func (req *BedrockRerankRequest) ToBifrostRerankRequest(ctx
*schemas.BifrostContext) to func (req *BedrockRerankRequest)
ToBifrostRerankRequest()) and then update all call sites to match, or if the
signature must remain for an interface, instead rename the param to _
(underscore) to mark it unused; reference the ToBifrostRerankRequest method on
BedrockRerankRequest and any callers you adjust.
core/schemas/bifrost.go (1)

498-750: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Complete the request mutators for all request envelopes.

GetRequestFields() can read File*, Batch*, Container*, and PassthroughRequest, but SetProvider() / SetModel() still ignore many of those same variants. After provider resolution moved into shared PreRequestHooks, that means a plugin can inspect these requests but fail to write the resolved provider or normalized model back, leaving later validation to reject them or forwarding prefixed models upstream. Based on learnings, RunPreRequestHooks is now the shared mutation point for request provider/model selection.

🤖 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 `@core/schemas/bifrost.go` around lines 498 - 750, SetProvider and SetModel are
incomplete: they must mirror GetRequestFields so plugins can write resolved
provider/model back. In SetProvider add cases to set Provider for all File*
(FileUploadRequest, FileListRequest, FileRetrieveRequest, FileDeleteRequest,
FileContentRequest), Batch* (BatchListRequest, BatchRetrieveRequest,
BatchCancelRequest, BatchResultsRequest, BatchDeleteRequest), Container*
(ContainerCreateRequest, ContainerListRequest, ContainerRetrieveRequest,
ContainerDeleteRequest, ContainerFileCreateRequest, ContainerFileListRequest,
ContainerFileRetrieveRequest, ContainerFileContentRequest,
ContainerFileDeleteRequest), Video* (VideoGenerationRequest,
VideoRetrieveRequest, VideoDownloadRequest, VideoListRequest,
VideoDeleteRequest, VideoRemixRequest) and PassthroughRequest. In SetModel add
matching branches to set Model (for pointer fields, preserve the existing nil
check and assign properly using new(model) or *field = model depending on the
struct: e.g., if br.FileListRequest.Model != nil { *br.FileListRequest.Model =
model } or br.FileUploadRequest.Model = model when non-pointer) so every variant
handled by GetRequestFields is writable by SetModel.
🤖 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 `@core/providers/openai/responses.go`:
- Around line 142-163: The current normalization only converts
message.Content.ContentStr to a reasoning block; update the logic in the message
normalization section (targeting message.Content and
ResponsesMessageContentBlock handling) to also normalize any existing non-empty
message.Content.ContentBlocks into blocks with Type set to
schemas.ResponsesOutputMessageContentTypeReasoning (preserving Text via
schemas.Ptr) instead of leaving original types, and drop empty block arrays by
setting message.Content = nil; also add a regression test exercising a replayed
reasoning message that arrives with ContentBlocks (not ContentStr) to assert the
blocks are retyped to ResponsesOutputMessageContentTypeReasoning and that empty
blocks become nil.

In `@core/providers/utils/utils_test.go`:
- Around line 1794-1880: Add cookie-based credential checks to both tests: in
TestExtractProviderResponseHeaders_StripsProviderSecrets and
TestExtractPassthroughProviderResponseHeaders, set cookie/set-cookie headers on
resp (e.g., resp.Header.Set("Cookie", "...") and resp.Header.Set("Set-Cookie",
"...")) and extend the secret lists checked via the lookup function to include
"cookie" and "set-cookie" alongside "authorization", "x-goog-api-key",
"x-api-key" so the assertions validate that cookie and set-cookie are stripped
by ExtractProviderResponseHeaders and ExtractPassthroughProviderResponseHeaders.
- Around line 824-971: The tests use a fixed 200ms time.After to assert
DrainNonSSEStreamReader returns promptly, which is flaky; instead implement a
deterministic handshake between the writer and the goroutine running
DrainNonSSEStreamReader: create a started chan struct{} (or similar) and have
the goroutine that calls DrainNonSSEStreamReader close(started) immediately
after launching, then have the writer goroutine wait for <-started before
writing; remove the time.After selects in
TestDrainNonSSEStreamReader_TinyOpenSSEPrefixReturnsPromptly and
TestDrainNonSSEStreamReader_FragmentedFieldPrefixReturnsPromptly and rely on the
handshake (or, if you prefer a safety net, replace 200ms with a much larger
timeout like 5s) while keeping the existing channels result, writeErr,
firstWriteErr, and suffixWriteErr logic intact.

In `@core/providers/utils/utils.go`:
- Around line 1099-1106: peekHasPrefix incorrectly treats partial buffered data
as a match (causing false SSE detection in DrainNonSSEStreamReader); update
peekHasPrefix to require the reader have at least len(prefix) bytes buffered
before peeking and only compare when full prefix length is available (i.e.,
return false if reader.Buffered() < len(prefix), otherwise peek len(prefix) and
compare), referencing the peekHasPrefix function and its usage in
DrainNonSSEStreamReader.

---

Outside diff comments:
In `@core/providers/bedrock/rerank.go`:
- Line 130: The method signature for ToBifrostRerankRequest on
BedrockRerankRequest still accepts an unused ctx *schemas.BifrostContext
parameter; update the signature to remove the unused parameter (change func (req
*BedrockRerankRequest) ToBifrostRerankRequest(ctx *schemas.BifrostContext) to
func (req *BedrockRerankRequest) ToBifrostRerankRequest()) and then update all
call sites to match, or if the signature must remain for an interface, instead
rename the param to _ (underscore) to mark it unused; reference the
ToBifrostRerankRequest method on BedrockRerankRequest and any callers you
adjust.

In `@core/schemas/bifrost.go`:
- Around line 498-750: SetProvider and SetModel are incomplete: they must mirror
GetRequestFields so plugins can write resolved provider/model back. In
SetProvider add cases to set Provider for all File* (FileUploadRequest,
FileListRequest, FileRetrieveRequest, FileDeleteRequest, FileContentRequest),
Batch* (BatchListRequest, BatchRetrieveRequest, BatchCancelRequest,
BatchResultsRequest, BatchDeleteRequest), Container* (ContainerCreateRequest,
ContainerListRequest, ContainerRetrieveRequest, ContainerDeleteRequest,
ContainerFileCreateRequest, ContainerFileListRequest,
ContainerFileRetrieveRequest, ContainerFileContentRequest,
ContainerFileDeleteRequest), Video* (VideoGenerationRequest,
VideoRetrieveRequest, VideoDownloadRequest, VideoListRequest,
VideoDeleteRequest, VideoRemixRequest) and PassthroughRequest. In SetModel add
matching branches to set Model (for pointer fields, preserve the existing nil
check and assign properly using new(model) or *field = model depending on the
struct: e.g., if br.FileListRequest.Model != nil { *br.FileListRequest.Model =
model } or br.FileUploadRequest.Model = model when non-pointer) so every variant
handled by GetRequestFields is writable by SetModel.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 98e7ca17-84e4-4bc5-83e0-deab21c07263

📥 Commits

Reviewing files that changed from the base of the PR and between da3318a and 3010c2b.

⛔ Files ignored due to path filters (1)
  • plugins/modelcatalogresolver/go.sum is excluded by !**/*.sum
📒 Files selected for processing (33)
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/text.go
  • core/providers/bedrock/invoke.go
  • core/providers/bedrock/rerank.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/text.go
  • core/providers/cohere/chat.go
  • core/providers/cohere/count_tokens.go
  • core/providers/cohere/embedding.go
  • core/providers/cohere/rerank.go
  • core/providers/gemini/embedding.go
  • core/providers/gemini/images.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/speech.go
  • core/providers/gemini/transcription.go
  • core/providers/gemini/videos.go
  • core/providers/openai/chat.go
  • core/providers/openai/embedding.go
  • core/providers/openai/images.go
  • core/providers/openai/responses.go
  • core/providers/openai/speech.go
  • core/providers/openai/text.go
  • core/providers/openai/transcription.go
  • core/providers/openai/videos.go
  • core/providers/utils/utils.go
  • core/providers/utils/utils_test.go
  • core/providers/vertex/rerank.go
  • core/schemas/bifrost.go
  • plugins/governance/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/go.mod
  • plugins/modelcatalogresolver/main.go
💤 Files with no reviewable changes (5)
  • plugins/modelcatalogresolver/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/main.go
  • plugins/governance/go.mod

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
core/providers/bedrock/rerank.go (1)

130-130: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Optional: Consider removing unused context parameter.

The ctx *schemas.BifrostContext parameter is no longer used after removing the CheckAndSetDefaultProvider call. If this signature is not part of a shared interface or pattern, consider removing it in a follow-up cleanup.

🤖 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 `@core/providers/bedrock/rerank.go` at line 130, The method signature for
ToBifrostRerankRequest on BedrockRerankRequest still accepts an unused ctx
*schemas.BifrostContext parameter; update the signature to remove the unused
parameter (change func (req *BedrockRerankRequest) ToBifrostRerankRequest(ctx
*schemas.BifrostContext) to func (req *BedrockRerankRequest)
ToBifrostRerankRequest()) and then update all call sites to match, or if the
signature must remain for an interface, instead rename the param to _
(underscore) to mark it unused; reference the ToBifrostRerankRequest method on
BedrockRerankRequest and any callers you adjust.
core/schemas/bifrost.go (1)

498-750: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Complete the request mutators for all request envelopes.

GetRequestFields() can read File*, Batch*, Container*, and PassthroughRequest, but SetProvider() / SetModel() still ignore many of those same variants. After provider resolution moved into shared PreRequestHooks, that means a plugin can inspect these requests but fail to write the resolved provider or normalized model back, leaving later validation to reject them or forwarding prefixed models upstream. Based on learnings, RunPreRequestHooks is now the shared mutation point for request provider/model selection.

🤖 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 `@core/schemas/bifrost.go` around lines 498 - 750, SetProvider and SetModel are
incomplete: they must mirror GetRequestFields so plugins can write resolved
provider/model back. In SetProvider add cases to set Provider for all File*
(FileUploadRequest, FileListRequest, FileRetrieveRequest, FileDeleteRequest,
FileContentRequest), Batch* (BatchListRequest, BatchRetrieveRequest,
BatchCancelRequest, BatchResultsRequest, BatchDeleteRequest), Container*
(ContainerCreateRequest, ContainerListRequest, ContainerRetrieveRequest,
ContainerDeleteRequest, ContainerFileCreateRequest, ContainerFileListRequest,
ContainerFileRetrieveRequest, ContainerFileContentRequest,
ContainerFileDeleteRequest), Video* (VideoGenerationRequest,
VideoRetrieveRequest, VideoDownloadRequest, VideoListRequest,
VideoDeleteRequest, VideoRemixRequest) and PassthroughRequest. In SetModel add
matching branches to set Model (for pointer fields, preserve the existing nil
check and assign properly using new(model) or *field = model depending on the
struct: e.g., if br.FileListRequest.Model != nil { *br.FileListRequest.Model =
model } or br.FileUploadRequest.Model = model when non-pointer) so every variant
handled by GetRequestFields is writable by SetModel.
🤖 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 `@core/providers/openai/responses.go`:
- Around line 142-163: The current normalization only converts
message.Content.ContentStr to a reasoning block; update the logic in the message
normalization section (targeting message.Content and
ResponsesMessageContentBlock handling) to also normalize any existing non-empty
message.Content.ContentBlocks into blocks with Type set to
schemas.ResponsesOutputMessageContentTypeReasoning (preserving Text via
schemas.Ptr) instead of leaving original types, and drop empty block arrays by
setting message.Content = nil; also add a regression test exercising a replayed
reasoning message that arrives with ContentBlocks (not ContentStr) to assert the
blocks are retyped to ResponsesOutputMessageContentTypeReasoning and that empty
blocks become nil.

In `@core/providers/utils/utils_test.go`:
- Around line 1794-1880: Add cookie-based credential checks to both tests: in
TestExtractProviderResponseHeaders_StripsProviderSecrets and
TestExtractPassthroughProviderResponseHeaders, set cookie/set-cookie headers on
resp (e.g., resp.Header.Set("Cookie", "...") and resp.Header.Set("Set-Cookie",
"...")) and extend the secret lists checked via the lookup function to include
"cookie" and "set-cookie" alongside "authorization", "x-goog-api-key",
"x-api-key" so the assertions validate that cookie and set-cookie are stripped
by ExtractProviderResponseHeaders and ExtractPassthroughProviderResponseHeaders.
- Around line 824-971: The tests use a fixed 200ms time.After to assert
DrainNonSSEStreamReader returns promptly, which is flaky; instead implement a
deterministic handshake between the writer and the goroutine running
DrainNonSSEStreamReader: create a started chan struct{} (or similar) and have
the goroutine that calls DrainNonSSEStreamReader close(started) immediately
after launching, then have the writer goroutine wait for <-started before
writing; remove the time.After selects in
TestDrainNonSSEStreamReader_TinyOpenSSEPrefixReturnsPromptly and
TestDrainNonSSEStreamReader_FragmentedFieldPrefixReturnsPromptly and rely on the
handshake (or, if you prefer a safety net, replace 200ms with a much larger
timeout like 5s) while keeping the existing channels result, writeErr,
firstWriteErr, and suffixWriteErr logic intact.

In `@core/providers/utils/utils.go`:
- Around line 1099-1106: peekHasPrefix incorrectly treats partial buffered data
as a match (causing false SSE detection in DrainNonSSEStreamReader); update
peekHasPrefix to require the reader have at least len(prefix) bytes buffered
before peeking and only compare when full prefix length is available (i.e.,
return false if reader.Buffered() < len(prefix), otherwise peek len(prefix) and
compare), referencing the peekHasPrefix function and its usage in
DrainNonSSEStreamReader.

---

Outside diff comments:
In `@core/providers/bedrock/rerank.go`:
- Line 130: The method signature for ToBifrostRerankRequest on
BedrockRerankRequest still accepts an unused ctx *schemas.BifrostContext
parameter; update the signature to remove the unused parameter (change func (req
*BedrockRerankRequest) ToBifrostRerankRequest(ctx *schemas.BifrostContext) to
func (req *BedrockRerankRequest) ToBifrostRerankRequest()) and then update all
call sites to match, or if the signature must remain for an interface, instead
rename the param to _ (underscore) to mark it unused; reference the
ToBifrostRerankRequest method on BedrockRerankRequest and any callers you
adjust.

In `@core/schemas/bifrost.go`:
- Around line 498-750: SetProvider and SetModel are incomplete: they must mirror
GetRequestFields so plugins can write resolved provider/model back. In
SetProvider add cases to set Provider for all File* (FileUploadRequest,
FileListRequest, FileRetrieveRequest, FileDeleteRequest, FileContentRequest),
Batch* (BatchListRequest, BatchRetrieveRequest, BatchCancelRequest,
BatchResultsRequest, BatchDeleteRequest), Container* (ContainerCreateRequest,
ContainerListRequest, ContainerRetrieveRequest, ContainerDeleteRequest,
ContainerFileCreateRequest, ContainerFileListRequest,
ContainerFileRetrieveRequest, ContainerFileContentRequest,
ContainerFileDeleteRequest), Video* (VideoGenerationRequest,
VideoRetrieveRequest, VideoDownloadRequest, VideoListRequest,
VideoDeleteRequest, VideoRemixRequest) and PassthroughRequest. In SetModel add
matching branches to set Model (for pointer fields, preserve the existing nil
check and assign properly using new(model) or *field = model depending on the
struct: e.g., if br.FileListRequest.Model != nil { *br.FileListRequest.Model =
model } or br.FileUploadRequest.Model = model when non-pointer) so every variant
handled by GetRequestFields is writable by SetModel.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 98e7ca17-84e4-4bc5-83e0-deab21c07263

📥 Commits

Reviewing files that changed from the base of the PR and between da3318a and 3010c2b.

⛔ Files ignored due to path filters (1)
  • plugins/modelcatalogresolver/go.sum is excluded by !**/*.sum
📒 Files selected for processing (33)
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/text.go
  • core/providers/bedrock/invoke.go
  • core/providers/bedrock/rerank.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/text.go
  • core/providers/cohere/chat.go
  • core/providers/cohere/count_tokens.go
  • core/providers/cohere/embedding.go
  • core/providers/cohere/rerank.go
  • core/providers/gemini/embedding.go
  • core/providers/gemini/images.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/speech.go
  • core/providers/gemini/transcription.go
  • core/providers/gemini/videos.go
  • core/providers/openai/chat.go
  • core/providers/openai/embedding.go
  • core/providers/openai/images.go
  • core/providers/openai/responses.go
  • core/providers/openai/speech.go
  • core/providers/openai/text.go
  • core/providers/openai/transcription.go
  • core/providers/openai/videos.go
  • core/providers/utils/utils.go
  • core/providers/utils/utils_test.go
  • core/providers/vertex/rerank.go
  • core/schemas/bifrost.go
  • plugins/governance/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/go.mod
  • plugins/modelcatalogresolver/main.go
💤 Files with no reviewable changes (5)
  • plugins/modelcatalogresolver/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/main.go
  • plugins/governance/go.mod
🛑 Comments failed to post (4)
core/providers/openai/responses.go (1)

142-163: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize existing reasoning blocks, not just string content.

Lines 147-163 only rewrite ContentStr. A replayed reasoning item that already carries ContentBlocks will still be forwarded with whatever block types it had before, but OpenAI expects reasoning content to be encoded as reasoning blocks. That means round-tripped reasoning messages can still 400 even after this normalization. Please normalize non-empty ContentBlocks here as well, and add a regression test for that replay path. Based on learnings, "if ResponsesReasoning != nil and the response contains content blocks, all content blocks should be treated as reasoning blocks by default."

🤖 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 `@core/providers/openai/responses.go` around lines 142 - 163, The current
normalization only converts message.Content.ContentStr to a reasoning block;
update the logic in the message normalization section (targeting message.Content
and ResponsesMessageContentBlock handling) to also normalize any existing
non-empty message.Content.ContentBlocks into blocks with Type set to
schemas.ResponsesOutputMessageContentTypeReasoning (preserving Text via
schemas.Ptr) instead of leaving original types, and drop empty block arrays by
setting message.Content = nil; also add a regression test exercising a replayed
reasoning message that arrives with ContentBlocks (not ContentStr) to assert the
blocks are retyped to ResponsesOutputMessageContentTypeReasoning and that empty
blocks become nil.

Source: Learnings

core/providers/utils/utils_test.go (2)

824-971: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid wall-clock 200ms deadlines in these stream promptness tests.

Both cases fail based on scheduler speed rather than function semantics. Under loaded CI or -race, the pipe writer / goroutine handoff can exceed 200ms even when the implementation is correct, which makes this suite flaky. Prefer a deterministic handshake or a materially looser timeout.

🤖 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 `@core/providers/utils/utils_test.go` around lines 824 - 971, The tests use a
fixed 200ms time.After to assert DrainNonSSEStreamReader returns promptly, which
is flaky; instead implement a deterministic handshake between the writer and the
goroutine running DrainNonSSEStreamReader: create a started chan struct{} (or
similar) and have the goroutine that calls DrainNonSSEStreamReader
close(started) immediately after launching, then have the writer goroutine wait
for <-started before writing; remove the time.After selects in
TestDrainNonSSEStreamReader_TinyOpenSSEPrefixReturnsPromptly and
TestDrainNonSSEStreamReader_FragmentedFieldPrefixReturnsPromptly and rely on the
handshake (or, if you prefer a safety net, replace 200ms with a much larger
timeout like 5s) while keeping the existing channels result, writeErr,
firstWriteErr, and suffixWriteErr logic intact.

1794-1880: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Extend the secret-header regressions to cookie and set-cookie.

These new tests only cover API-key / Authorization branches, but the filter contract here also strips cookie-based credentials. Without those assertions, a future regression in that path will still pass this security suite. Based on learnings, providerResponseFilterHeaders must exclude credentials-bearing headers including authorization, cookie, and set-cookie.

🤖 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 `@core/providers/utils/utils_test.go` around lines 1794 - 1880, Add
cookie-based credential checks to both tests: in
TestExtractProviderResponseHeaders_StripsProviderSecrets and
TestExtractPassthroughProviderResponseHeaders, set cookie/set-cookie headers on
resp (e.g., resp.Header.Set("Cookie", "...") and resp.Header.Set("Set-Cookie",
"...")) and extend the secret lists checked via the lookup function to include
"cookie" and "set-cookie" alongside "authorization", "x-goog-api-key",
"x-api-key" so the assertions validate that cookie and set-cookie are stripped
by ExtractProviderResponseHeaders and ExtractPassthroughProviderResponseHeaders.

Source: Learnings

core/providers/utils/utils.go (1)

1099-1106: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid partial-prefix SSE detection false positives.

At Line 1100, peekHasPrefix treats partial buffered bytes as a valid match (e.g., just "d" matching "data:"). That can misclassify non-SSE payloads as SSE and skip draining in DrainNonSSEStreamReader.

Suggested fix
func peekHasPrefix(reader *bufio.Reader, prefix []byte) bool {
-	n := min(reader.Buffered(), len(prefix))
-	if n == 0 {
-		return false
-	}
-	peeked, err := reader.Peek(n)
-	return err == nil && bytes.Equal(peeked, prefix[:n])
+	peeked, err := reader.Peek(len(prefix))
+	if err != nil {
+		return false
+	}
+	return bytes.Equal(peeked, prefix)
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

func peekHasPrefix(reader *bufio.Reader, prefix []byte) bool {
	peeked, err := reader.Peek(len(prefix))
	if err != nil {
		return false
	}
	return bytes.Equal(peeked, prefix)
}
🤖 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 `@core/providers/utils/utils.go` around lines 1099 - 1106, peekHasPrefix
incorrectly treats partial buffered data as a match (causing false SSE detection
in DrainNonSSEStreamReader); update peekHasPrefix to require the reader have at
least len(prefix) bytes buffered before peeking and only compare when full
prefix length is available (i.e., return false if reader.Buffered() <
len(prefix), otherwise peek len(prefix) and compare), referencing the
peekHasPrefix function and its usage in DrainNonSSEStreamReader.

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_add_model_catalog_router_plugin branch from 3010c2b to 5ec0e17 Compare June 8, 2026 06:54
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_governance_routing_moved_to_prerequesthook branch from 59a92e7 to 21ae88f Compare June 8, 2026 06:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@core/providers/utils/utils.go`:
- Around line 270-316: Add unit/integration tests around the
DNS-resolution-and-dial loop that exercise the net.SplitHostPort ->
net.DefaultResolver.LookupIP -> dialing logic: verify behavior when LookupIP
returns an empty list (ensure the "no usable address resolved for %s" branch is
hit), when all resolved IPs are rejected by the filters (ensure lastErr is
returned when present), mixed IPv4/IPv6 responses, and the private-IP filtering
when allowPrivateNetwork is false vs true; target the code paths around the
resolver/dial loop (references: net.SplitHostPort, net.DefaultResolver.LookupIP,
allowPrivateNetwork, network.IsPrivateIP, network.IsLinkLocal, lastErr, and the
dial loop) and use mocked DNS resolver and net.Dialer or test hooks to simulate
each scenario.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 401ca876-797a-42a6-8c67-54fb179fa727

📥 Commits

Reviewing files that changed from the base of the PR and between 3010c2b and 5ec0e17.

⛔ Files ignored due to path filters (1)
  • plugins/modelcatalogresolver/go.sum is excluded by !**/*.sum
📒 Files selected for processing (33)
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/text.go
  • core/providers/bedrock/invoke.go
  • core/providers/bedrock/rerank.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/text.go
  • core/providers/cohere/chat.go
  • core/providers/cohere/count_tokens.go
  • core/providers/cohere/embedding.go
  • core/providers/cohere/rerank.go
  • core/providers/gemini/embedding.go
  • core/providers/gemini/images.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/speech.go
  • core/providers/gemini/transcription.go
  • core/providers/gemini/videos.go
  • core/providers/openai/chat.go
  • core/providers/openai/embedding.go
  • core/providers/openai/images.go
  • core/providers/openai/responses.go
  • core/providers/openai/speech.go
  • core/providers/openai/text.go
  • core/providers/openai/transcription.go
  • core/providers/openai/videos.go
  • core/providers/utils/utils.go
  • core/providers/utils/utils_test.go
  • core/providers/vertex/rerank.go
  • core/schemas/bifrost.go
  • plugins/governance/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/go.mod
  • plugins/modelcatalogresolver/main.go
💤 Files with no reviewable changes (5)
  • plugins/modelcatalogresolver/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/main.go
  • plugins/governance/go.mod

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 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 `@core/providers/utils/utils.go`:
- Around line 270-316: Add unit/integration tests around the
DNS-resolution-and-dial loop that exercise the net.SplitHostPort ->
net.DefaultResolver.LookupIP -> dialing logic: verify behavior when LookupIP
returns an empty list (ensure the "no usable address resolved for %s" branch is
hit), when all resolved IPs are rejected by the filters (ensure lastErr is
returned when present), mixed IPv4/IPv6 responses, and the private-IP filtering
when allowPrivateNetwork is false vs true; target the code paths around the
resolver/dial loop (references: net.SplitHostPort, net.DefaultResolver.LookupIP,
allowPrivateNetwork, network.IsPrivateIP, network.IsLinkLocal, lastErr, and the
dial loop) and use mocked DNS resolver and net.Dialer or test hooks to simulate
each scenario.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 401ca876-797a-42a6-8c67-54fb179fa727

📥 Commits

Reviewing files that changed from the base of the PR and between 3010c2b and 5ec0e17.

⛔ Files ignored due to path filters (1)
  • plugins/modelcatalogresolver/go.sum is excluded by !**/*.sum
📒 Files selected for processing (33)
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/text.go
  • core/providers/bedrock/invoke.go
  • core/providers/bedrock/rerank.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/text.go
  • core/providers/cohere/chat.go
  • core/providers/cohere/count_tokens.go
  • core/providers/cohere/embedding.go
  • core/providers/cohere/rerank.go
  • core/providers/gemini/embedding.go
  • core/providers/gemini/images.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/speech.go
  • core/providers/gemini/transcription.go
  • core/providers/gemini/videos.go
  • core/providers/openai/chat.go
  • core/providers/openai/embedding.go
  • core/providers/openai/images.go
  • core/providers/openai/responses.go
  • core/providers/openai/speech.go
  • core/providers/openai/text.go
  • core/providers/openai/transcription.go
  • core/providers/openai/videos.go
  • core/providers/utils/utils.go
  • core/providers/utils/utils_test.go
  • core/providers/vertex/rerank.go
  • core/schemas/bifrost.go
  • plugins/governance/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/go.mod
  • plugins/modelcatalogresolver/main.go
💤 Files with no reviewable changes (5)
  • plugins/modelcatalogresolver/go.mod
  • plugins/governance/httptransportprehook_test.go
  • plugins/governance/main.go
  • plugins/modelcatalogresolver/main.go
  • plugins/governance/go.mod
🛑 Comments failed to post (1)
core/providers/utils/utils.go (1)

270-316: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Good SSRF protection via DNS resolution and IP filtering.

The manual DNS resolution with IP filtering (unspecified, link-local, private) before dialing closes the DNS rebinding window between URL validation and connection. The logic correctly:

  • Rejects dangerous IP classes before attempting connection
  • Tries each resolved IP sequentially with proper error tracking
  • Preserves loopback for local testing

Recommend verifying test coverage for edge cases:

  • Empty IP list from DNS (line 315 path)
  • All IPs rejected by filters (would return lastErr from line 313)
  • Mixed IPv4/IPv6 responses
  • Private IP filtering when allowPrivateNetwork=false vs true
🤖 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 `@core/providers/utils/utils.go` around lines 270 - 316, Add unit/integration
tests around the DNS-resolution-and-dial loop that exercise the
net.SplitHostPort -> net.DefaultResolver.LookupIP -> dialing logic: verify
behavior when LookupIP returns an empty list (ensure the "no usable address
resolved for %s" branch is hit), when all resolved IPs are rejected by the
filters (ensure lastErr is returned when present), mixed IPv4/IPv6 responses,
and the private-IP filtering when allowPrivateNetwork is false vs true; target
the code paths around the resolver/dial loop (references: net.SplitHostPort,
net.DefaultResolver.LookupIP, allowPrivateNetwork, network.IsPrivateIP,
network.IsLinkLocal, lastErr, and the dial loop) and use mocked DNS resolver and
net.Dialer or test hooks to simulate each scenario.

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_governance_routing_moved_to_prerequesthook branch from 21ae88f to 4b9952a Compare June 8, 2026 11:55
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_add_model_catalog_router_plugin branch from 5ec0e17 to 13daf7a Compare June 8, 2026 11:55
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_governance_routing_moved_to_prerequesthook branch from 4b9952a to 29d2b9f Compare June 8, 2026 12:24
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-01-feat_add_model_catalog_router_plugin branch from 13daf7a to 24abc35 Compare June 8, 2026 12:24
@Madhuvod
Madhuvod force-pushed the 06-01-feat_governance_routing_moved_to_prerequesthook branch from 29d2b9f to 4b9952a Compare June 8, 2026 12:25
@Madhuvod
Madhuvod force-pushed the 06-01-feat_add_model_catalog_router_plugin branch from 24abc35 to 13daf7a Compare June 8, 2026 12:25

akshaydeo commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jun 9, 5:17 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 9, 5:19 AM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo changed the base branch from 06-01-feat_governance_routing_moved_to_prerequesthook to graphite-base/3934 June 9, 2026 05:18
@akshaydeo
akshaydeo changed the base branch from graphite-base/3934 to dev June 9, 2026 05:18
@akshaydeo
akshaydeo merged commit 122fd81 into dev Jun 9, 2026
9 of 10 checks passed
@akshaydeo
akshaydeo deleted the 06-01-feat_add_model_catalog_router_plugin branch June 9, 2026 05:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants