Skip to content

fix: unify model catalog store/helpers - #5640

Open
TejasGhatte wants to merge 1 commit into
07-27-adds_model_list_caching_adds_new_cache_from
07-29-fix_unify_model_catalog_store_helpers
Open

TejasGhatte wants to merge 1 commit into
07-27-adds_model_list_caching_adds_new_cache_from
07-29-fix_unify_model_catalog_store_helpers

Conversation

@TejasGhatte

@TejasGhatte TejasGhatte commented Jul 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

ListModelsCatalog and ModelInfoProvider were two separate interfaces serving overlapping concerns — one for list-models caching/reconciliation, the other for plugin-facing model lookups. This PR merges them into a single ModelCatalog interface, removes the intermediate liveModelsCache adapter, and makes *modelcatalog.ModelCatalog implement the unified interface directly.

Changes

  • schemas.ListModelsCatalog and schemas.ModelInfoProvider are replaced by a single schemas.ModelCatalog interface that covers CachedModels, RoutableModels, GetModelInfo, and CalculateRequestCost
  • BifrostConfig.ListModelsCatalog is renamed to BifrostConfig.ModelCatalog
  • Bifrost.SetListModelsCatalog / HasListModelsCatalog are renamed to SetModelCatalog / HasModelCatalog; the separate SetModelCatalog(ModelInfoProvider) overload is removed
  • The liveModelsCache adapter struct in the HTTP server is deleted; *modelcatalog.ModelCatalog now satisfies schemas.ModelCatalog directly via new CachedModels and RoutableModels methods on the type
  • GetModelInfo now composes live store data with the datasheet: it starts from what the provider most recently reported, then lets the datasheet fill gaps, so models the datasheet has no row for are no longer unknown to plugins
  • live.Store.FindModel is added to support the live-first lookup in GetModelInfo
  • schemas.Model.Clone() and schemas.Model.HasMetadata() are promoted to methods on the struct; hasModelMetadata in the HTTP handler and the modelCatalogHolder wrapper type are removed
  • BifrostConfig.ModelCatalog is now passed directly into Init, so the plugin-facing catalog and the list-models catalog are installed in one step rather than two separate calls at boot
  • ptr[T] helper in modelinfo.go is replaced with the built-in new expression

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 ./core/... ./framework/modelcatalog/... ./transports/bifrost-http/...

Existing tests have been updated to use fakeModelCatalog (which now implements all four methods) and the renamed API surface. New tests in modelinfo_test.go cover the live-first lookup, key-scope independence, provider-prefix matching, and caller ownership of returned values.

Breaking changes

  • Yes
  • No

BifrostConfig.ListModelsCatalog → BifrostConfig.ModelCatalog. Any caller setting ListModelsCatalog must rename the field. Any type implementing schemas.ListModelsCatalog must add GetModelInfo and CalculateRequestCost to satisfy schemas.ModelCatalog, or switch to *modelcatalog.ModelCatalog directly. Bifrost.SetListModelsCatalog and HasListModelsCatalog are renamed; callers must update to SetModelCatalog and HasModelCatalog.

Related issues

Security considerations

None. No auth paths, secrets, or PII handling changed.

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

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Unified model directory support for /v1/models, including cached and routable model reconciliation, pricing, and metadata lookups.
    • Added deep-copying and metadata detection for model details.
    • Improved provider-prefixed model ID matching and live metadata enrichment.
  • Bug Fixes
    • Improved list-models fallback, disabled-key handling, and no-directory behavior.
    • Responses now omit models without metadata.
  • API Updates
    • Replaced separate catalog configurations with a single model directory interface.

Walkthrough

The PR replaces separate catalog and list-models state with a unified ModelDirectory, adds deep model cloning and metadata detection, updates live metadata lookup, and rewires core, transport, and HTTP server paths to use the shared directory.

Changes

Unified model directory

