Skip to content

adds sync support from local files for airgapped deployments - #4574

Merged
akshaydeo merged 1 commit into
devfrom
06-20-adds_sync_support_from_local_files_for_airgapped_deployments
Jun 20, 2026
Merged

adds sync support from local files for airgapped deployments#4574
akshaydeo merged 1 commit into
devfrom
06-20-adds_sync_support_from_local_files_for_airgapped_deployments

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds support for loading Bifrost's pricing and model parameters datasheets from local files using the file:// URL scheme. This resolves a connectivity issue (closes #4305) where hosts without outbound internet access, or behind HTTP proxies that block DNS resolution of getbifrost.ai, could not start Bifrost successfully.

Changes

  • Added a new example config at examples/configs/withlocalpricingfiles/ demonstrating how to configure pricing_url and model_parameters_url with file:// paths, along with sample pricing and model parameters datasheets containing real entries for gpt-4o, gpt-4o-mini, gpt-4.1, claude-sonnet-4-20250514, and text-embedding-3-small.
  • Added unit tests in framework/modelcatalog/datasheet/localfiles_test.go that verify both datasheets load correctly from file:// URLs without any network access or hostname resolution. A dedicated regression test (TestLoadFromLocalFiles_NeverResolvesHostname) guards against the file:// scheme accidentally falling through to external URL validation.
  • Added testdata/ fixtures mirroring the example datasheets for use by the tests.

The file:// scheme short-circuits external URL validation and hostname lookup entirely, reading the path directly off disk.

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 ./framework/modelcatalog/datasheet/...

To validate the Docker example:

cd examples/configs/withlocalpricingfiles
docker run -p 8080:8080 \
  -e OPENAI_API_KEY=sk-... \
  -v "$(pwd)/config.json:/app/data/config.json" \
  -v "$(pwd)/pricing.json:/opt/bifrost/pricing.json" \
  -v "$(pwd)/model-parameters.json:/opt/bifrost/model-parameters.json" \
  maximhq/bifrost

Bifrost should start without attempting to reach getbifrost.ai. Pricing and model parameter lookups for the bundled models should resolve correctly from the local files.

New config fields:

Field Example value Description
framework.pricing.pricing_url file:///opt/bifrost/pricing.json Local path to the pricing datasheet
framework.pricing.model_parameters_url file:///opt/bifrost/model-parameters.json Local path to the model parameters datasheet

Breaking changes

  • Yes
  • No

Related issues

Closes #4305

Security considerations

The file:// scheme reads arbitrary paths off disk as the process user. Operators should ensure the mounted files are not world-writable and that the container or process runs with appropriate least-privilege permissions.

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

@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 Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

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

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

To continue reviewing without waiting, enable usage-based billing 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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8037d1c5-8693-4d36-ba61-3780f999ba39

📥 Commits

Reviewing files that changed from the base of the PR and between 90ad24b and 51171a9.

📒 Files selected for processing (9)
  • examples/configs/withlocalpricingfiles/README.md
  • examples/configs/withlocalpricingfiles/config.json
  • examples/configs/withlocalpricingfiles/model-parameters.json
  • examples/configs/withlocalpricingfiles/pricing.json
  • framework/modelcatalog/datasheet/localfiles_test.go
  • framework/modelcatalog/datasheet/params.go
  • framework/modelcatalog/datasheet/sync.go
  • framework/modelcatalog/datasheet/testdata/model-parameters.json
  • framework/modelcatalog/datasheet/testdata/pricing.json
📝 Walkthrough

Walkthrough

Adds a new withlocalpricingfiles example configuration demonstrating Bifrost loading pricing and model-parameter datasheets from local file:// URLs instead of remote endpoints. Accompanying Go tests in the datasheet package validate that file:// URLs load correctly and that no hostname resolution occurs (regression guard for issue #4305).

Changes

Local file:// Datasheet Loading

Layer / File(s) Summary
Example config and README for local file:// setup
examples/configs/withlocalpricingfiles/README.md, examples/configs/withlocalpricingfiles/config.json
README describes air-gapped use case, Docker/local run instructions, and download commands. config.json wires a SQLite store, file:// pricing/model-parameter sources with daily sync, and an OpenAI provider from an environment variable.
Example pricing and model-parameter JSON data
examples/configs/withlocalpricingfiles/pricing.json, examples/configs/withlocalpricingfiles/model-parameters.json
Full sample data for gpt-4o, gpt-4o-mini, gpt-4.1, claude-sonnet-4-20250514, and text-embedding-3-small covering token costs, limits, capability flags, deprecation metadata, and model_parameters arrays with defaults, ranges, and options.
Test fixtures and Go tests for file:// loading
framework/modelcatalog/datasheet/localfiles_test.go, framework/modelcatalog/datasheet/testdata/pricing.json, framework/modelcatalog/datasheet/testdata/model-parameters.json
Test data fixtures mirror the example JSON data. TestLoadFromLocalFiles asserts correct pricing and parameter contents (gpt-4o InputCostPerToken, temperature, tools). TestLoadFromLocalFiles_NeverResolvesHostname is a regression test ensuring file:// URLs bypass hostname resolution.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • maximhq/bifrost#3609: Introduced a configurable model_parameters_url field that drives where model-parameter data is fetched; this PR's store.ModelParametersURL() assertion and example config directly build on that field.
  • maximhq/bifrost#4045: Introduced file:// URL-loading behavior and the hostname-resolution bypass that this PR's regression test (TestLoadFromLocalFiles_NeverResolvesHostname, issue #4305) exercises.

Suggested reviewers

  • danpiths
  • Pratham-Mishra04

🐇 A rabbit hops through disk and drive,
No DNS needed — files stay alive!
file:// paths, no hostname to chase,
Air-gapped and cozy in its local space.
Pricing and params, all tucked snug on disk,
No network required — now that's worth the risk! 🗂️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding support for local file synchronization in air-gapped deployments.
Description check ✅ Passed The PR description comprehensively covers all required template sections including summary, changes, type of change, affected areas, testing instructions, and related issues.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #4305: enables local file support via file:// scheme, supports air-gapped deployments, eliminates hostname resolution for local paths, and prioritizes local configuration.
Out of Scope Changes check ✅ Passed All code changes are directly related to the PR objectives: example configs, test fixtures, and unit tests for local file support from issue #4305. No unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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-20-adds_sync_support_from_local_files_for_airgapped_deployments

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

@akshaydeo
akshaydeo marked this pull request as ready for review June 20, 2026 10:59

Copy link
Copy Markdown
Contributor Author

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

@greptile-apps

greptile-apps Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

The core Go changes are a small, well-tested helper plus two call-site updates; the file:// branch is entirely additive and does not affect the existing HTTP path.

The filePathFromURL helper is correct for all documented URL shapes and is thoroughly exercised by the new unit tests. The scheme check is cleanly placed before URL validation and HTTP dispatch, so existing behaviour is unaffected. The only issues are data-accuracy nits in the bundled JSON fixtures (presence_penalty range), which do not affect the Go loading logic itself.

Both model-parameters.json fixtures (testdata/ and examples/configs/withlocalpricingfiles/) contain an inaccurate presence_penalty range for gpt-4o-mini.

Important Files Changed