Layer / File(s) Summary
Directory contracts and model metadata
core/schemas/..., transports/bifrost-http/handlers/...
ModelDirectory combines metadata, cost, cached-model, and routable-model operations. Model.DeepCopy() and Model.HasMetadata() centralize copying and metadata checks.
Live model metadata lookup
framework/modelcatalog/...
Live entries are found across key scopes, merged with datasheet metadata, cloned for callers, and exposed through directory methods.
Core directory state and list-models flow
core/bifrost.go, core/*listmodels*test.go, core/modelcataloghooks_test.go
Atomic directory state replaces separate catalog pointers. Cache lookup, fallback, reconciliation, context propagation, and tests use the new API.
HTTP server directory wiring
transports/bifrost-http/server/..., transports/bifrost-http/handlers/middlewares.go
Bootstrap and cache synchronization install or clear the directory, while transport contexts and interface tests use ModelDirectory.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: pratham-mishra04, akshaydeo, roroghost17

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 80.56% which is sufficient. The required threshold is 80.00%.
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.
Title check ✅ Passed The title clearly identifies the main change: unifying model catalog storage and helpers.
Description check ✅ Passed The description covers the purpose, changes, testing, affected areas, breaking changes, security, and checklist sections.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 07-29-fix_unify_model_catalog_store_helpers

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

@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.


tejas ghatte seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

TejasGhatte commented Jul 29, 2026 •

Copy link
Copy Markdown
Collaborator Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@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/schemas/models.go`:
- Around line 194-235: Update Model.Clone so Pricing, TopProvider,
PerRequestLimits, and DefaultParameters are deep-cloned rather than copied with
clonePtr. For each non-nil nested struct, copy the struct and independently
clone its pointer fields, matching the explicit Architecture and Reasoning
handling, while preserving nil values and preventing shared-cache mutations.
🪄 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: 6a21d078-583a-4feb-9de8-704ccad105e9

📥 Commits

Reviewing files that changed from the base of the PR and between 050c40b and 1c9092e.

📒 Files selected for processing (18)
  • core/bifrost.go
  • core/listmodelscache_test.go
  • core/listmodelsdisabledkey_test.go
  • core/listmodelsidshape_test.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/modelcatalog.go
  • core/schemas/modelcatalog_test.go
  • core/schemas/models.go
  • framework/modelcatalog/bench_routable_test.go
  • framework/modelcatalog/live/store.go
  • framework/modelcatalog/modelinfo.go
  • framework/modelcatalog/modelinfo_test.go
  • framework/modelcatalog/pool.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/listmodelsmetadata_test.go
  • transports/bifrost-http/server/server.go
  • transports/bifrost-http/server/server_test.go
💤 Files with no reviewable changes (1)
  • core/schemas/modelcatalog.go

Comment thread core/schemas/models.go Outdated
@TejasGhatte
TejasGhatte force-pushed the 07-29-fix_unify_model_catalog_store_helpers branch from 1c9092e to 68a0d55 Compare July 29, 2026 05:06

@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

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

⚠️ Outside diff range comments (1)
transports/bifrost-http/server/server.go (1)

2347-2359: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Avoid installing a typed-nil model directory.

Line 2358 converts a nil *modelcatalog.ModelCatalog into a non-nil schemas.ModelDirectory. Core then considers the directory installed and later calls it instead of taking the intended no-catalog path. This contradicts the nil handling in syncListModelsCache.

Proposed fix
+var modelDirectory schemas.ModelDirectory
+if s.Config.ModelCatalog != nil {
+    modelDirectory = s.Config.ModelCatalog
+}
 s.Client, err = bifrost.Init(ctx, schemas.BifrostConfig{
     ...
-    ModelDirectory: s.Config.ModelCatalog,
+    ModelDirectory: modelDirectory,
 })
🤖 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 `@transports/bifrost-http/server/server.go` around lines 2347 - 2359, Update
the client initialization around bifrost.Init so a nil
*modelcatalog.ModelCatalog is not converted into and passed as a typed-nil
schemas.ModelDirectory. Preserve a genuinely nil ModelDirectory when
s.Config.ModelCatalog is nil, matching the nil handling used by syncListModels,
while still passing the configured catalog when present.
🤖 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.

Outside diff comments:
In `@transports/bifrost-http/server/server.go`:
- Around line 2347-2359: Update the client initialization around bifrost.Init so
a nil *modelcatalog.ModelCatalog is not converted into and passed as a typed-nil
schemas.ModelDirectory. Preserve a genuinely nil ModelDirectory when
s.Config.ModelCatalog is nil, matching the nil handling used by syncListModels,
while still passing the configured catalog when present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e422d3e-248e-4785-9354-f2996e0f0a0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1c9092e and 68a0d55.

📒 Files selected for processing (19)
  • core/bifrost.go
  • core/listmodelscache_test.go
  • core/listmodelsdisabledkey_test.go
  • core/listmodelsidshape_test.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/modelcatalog.go
  • core/schemas/modeldirectory_test.go
  • core/schemas/models.go
  • framework/modelcatalog/bench_routable_test.go
  • framework/modelcatalog/live/store.go
  • framework/modelcatalog/modelinfo.go
  • framework/modelcatalog/modelinfo_test.go
  • framework/modelcatalog/pool.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/listmodelsmetadata_test.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/server/server.go
  • transports/bifrost-http/server/server_test.go
💤 Files with no reviewable changes (1)
  • core/schemas/modelcatalog.go
🚧 Files skipped from review as they are similar to previous changes (9)
  • core/listmodelsidshape_test.go
  • framework/modelcatalog/live/store.go
  • transports/bifrost-http/handlers/listmodelsmetadata_test.go
  • core/schemas/models.go
  • framework/modelcatalog/modelinfo.go
  • core/listmodelsdisabledkey_test.go
  • framework/modelcatalog/modelinfo_test.go
  • framework/modelcatalog/pool.go
  • transports/bifrost-http/handlers/inference.go

@TejasGhatte
TejasGhatte force-pushed the 07-29-fix_unify_model_catalog_store_helpers branch from 68a0d55 to c8e84fb Compare July 29, 2026 06:22

@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.

🧹 Nitpick comments (1)
core/schemas/models.go (1)

185-283: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Deep-clone implementation correctly fixes the previously-flagged aliasing gap. Pricing, TopProvider, PerRequestLimits, and DefaultParameters now each get their own DeepCopy() that clones their pointer fields, resolving the earlier concern that clonePtr left nested structs aliased.

Optional: the repeated if x != nil { out.X = new(*x) } pattern appears ~30 times across Model.DeepCopy and the six nested DeepCopy methods (this block plus lines 292-311, 323-423, 435-453). A small generic helper would cut the boilerplate without changing behavior.

♻️ Optional generic helper to reduce duplication
// clonePtr returns a copy of p that shares nothing with it, or nil for a nil p.
func clonePtr[T any](p *T) *T {
	if p == nil {
		return nil
	}
	v := *p
	return &v
}
-	if m.CanonicalSlug != nil {
-		out.CanonicalSlug = new(*m.CanonicalSlug)
-	}
-	if m.Name != nil {
-		out.Name = new(*m.Name)
-	}
+	out.CanonicalSlug = clonePtr(m.CanonicalSlug)
+	out.Name = clonePtr(m.Name)
🤖 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/models.go` around lines 185 - 283, Optionally reduce the
repeated pointer-copy boilerplate across Model.DeepCopy and the six nested
DeepCopy methods by adding and reusing a generic clonePtr helper. Replace each
nil-check plus new(*field) pattern with the helper while preserving nil values
and independent pointees; leave the existing slice, map, and nested DeepCopy
behavior unchanged.
🤖 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 `@core/schemas/models.go`:
- Around line 185-283: Optionally reduce the repeated pointer-copy boilerplate
across Model.DeepCopy and the six nested DeepCopy methods by adding and reusing
a generic clonePtr helper. Replace each nil-check plus new(*field) pattern with
the helper while preserving nil values and independent pointees; leave the
existing slice, map, and nested DeepCopy behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a996b289-40ad-4ed4-b935-d13d805d7604

📥 Commits

Reviewing files that changed from the base of the PR and between 68a0d55 and c8e84fb.

📒 Files selected for processing (20)
  • core/bifrost.go
  • core/listmodelscache_test.go
  • core/listmodelsdisabledkey_test.go
  • core/listmodelsidshape_test.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/modelcatalog.go
  • core/schemas/modeldirectory_test.go
  • core/schemas/models.go
  • core/schemas/models_test.go
  • framework/modelcatalog/bench_routable_test.go
  • framework/modelcatalog/live/store.go
  • framework/modelcatalog/modelinfo.go
  • framework/modelcatalog/modelinfo_test.go
  • framework/modelcatalog/pool.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/listmodelsmetadata_test.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/server/server.go
  • transports/bifrost-http/server/server_test.go
💤 Files with no reviewable changes (1)
  • core/schemas/modelcatalog.go
🚧 Files skipped from review as they are similar to previous changes (15)
  • transports/bifrost-http/handlers/listmodelsmetadata_test.go
  • framework/modelcatalog/bench_routable_test.go
  • transports/bifrost-http/handlers/middlewares.go
  • framework/modelcatalog/live/store.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • framework/modelcatalog/modelinfo_test.go
  • core/schemas/modeldirectory_test.go
  • core/listmodelsdisabledkey_test.go
  • transports/bifrost-http/server/server_test.go
  • framework/modelcatalog/modelinfo.go
  • transports/bifrost-http/handlers/inference.go
  • core/listmodelscache_test.go
  • transports/bifrost-http/server/server.go
  • core/bifrost.go

@TejasGhatte
TejasGhatte changed the base branch from 07-28-adds_calculatecost_and_getmodelconfig_for_ctx_in_plugins to graphite-base/5640 July 31, 2026 10:32
@TejasGhatte
TejasGhatte force-pushed the 07-29-fix_unify_model_catalog_store_helpers branch from c8e84fb to 687c327 Compare July 31, 2026 10:33
@TejasGhatte
TejasGhatte changed the base branch from graphite-base/5640 to 07-27-adds_model_list_caching_adds_new_cache_ July 31, 2026 10:33

@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

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

⚠️ Outside diff range comments (1)
transports/bifrost-http/server/server.go (1)

2343-2359: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Pass a nil-safe ModelDirectory to bifrost.Init.

When Config.ModelCatalog is nil, assigning it to schemas.ModelDirectory creates a typed-nil interface. SetModelDirectory then installs a state, so HasModelDirectory() reports true and request contexts can receive the typed nil. The catalog methods are nil-receiver-safe, and ConnectConfiguredMCPClients does not directly access the directory, but the state still violates the nil-removal contract. Assign ModelDirectory only when s.Config.ModelCatalog != nil.

🤖 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 `@transports/bifrost-http/server/server.go` around lines 2343 - 2359, The
bifrost initialization currently passes a typed-nil ModelDirectory when
s.Config.ModelCatalog is nil. Update the configuration construction around
bifrost.Init so ModelDirectory is assigned only when s.Config.ModelCatalog is
non-nil, preserving a truly nil value otherwise and the existing catalog
behavior when configured.
🧹 Nitpick comments (1)
core/schemas/bifrost.go (1)

429-429: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Update the stale field reference in this comment.

This comment still says the key bypasses BifrostConfig.ListModelsCatalog. That field is renamed to ModelDirectory (with ServeListModelsFromCatalog controlling cache serving) elsewhere in this same file. Update the comment text so it does not point to a config field that no longer exists.

📝 Proposed fix
-	BifrostContextKeySkipListModelsCache                 BifrostContextKey = "bifrost-skip-list-models-cache"             // bool - bypass BifrostConfig.ListModelsCatalog and fetch from the provider. Set by the catalog refresher, which would otherwise read the cache it is about to replace, and by callers explicitly asking for a live pull.
+	BifrostContextKeySkipListModelsCache                 BifrostContextKey = "bifrost-skip-list-models-cache"             // bool - bypass BifrostConfig.ModelDirectory's cached serving and fetch from the provider. Set by the catalog refresher, which would otherwise read the cache it is about to replace, and by callers explicitly asking for a live pull.
🤖 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` at line 429, Update the comment for
BifrostContextKeySkipListModelsCache to replace the stale
BifrostConfig.ListModelsCatalog reference with the current ModelDirectory and
ServeListModelsFromCatalog terminology, while preserving the existing
explanation of bypassing the cache for live provider pulls.
🤖 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.

Outside diff comments:
In `@transports/bifrost-http/server/server.go`:
- Around line 2343-2359: The bifrost initialization currently passes a typed-nil
ModelDirectory when s.Config.ModelCatalog is nil. Update the configuration
construction around bifrost.Init so ModelDirectory is assigned only when
s.Config.ModelCatalog is non-nil, preserving a truly nil value otherwise and the
existing catalog behavior when configured.

---

Nitpick comments:
In `@core/schemas/bifrost.go`:
- Line 429: Update the comment for BifrostContextKeySkipListModelsCache to
replace the stale BifrostConfig.ListModelsCatalog reference with the current
ModelDirectory and ServeListModelsFromCatalog terminology, while preserving the
existing explanation of bypassing the cache for live provider pulls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d1d43afe-748a-484c-a6b0-88ddd9cd2c48

📥 Commits

Reviewing files that changed from the base of the PR and between c8e84fb and 687c327.

📒 Files selected for processing (20)
  • core/bifrost.go
  • core/listmodelscache_test.go
  • core/listmodelsdisabledkey_test.go
  • core/listmodelsidshape_test.go
  • core/modelcataloghooks_test.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/modeldirectory_test.go
  • core/schemas/models.go
  • core/schemas/models_test.go
  • framework/modelcatalog/bench_routable_test.go
  • framework/modelcatalog/live/store.go
  • framework/modelcatalog/modelinfo.go
  • framework/modelcatalog/modelinfo_test.go
  • framework/modelcatalog/pool.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/listmodelsmetadata_test.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/server/server.go
  • transports/bifrost-http/server/server_test.go
🚧 Files skipped from review as they are similar to previous changes (15)
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/middlewares.go
  • framework/modelcatalog/bench_routable_test.go
  • core/schemas/models_test.go
  • framework/modelcatalog/live/store.go
  • core/schemas/context.go
  • core/listmodelsidshape_test.go
  • core/listmodelsdisabledkey_test.go
  • transports/bifrost-http/handlers/listmodelsmetadata_test.go
  • transports/bifrost-http/server/server_test.go
  • core/schemas/modeldirectory_test.go
  • core/schemas/models.go
  • framework/modelcatalog/pool.go
  • core/listmodelscache_test.go
  • core/bifrost.go

This branch has not been deployed

No deployments
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.

2 participants