Filename Overview
framework/modelcatalog/datasheet/sync.go Adds filePathFromURL helper and switches loadPricingFromURL to use it instead of parsed.Path directly; correctly handles all file:// URL forms (absolute, relative, opaque, localhost authority)
framework/modelcatalog/datasheet/params.go Mirrors the filePathFromURL fix in loadModelParametersFromURL; one-line change consistent with the sync.go update
framework/modelcatalog/datasheet/localfiles_test.go Adds well-structured unit tests covering all URL shapes, both datasheets, and a dedicated regression test ensuring file:// never triggers hostname resolution
framework/modelcatalog/datasheet/testdata/model-parameters.json Real-entry fixture for tests; presence_penalty range for gpt-4o-mini uses min: 0 instead of the correct -2
examples/configs/withlocalpricingfiles/model-parameters.json Example model-parameters datasheet for air-gapped deployments; same presence_penalty min: 0 inaccuracy as the test fixture for gpt-4o-mini
examples/configs/withlocalpricingfiles/config.json Example config using relative file:// URLs; requires running from the transports directory as documented in the accompanying README
framework/modelcatalog/datasheet/testdata/pricing.json Pricing fixture with real entries; values look correct
examples/configs/withlocalpricingfiles/pricing.json Example pricing datasheet; values consistent with the test fixture

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[loadPricingFromURL / loadModelParametersFromURL] --> B{url.Parse scheme}
    B -- file --> C[filePathFromURL]
    C --> D{parsed.Opaque != empty?}
    D -- yes --> E[return Opaque\ne.g. file:./x.json]
    D -- no --> F{Host != empty\nand != localhost?}
    F -- yes --> G[return Host + Path\ne.g. file://../../x.json]
    F -- no --> H[return Path\ne.g. file:///abs/x.json]
    E & G & H --> I[os.ReadFile]
    B -- http/https --> J[ValidateExternalURL]
    J --> K[http.Client.Do]
    K --> L[io.ReadAll]
    I & L --> M[json.Unmarshal]
    M --> N[applyPricingData /\napplyModelParameters]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[loadPricingFromURL / loadModelParametersFromURL] --> B{url.Parse scheme}
    B -- file --> C[filePathFromURL]
    C --> D{parsed.Opaque != empty?}
    D -- yes --> E[return Opaque\ne.g. file:./x.json]
    D -- no --> F{Host != empty\nand != localhost?}
    F -- yes --> G[return Host + Path\ne.g. file://../../x.json]
    F -- no --> H[return Path\ne.g. file:///abs/x.json]
    E & G & H --> I[os.ReadFile]
    B -- http/https --> J[ValidateExternalURL]
    J --> K[http.Client.Do]
    K --> L[io.ReadAll]
    I & L --> M[json.Unmarshal]
    M --> N[applyPricingData /\napplyModelParameters]
Loading

Reviews (3): Last reviewed commit: "adds sync support from local files for a..." | Re-trigger Greptile

Comment thread framework/modelcatalog/datasheet/testdata/model-parameters.json
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 20, 2026
@akshaydeo
akshaydeo force-pushed the 06-20-adds_sync_support_from_local_files_for_airgapped_deployments branch from c1419ac to 90ad24b Compare June 20, 2026 11: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.

Actionable comments posted: 2

🤖 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 `@framework/modelcatalog/datasheet/testdata/model-parameters.json`:
- Line 613: The model configuration on line 613 declares mode as "embedding",
but the subsequent lines 619-759 contain chat-generation specific parameters
such as temperature, max_tokens, stop, n, and stream, which are not valid for
embedding models. To fix this, either change the mode value from "embedding" to
an appropriate chat-specific mode that supports these parameters, or remove all
chat-only control parameters from this configuration block to ensure the
parameters align with the embedding mode declaration.
- Line 61: The text-embedding-3-small model is declared with "mode": "embedding"
but includes chat completion-specific parameters that don't apply to embedding
models. Locate the text-embedding-3-small model definition in the fixture and
remove all chat completion parameters (temperature, max_tokens, stop, top_p,
frequency_penalty, logit_bias, logprobs, n, presence_penalty, seed, stream) from
its parameter list, keeping only parameters that are applicable to embedding
requests.
🪄 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: 10f356bf-6976-45e5-824f-0d7a7e5259c2

📥 Commits

Reviewing files that changed from the base of the PR and between c1419ac and 90ad24b.

📒 Files selected for processing (7)
  • examples/configs/withlocalpricingfiles/README.md
  • examples/configs/withlocalpricingfiles/config.json
  • examples/configs/withlocalpricingfiles/model-parameters.json
  • examples/configs/withlocalpricingfiles/pricing.json
  • framework/modelcatalog/datasheet/localfiles_test.go
  • framework/modelcatalog/datasheet/testdata/model-parameters.json
  • framework/modelcatalog/datasheet/testdata/pricing.json
✅ Files skipped from review due to trivial changes (2)
  • examples/configs/withlocalpricingfiles/config.json
  • examples/configs/withlocalpricingfiles/README.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • framework/modelcatalog/datasheet/localfiles_test.go
  • examples/configs/withlocalpricingfiles/pricing.json
  • examples/configs/withlocalpricingfiles/model-parameters.json
  • framework/modelcatalog/datasheet/testdata/pricing.json

Comment thread framework/modelcatalog/datasheet/testdata/model-parameters.json
Comment thread framework/modelcatalog/datasheet/testdata/model-parameters.json
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 20, 2026
@akshaydeo
akshaydeo force-pushed the 06-20-adds_sync_support_from_local_files_for_airgapped_deployments branch from 90ad24b to 51171a9 Compare June 20, 2026 12:12

akshaydeo commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Jun 20, 12:14 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 20, 12:15 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit 565750a into dev Jun 20, 2026
13 of 15 checks passed
@akshaydeo
akshaydeo deleted the 06-20-adds_sync_support_from_local_files_for_airgapped_deployments branch June 20, 2026 12:15
akshaydeo added a commit that referenced this pull request Jun 21, 2026
## Summary

Adds support for loading Bifrost's pricing and model parameters datasheets from local files using the `file://` URL scheme. This resolves a connectivity issue (closes #4305) where hosts without outbound internet access, or behind HTTP proxies that block DNS resolution of `getbifrost.ai`, could not start Bifrost successfully.

## Changes

- Added a new example config at `examples/configs/withlocalpricingfiles/` demonstrating how to configure `pricing_url` and `model_parameters_url` with `file://` paths, along with sample pricing and model parameters datasheets containing real entries for `gpt-4o`, `gpt-4o-mini`, `gpt-4.1`, `claude-sonnet-4-20250514`, and `text-embedding-3-small`.
- Added unit tests in `framework/modelcatalog/datasheet/localfiles_test.go` that verify both datasheets load correctly from `file://` URLs without any network access or hostname resolution. A dedicated regression test (`TestLoadFromLocalFiles_NeverResolvesHostname`) guards against the `file://` scheme accidentally falling through to external URL validation.
- Added `testdata/` fixtures mirroring the example datasheets for use by the tests.

The `file://` scheme short-circuits external URL validation and hostname lookup entirely, reading the path directly off disk.

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [x] Docs

## How to test

```sh
go test ./framework/modelcatalog/datasheet/...
```

To validate the Docker example:

```sh
cd examples/configs/withlocalpricingfiles
docker run -p 8080:8080 \
  -e OPENAI_API_KEY=sk-... \
  -v "$(pwd)/config.json:/app/data/config.json" \
  -v "$(pwd)/pricing.json:/opt/bifrost/pricing.json" \
  -v "$(pwd)/model-parameters.json:/opt/bifrost/model-parameters.json" \
  maximhq/bifrost
```

Bifrost should start without attempting to reach `getbifrost.ai`. Pricing and model parameter lookups for the bundled models should resolve correctly from the local files.

**New config fields:**

| Field | Example value | Description |
| --- | --- | --- |
| `framework.pricing.pricing_url` | `file:///opt/bifrost/pricing.json` | Local path to the pricing datasheet |
| `framework.pricing.model_parameters_url` | `file:///opt/bifrost/model-parameters.json` | Local path to the model parameters datasheet |

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Closes #4305

## Security considerations

The `file://` scheme reads arbitrary paths off disk as the process user. Operators should ensure the mounted files are not world-writable and that the container or process runs with appropriate least-privilege permissions.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
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.

[Bug]: Model parameters can't be configured locally

2 participants