Skip to content

Feat/dynamic worker autoscaler v2 - #4768

Closed
Prateek-Gupta001 wants to merge 25 commits into
maximhq:devfrom
Prateek-Gupta001:feat/dynamic-worker-autoscaler-v2
Closed

Feat/dynamic worker autoscaler v2#4768
Prateek-Gupta001 wants to merge 25 commits into
maximhq:devfrom
Prateek-Gupta001:feat/dynamic-worker-autoscaler-v2

Conversation

@Prateek-Gupta001

@Prateek-Gupta001 Prateek-Gupta001 commented Jun 29, 2026

Copy link
Copy Markdown

Summary

Previously, the number of worker goroutines per provider in Bifrost was fixed at initialization time via the Concurrency field. Under heavy load, a provider with a small worker pool became a bottleneck, requests queued up faster than workers could drain them. During idle periods, pre-allocated goroutines sat doing nothing, wasting memory.
This PR implements opt-in dynamic worker pool auto-scaling per provider. A background goroutine monitors queue utilization at a configurable interval and adds or removes workers at runtime, bounded by MinWorkers and MaxWorkers. Providers that don't opt in see zero behavior change.

Closes #128

Changes:

core/bifrost.go

  • Added quit chan struct{} and ActiveWorkers atomic.Int32 fields to ProviderQueue
  • Added DynamicWorkerScaling() goroutine which runs on after a set time which can be configured by the user, the go routine then reads len(queue)/cap(queue) as utilization, scales up in steps (15% of MaxWorkers, doubled at ≥90% utilization) or signals workers to self-exit via the quit channel.
  • Modified prepareProvider() to validate scaling config and conditionally launch the scaler goroutine
  • Modified requestWorker() to select on pq.quit alongside pq.queue, allowing voluntary self-exit on scale-down signals

Design decisions: Buffer resizing is out of scope. It would require stop-the-world channel swap operation that cannot be done frequently. This was confirmed in the issue thread by @HzTTT and acknowledged by @Pratham-Mishra04.
Dynamic worker scaling achieves the same throughput benefit without touching the buffer.

core/schemas/provider.go

  • Added 6 new fields to ConcurrencyAndBufferSize: DynamicScaling, MinWorkers, MaxWorkers, ScaleUpThreshold, ScaleDownThreshold, ScalingInterval

core/bifrost_test.go

  • TestDynamicWorkerScalingConfig: 8 edge cases covering invalid config combinations (negative values, max < min, concurrency out of bounds, thresholds inverted, zero values). Verifies invalid configs disable scaling gracefully via warning log rather than hard error.
  • TestDynamicWorkerScalingUp: floods the provider queue with dummy requests, asserts ActiveWorkers reaches MaxWorkers within the scaling interval.
  • TestDynamicWorkerScalingDown: starts with a full worker pool against an empty queue, asserts ActiveWorkers drains to MinWorkers after a couple of iterations of scaling.

Type of change

  • Feature

Affected areas

  • Core (Go)

Breaking changes

  • No

All new fields are additive and zero-valued by default. Providers without DynamicScaling config are entirely unaffected.

Security considerations

No auth, secrets, or PII involved. The scaler only reads len(queue) and cap(queue) ,no request content is accessed.

How to test

cd core
go test -v -run ^TestDynamicWorkerScalingConfig$
go test -v -run ^TestDynamicWorkerScalingUp$
go test -v -run ^TestDynamicWorkerScalingDown$

New config changes:

type ConcurrencyAndBufferSize struct {
	Concurrency        int           `json:"concurrency"`          // Number of concurrent operations. Also used as the initial pool size for the provider reponses.
	BufferSize         int           `json:"buffer_size"`          // Size of the buffer
	DynamicScaling     bool          `json:"dynamic_scaling"`      //Whether the user wants dynamic scaling to happen
	ScalingInterval    time.Duration `json:"scaling_interval"`     //After how much time will the go routine run and check the capacity of the queue and make the nesscary changes.
	MinWorkers         int           `json:"min_workers"`          //No. of workers will never go below this value
	MaxWorkers         int           `json:"max_workers"`          //No. of workers will never go above this value
	ScaleUpThreshold   float64       `json:"scale_up_threshold"`   //If Queue capacity is above this threshold (eg 70%) then workers would be scaled up.
	ScaleDownThreshold float64       `json:"scale_down_threshold"` //If Queue capacity is below this threshold (eg 20%) then workers would be scaled down.
}


type ProviderQueue struct {
	queue         chan *ChannelMessage // the actual request queue channel
	done          chan struct{}        // closed to signal shutdown to producers
	closing       uint32               // atomic: 0 = open, 1 = closing
	quit          chan struct{}        //signal is sent on this channel to kill the workers during autoscaling.
	ActiveWorkers atomic.Int32
	signalOnce    sync.Once
	closeOnce     sync.Once
}

Testing

Some tests are failing on main branch as well (unrelated to this PR).
No additional failures introduced by this change.
All tests in core (the package affected by this PR pass)

Linting

golangci-lint when done on core introduced existing issues.
This PR does not introduce new lint errors in modified files.

##Notes
I will update the documentation once we finalise on certain small issues such as:

  1. What should be the step size of incrementing/decrementing workers. Currently it is 15% of MaxWorkers.
    and other implementation based details.

Checklist

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

akshaydeo and others added 22 commits June 25, 2026 20:18
…dle special characters in URLs (maximhq#4714)

## Summary

Array-type query parameters in the logs page (models, providers, etc.) were not using the safe URI-encoding parser, meaning values containing characters like `://` (e.g. model names such as `gpt://host/model`) could be misinterpreted as path or query delimiters by TanStack Router. This introduces `parseAsSafeArrayOf` and applies it consistently across all array filters.

## Changes

- Added `parseAsSafeArrayOf` to `queryParamsParser.ts` by composing `parseAsArrayOf` with the existing `parseAsSafeString` parser, ensuring full URI-encoding for comma-separated filter values.
- Replaced all usages of `parseAsArrayOf(parseAsString)` in the logs page with `parseAsSafeArrayOf` so that array filters (models, providers, aliases, status, etc.) benefit from the same encoding guarantees as string filters.
- Added unit tests for both `parseAsSafeString` and `parseAsSafeArrayOf` to verify round-trip correctness with model names containing `://`.

## Type of change

- [x] Bug fix

## Affected areas

- [x] UI (React)

## How to test

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

To manually verify, navigate to the logs page and apply a filter using a model name containing `://` (e.g. `gpt://host/model`). Confirm the URL encodes correctly and the filter persists on page reload without routing errors.

## Screenshots/Recordings

N/A

## Breaking changes

- [x] No

## Related issues

maximhq#4603

## Security considerations

No security implications. This change only affects URL query parameter encoding in the UI.

## Checklist

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

## Summary

Adds a reusable `TruncatedLabel` component that displays truncated text with an automatic tooltip when the content overflows its container.

## Changes

- Introduces `TruncatedLabel`, a `<span>`-based component that detects when its text content is truncated via CSS overflow and conditionally renders a `Tooltip` to show the full content
- Truncation detection is performed by comparing `scrollWidth` to `clientWidth`, and re-evaluated on window resize or when `children` changes
- The tooltip content defaults to the `children` value if it is a string, but accepts an explicit `tooltip` prop for custom content
- The tooltip is only rendered when the text is actually truncated, avoiding unnecessary DOM overhead when content fits

## Type of change

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

## Affected areas

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

## How to test

```sh
cd ui
pnpm i || npm i
pnpm build || npm run build
```

Render a `TruncatedLabel` inside a constrained-width container with a long string. Verify that hovering over the truncated text shows a tooltip with the full content, and that no tooltip appears when the text is not truncated.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

No security implications. The component renders user-provided React nodes, which is consistent with existing UI patterns.

## 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
…ation logic (maximhq#4716)

## Summary

Extracts the truncated label logic (truncate text with a tooltip on overflow) into a shared `TruncatedLabel` component and replaces all inline implementations with it.

## Changes

- Added a reusable `TruncatedLabel` component in `ui/components/ui/truncatedLabel` that handles text truncation and conditionally renders a tooltip when the content overflows
- Removed the local `TruncatedName` component from the providers page, which duplicated this logic using `useRef`, `useState`, and a resize event listener
- Replaced inline `<span className="truncate ...">` elements in the logs and MCP filter sidebars with `TruncatedLabel`

## Type of change

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

## Affected areas

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

## How to test

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

Verify that truncated labels in the providers list and filter sidebars still show a tooltip on hover when the text overflows, and no tooltip when it does not.

## Screenshots/Recordings

Verify the providers sidebar and log/MCP filter sidebars visually behave the same as before — truncated text shows a tooltip, non-truncated text does not.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

maximhq#4604

## Security considerations

None.

## 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
…ximhq#4719)

## Summary

Fixes the layout of the Audit Logs page to correctly fill the viewport and apply the appropriate background and border styles.

## Changes

- Replaced `h-[calc(100dvh-1rem)]` with `h-[calc(100vh-16px)]` for consistent viewport height calculation
- Swapped `mx-auto flex flex-col p-4` utility classes for `no-border-parent bg-background flex` to align with the layout conventions used elsewhere in the app
- Added missing newline at end of file

## Type of change

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

## Affected areas

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

## How to test

Navigate to the Audit Logs page and verify:
- The page fills the full viewport height without overflow or clipping
- The background color and border styling match the rest of the workspace layout

```sh
cd ui
pnpm i || npm i
pnpm build || npm run build
```

## Screenshots/Recordings

Add before/after screenshots showing the corrected Audit Logs page layout.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None.

## 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

Adds collapsible tag support to the `TagInput` component and applies it to the keyword lists on the Complexity Router page. When a keyword list exceeds a configurable limit, tags beyond that limit are hidden behind a gradient overlay with a "Show more" toggle, keeping the UI compact while still allowing full access to all tags.

## Changes

- Added `collapsedTagLimit` and `expandButtonTestId` props to `TagInput`. When `collapsedTagLimit` is provided, the component renders in a collapsible layout: tags beyond the limit are hidden with a fade gradient, and "Show more" / "Show less" buttons toggle the expanded state. The collapsed state auto-resets when the tag count drops back to or below the limit.
- Set `KEYWORD_COLLAPSED_LIMIT = 8` on the Complexity Router page and passed it along with a `expandButtonTestId` to each keyword `TagInput`.
- Standardized border radius tokens from `rounded-lg`/`rounded-md`/`rounded-full` to `rounded-sm` across the Complexity Router page for visual consistency.
- Reformatted `index.html` inline shell skeleton from a single minified line to readable, indented HTML and CSS.

## Type of change

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

## Affected areas

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

## How to test

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

1. Navigate to the Complexity Router page.
2. Add more than 8 keywords to any keyword list.
3. Verify that tags beyond 8 are hidden with a gradient overlay and a "Show more" button appears.
4. Click "Show more" and confirm all tags are visible with a "Show less" button.
5. Click "Show less" and confirm the list collapses again.
6. Remove tags until 8 or fewer remain and confirm the list stays expanded without the toggle controls.

## Screenshots/Recordings

Before/after screenshots of the keyword lists with collapse behavior recommended.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None.

## 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
…maximhq#4722)

* fix: rebuild token_usage from denormalized columns in hybrid log list

* refactor: inline hybrid token usage reconstruction

* fix: preserve malformed serialized token usage state

---------

Co-authored-by: gexiangdong <xiangdong.ge@pandasofcaribbean.com>
…hatRequestBody` and `AnthropicProviderRequestDefaultsMap` (maximhq#3309)

## Summary

This PR consolidates Anthropic-family request building across all providers (Anthropic native, Azure, Vertex, Bedrock) into two shared builder functions — `BuildAnthropicChatRequestBody` and `BuildAnthropicResponsesRequestBody` — eliminating duplicated inline logic and provider-specific wrapper helpers that previously scattered the same field-stripping, beta-header injection, and model-field manipulation across multiple files.

## Changes

- Introduced `AnthropicProviderRequestDefaults` and `AnthropicProviderRequestDefaultsMap` to encode static, per-provider request-shaping flags (e.g. `DeleteModelField`, `DeleteStreamField`, `AddAnthropicVersion`, `InjectBetaHeadersIntoBody`) in one place. Callers no longer pass these flags directly; the builder looks them up by `cfg.Provider`.
- Renamed `Deployment` to `Model` in `AnthropicRequestBuildConfig` for clarity, since all providers now use the same field for model/deployment overrides.
- Added `BuildAnthropicChatRequestBody` as the chat-completion analogue of `BuildAnthropicResponsesRequestBody`, covering both raw-body and typed paths, including field stripping, beta-header injection, streaming flag handling, and `fallbacks` deletion.
- Bedrock now routes Anthropic models through the Anthropic Messages API format (`invoke` / `invoke-with-response-stream` endpoints) for both chat and responses, rather than the Bedrock Converse API. This includes proper response parsing via `AcquireAnthropicMessageResponse` and streaming via `AnthropicStreamState` / `AnthropicResponsesStreamState`.
- Removed private wrapper functions `getRequestBodyForResponses` (Anthropic), `getRequestBodyForAnthropicResponses` (Azure, Vertex), and the inline `CheckContextAndGetRequestBody` closures for Anthropic models in Vertex and Azure, replacing all call sites with direct `BuildAnthropicChatRequestBody` / `BuildAnthropicResponsesRequestBody` calls.
- Exported `AcquireAnthropicResponsesStreamState`, `ReleaseAnthropicResponsesStreamState`, `AcquireAnthropicMessageResponse`, and `ReleaseAnthropicMessageResponse` so Bedrock can reuse the Anthropic stream state pool.
- Removed `DefaultVertexAnthropicVersion` constant from the Vertex package; the canonical version string now lives in `AnthropicProviderRequestDefaultsMap`.
- Bedrock's `releaseBedrockChatResponse` now zeroes the struct before returning it to the pool.
- `stripUnsupportedAnthropicFields` is now called inside `BuildAnthropicResponsesRequestBody` on the typed path, making field stripping symmetric across raw and typed paths and across both APIs.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./core/providers/anthropic/...
go test ./core/providers/azure/...
go test ./core/providers/bedrock/...
go test ./core/providers/vertex/...
go test ./...
```

Run integration tests against Anthropic, Azure (Anthropic models), Vertex (Claude models), and Bedrock (Claude models) for chat completion, streaming, responses, responses streaming, and count-tokens endpoints. Verify that raw-body passthrough requests produce the same field stripping and beta-header injection as typed requests.

## Breaking changes

- [x] Yes
- [ ] No

`AnthropicRequestBuildConfig` has a breaking field rename: `Deployment` → `Model`. Any external code constructing this struct directly must update the field name. The static shaping flags (`DeleteModelField`, `DeleteRegionField`, `AddAnthropicVersion`, `AnthropicVersion`, `StripCacheControlScope`, `RemapToolVersions`, `InjectBetaHeadersIntoBody`) have been removed from `AnthropicRequestBuildConfig` and are now looked up internally via `AnthropicProviderRequestDefaultsMap`; callers that set these fields must remove them.

## Related issues

## Security considerations

No new auth flows, secrets handling, or PII exposure introduced. Field stripping ensures provider-unsupported fields are not forwarded to external APIs.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
…hropicResponsesRequest` and make `completeRequest` a package-level func shared by Anthropic, Azure, and Bedrock providers (maximhq#4394)

## Summary

The Anthropic provider's unary request logic was duplicated across the Anthropic, Azure, Bedrock, and Vertex providers. This PR extracts the core non-streaming request execution into a package-level `completeRequest` function and introduces two exported handler functions — `HandleAnthropicChatCompletionRequest` and `HandleAnthropicResponsesRequest` — that encapsulate the full build → send → parse pipeline for chat completions and the Responses API respectively. Azure and Bedrock now delegate directly to these shared handlers for Anthropic-family models instead of reimplementing request dispatch, response parsing, and raw request/response handling inline.

A secondary bug fix is included: the large-response streaming client was being activated for count-tokens requests (which should always be buffered) and skipped for all other requests — the condition was inverted.

## Changes

- Extracted `completeRequest` as a package-level function accepting explicit `client`, `headers`, `extraHeaders`, `betaHeaderOverrides`, `providerName`, and `logger` arguments, removing the method receiver dependency so it can be called by other providers.
- Added `anthropicRequestHeaders` as a provider method to build the `x-api-key` / `anthropic-version` header map, shared across `TextCompletion`, `ChatCompletion`, `Responses`, and `CountTokens`.
- Introduced `HandleAnthropicChatCompletionRequest` and `HandleAnthropicResponsesRequest` as exported functions that perform the full unary request lifecycle (body build, HTTP send, large-response detection, response parse, raw request/response attachment). These are now called by the Anthropic, Azure, and Bedrock providers.
- Removed `completeMantleRequest` from Bedrock — its logic is now covered by `completeRequest` inside the shared handlers.
- Azure's `ChatCompletion` and `Responses` methods now branch early for Anthropic-family models, calling the shared handlers with Azure-specific auth headers, and fall through to the OpenAI-compatible path otherwise, eliminating the post-response model-family branch.
- Fixed the inverted condition in `completeRequest` that caused the large-response streaming client to be used for count-tokens requests instead of being skipped for them.
- `AnthropicRequestBuildConfig` now carries `BetaHeaderOverrides` so callers do not need to pass it separately.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./...
```

Validate that chat completions and Responses API requests succeed for Anthropic-family models routed through the Azure and Bedrock providers, and that count-tokens requests return buffered responses without triggering large-response mode.

## Breaking changes

- [ ] Yes
- [x] No

## Security considerations

Auth headers (`x-api-key`, Bearer tokens, SigV4-signed headers) are applied last in `completeRequest`, after network-config extra headers, ensuring they cannot be overridden by user-supplied configuration. No new secrets or PII handling paths are introduced.

## 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
…atible providers from `schemas.Key` to `map[string]string` auth header param (maximhq#4425)

## Summary

This PR standardizes how Bearer token authentication headers are constructed across all OpenAI-compatible providers. Previously, each call site independently built the `Authorization: Bearer <token>` header map with duplicated inline logic. A new `BearerAuthHeader(key)` helper is introduced in the OpenAI package and used uniformly everywhere.

Additionally, the Azure provider's private `completeRequest` method is removed. Its non-Anthropic request paths (text completion, chat completion, responses, embedding, compaction) are now delegated directly to the shared `Handle*` functions in the OpenAI package, consistent with how other providers already work. The `Handle*` functions themselves are updated to accept a pre-built `authHeader map[string]string` instead of a raw `schemas.Key`, making them provider-agnostic and compatible with non-Bearer auth schemes (e.g., Azure API key headers, SigV4).

## Changes

- Added `BearerAuthHeader(key schemas.Key) map[string]string` to the OpenAI provider package, which returns an `Authorization: Bearer <token>` header map, or an empty map when the key carries no value.
- Updated all `Handle*Request` and `handleOpenAILargePayloadPassthrough` function signatures to accept `authHeader map[string]string` instead of `schemas.Key`, applying the map directly to request headers.
- Replaced all inline `var authHeader map[string]string` + conditional assignment blocks across Cerebras, Fireworks, Groq, HuggingFace, Mistral, Nebius, Ollama, Opencode, OpenRouter, Parasail, Perplexity, SGL, VLLM, xAI, and Bedrock with calls to `openai.BearerAuthHeader(key)`.
- Removed the Azure provider's `completeRequest` method and replaced its usage in `TextCompletion`, `ChatCompletion`, `Responses`, `Embedding`, and `Compaction` with direct calls to the corresponding shared OpenAI `Handle*` functions, passing Azure-specific auth headers and pre-resolved endpoint URLs.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./...
```

Verify that all OpenAI-compatible providers (OpenAI, Azure, Cerebras, Fireworks, Groq, HuggingFace, Mistral, Nebius, Ollama, Opencode, OpenRouter, Parasail, Perplexity, SGL, VLLM, xAI, Bedrock Mantle) continue to authenticate correctly and that requests succeed for text completion, chat completion, responses, embeddings, and compaction endpoints.

## Breaking changes

- [ ] Yes
- [x] No

## Security considerations

The `BearerAuthHeader` helper preserves the existing behavior of omitting the `Authorization` header when the key value is empty, which is intentional for providers that supply auth via other mechanisms (e.g., extra headers or SigV4 signing). No secrets are logged or exposed.

## 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
… closure passed through request handlers (maximhq#4735)

## Summary

Replaces the pre-build-and-sign approach for Bedrock Mantle SigV4 authentication with a `BodySigner` callback that is invoked after the request handler has marshaled the body. This ensures the signature always covers the exact bytes sent on the wire, eliminating the previous double-marshal pattern where the body was built once for signing and again inside the handler.

## Changes

- Introduces a new `BodySigner` type (`func(jsonData []byte) (map[string]string, *schemas.BifrostError)`) in `core/providers/utils/bodysigner.go`. Handlers call it after building the request body and apply the returned headers to the outgoing request.
- Adds the `signer` parameter to `HandleOpenAIChatCompletionRequest`, `HandleOpenAIChatCompletionStreaming`, `HandleOpenAIResponsesRequest`, `HandleOpenAIResponsesStreaming`, `HandleAnthropicChatCompletionRequest`, `HandleAnthropicChatCompletionStreaming`, `HandleAnthropicResponsesRequest`, and `HandleAnthropicResponsesStream`. All existing callers pass `nil`.
- Rewrites Bedrock Mantle's SigV4 paths (`mantleChatCompletions`, `mantleChatCompletionsStream`, `mantleResponses`, `mantleResponsesStream`) to construct a `BodySigner` closure when no API key is present, instead of pre-building the body, signing it, and merging the signature headers into `extraHeaders`. The Bearer path no longer needs a separate early-return branch.
- Removes the now-unnecessary `maps` import and the intermediate `extraHeaders` map copies in the Mantle code paths.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./...
```

For Bedrock Mantle with SigV4 (empty key value), verify that requests to chat completions, streaming chat completions, responses, and streaming responses are signed correctly and accepted by the Bedrock endpoint. For Bearer key paths, confirm that no signing is attempted and the `Authorization` header is set as expected.

## Breaking changes

- [ ] Yes
- [x] No

## Security considerations

The `BodySigner` callback signs the exact serialized bytes that are placed on the wire. Previously, the body was serialized twice (once for signing, once inside the handler), which could in theory produce a signature mismatch if marshaling were non-deterministic. This change closes that gap by signing after the final body is set.

## 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
…ropic and OpenAI-compatible routing (maximhq#4736)

## Summary

Introduces `bedrock_mantle` as a first-class, standalone provider that owns the Bedrock Mantle surface (`bedrock-mantle.{region}.api.aws`). Previously, Mantle routing was handled as an internal routing decision inside the existing `bedrock` provider. The new provider gives operators a dedicated configuration surface for Claude (native Anthropic Messages API), OpenAI-compatible models (gpt-*), and Gemma models served through Mantle, without requiring a full Bedrock setup.

## Changes

- Added `schemas.BedrockMantle` (`"bedrock_mantle"`) as a new `ModelProvider` constant and registered it in `StandardProviders`, `dynamicallyConfigurableProviders`, `CanProviderKeyValueBeEmpty`, and `isKeySkippingAllowed`.
- Added `BedrockMantleKeyConfig` to the `Key` struct, carrying AWS credentials and region for SigV4 auth against the `bedrock-mantle` service. The existing `BedrockKeyConfig` is unchanged.
- Introduced the `core/providers/bedrockmantle` package implementing the full `Provider` interface. Chat, streaming chat, Responses, and streaming Responses dispatch by model family: Anthropic-family models use the native Anthropic Messages surface (`/anthropic/v1/messages`); all others use the OpenAI-compatible surface (`/v1` or `/openai/v1`). All other operations return unsupported-operation errors.
- Refactored `signAWSRequest` in the `bedrock` package to accept a `*BedrockKeyConfig` instead of individual credential fields, eliminating the now-redundant `signAWSRequestFromKey` wrapper. All call sites updated accordingly.
- Exported `SignMantleV4Headers` (previously `mantleSigV4Headers`, a method on `BedrockProvider`) so the new `bedrockmantle` package can sign requests without depending on the internal Bedrock provider struct. The function now supports both `BedrockKeyConfig` and `BedrockMantleKeyConfig` by mapping the latter into a synthetic `BedrockKeyConfig` for signing, and correctly handles GET requests (nil body) for the list-models path.
- Extended the Anthropic chat and Responses request builders to convert native structured outputs to tool calls for `BedrockMantle`, matching the existing `Vertex` workaround.
- Added `BedrockMantle` to the comprehensive LLM test harness (`ComprehensiveTestAccount`) with key config, provider config, and a full test file covering the supported scenarios (chat, streaming, tool calls, vision, structured outputs, prompt caching, reasoning, list models) and explicitly disabling unsupported ones.
- Marked `isMantleModel` in `bedrock/mantle.go` as deprecated in favour of the new provider.

## Type of change

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

## Affected areas

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

## How to test

Set AWS credentials and run the new provider test:

```sh
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...   # optional, for temporary credentials
export AWS_REGION=us-east-1

go test ./core/providers/bedrockmantle/... -v -run TestBedrockMantle
```

To run the full suite (skips Bedrock Mantle automatically when credentials are absent):

```sh
go test ./...
```

Configure a `bedrock_mantle` provider by supplying a `BedrockMantleKeyConfig` (or a Bearer API key in `Value`) with the desired region. The region can also be embedded as a prefix in the model ID (e.g. `us-west-2/anthropic.claude-haiku-4-5`) or set at the alias level via `AliasConfig.Region`.

## Breaking changes

- [ ] Yes
- [x] No

The `signAWSRequest` signature change is internal to the `bedrock` package and does not affect any public API. The `isMantleModel` function is deprecated but not removed.

## Security considerations

AWS credentials for `BedrockMantleKeyConfig` follow the same `SecretVar` resolution pattern used by `BedrockKeyConfig` (env-var references, never inlined literals). SigV4 signing is performed per-request on the exact body bytes that are sent, so the signature always covers what is transmitted. When a Bearer API key is present it takes precedence and no AWS credentials are required.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
…on, and UI support (maximhq#4737)

## Summary

Adds `bedrock_mantle` as a first-class provider, enabling Bifrost to route requests to AWS Bedrock through a Mantle proxy endpoint. The provider supports the same SigV4 credential options as the existing Bedrock provider (inherited IAM role, explicit access/secret key, session token, AssumeRole) as well as a Bearer API key authentication mode.

## Changes

- Added `BedrockMantle` to the Anthropic passthrough allowlist in `clearAnthropicPassthroughForNonNativeProvider` so raw request bodies are preserved when routing through Bedrock Mantle.
- Added `BedrockMantleKeyConfig` redaction logic in `clientconfig.go`, mirroring the existing Bedrock redaction pattern.
- Added a new `migrationAddBedrockMantleKeyColumns` database migration that introduces seven `bedrock_mantle_*` SigV4 credential columns to the `config_keys` table.
- Extended `TableKey` with the seven Bedrock Mantle credential fields, along with `BeforeSave` serialization and `AfterFind` reconstruction hooks.
- Updated `mergeUpdatedKey` in the HTTP handler to correctly restore redacted Bedrock Mantle credential fields during key updates.
- Fixed `isClaudeModel` in the Anthropic integration to recognize `bedrock_mantle` (previously incorrectly matched `bedrock`) as a provider that can serve Claude models.
- Included `BedrockMantleKeyConfig` in the key hash inputs used by `mergeProviderKeys` and `reconcileProviderKeys` for config file/DB reconciliation.
- Added Bedrock Mantle credential redaction to `GetAllKeys`.
- Extended `config.schema.json` with `bedrock_mantle_key` and `provider_with_bedrock_mantle_config` definitions and registered `bedrock_mantle` as a valid provider name throughout the schema.
- Added UI support: provider icon (reusing the Bedrock SVG mark with a distinct gradient ID), model placeholder text, `isKeyRequiredByProvider` entry, label, form schema (`BedrockMantleKeyConfigSchema`), type definitions (`BedrockMantleKeyConfig`, `DefaultBedrockMantleKeyConfig`), and a full authentication method tab UI (IAM Role / Explicit Credentials / API Key) matching the Bedrock provider UX.
- Added `bedrock_mantle` to the Anthropic beta-headers provider family and the provider config sheet's Anthropic family list.
- Stripped the internal `_auth_type` field from `bedrock_mantle_key_config` before submitting the form payload.

## Type of change

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

## Affected areas

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

## How to test

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

Configure a `bedrock_mantle` provider in `config.json` or via the UI with one of the three auth methods:

- **IAM Role (Inherited):** set only `region`; leave access/secret key empty.
- **Explicit Credentials:** set `access_key`, `secret_key`, and `region`; optionally set `session_token`, `role_arn`, `external_id`, and `session_name`.
- **API Key:** set `region` and provide a Bearer token as the key `value`.

Send a request targeting a Claude model through the `bedrock_mantle` provider and verify the response is returned correctly and that credentials are redacted in the UI and API responses.

## Screenshots/Recordings

_Add before/after screenshots of the new Bedrock Mantle provider form and icon in the UI._

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

_Link related issues and discussions._

## Security considerations

- All seven Bedrock Mantle credential fields (`access_key`, `secret_key`, `session_token`, `region`, `role_arn`, `external_id`, `role_session_name`) are stored as `SecretVar` and are redacted in API responses and the UI, consistent with the existing Bedrock provider handling.
- The `_auth_type` discriminator field is stripped from the payload before it is persisted or transmitted.

## 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

Adds documentation for the AWS Bedrock Mantle provider, a distinct AWS endpoint (`bedrock-mantle.{region}.api.aws`) that exposes Claude models via the native Anthropic Messages API and OpenAI-family/Gemma models via an OpenAI-compatible API — all addressable through a single `bedrock_mantle/<model>` prefix in Bifrost.

## Changes

- Added a new `bedrock-mantle.mdx` provider page covering model ID formats, supported operations, all three authentication modes (SigV4 with explicit credentials, IAM role/inherited credentials, and Bearer API key), IAM role assumption via `role_arn`, and usage examples.
- Added the Bedrock Mantle configuration block to the `providers.mdx` config reference, with tabs for Static Credentials, IAM Role, and API Key (Bearer) auth modes.
- Added Bedrock Mantle to the provider capability matrix in `overview.mdx`.
- Registered `bedrock-mantle` in `docs.json` so it appears in the sidebar navigation.

## Type of change

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

## Affected areas

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

## How to test

Navigate to the Bedrock Mantle provider page and config reference in the rendered docs and verify:

- The sidebar entry for `bedrock-mantle` appears between `bedrock` and `cerebras`.
- All three auth tabs (Static Credentials, IAM Role, API Key) render correctly in both the provider page and the config reference.
- The capability matrix row for `bedrock_mantle/<model>` is present and accurate.
- Cross-links between the provider page and the config reference resolve correctly.

## Breaking changes

- [x] No

## Security considerations

Authentication credentials (`access_key`, `secret_key`, `session_token`, API keys) are documented using the `env.*` indirection pattern, consistent with how other providers handle secrets. No credentials are hardcoded in examples.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] 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
…ment config (maximhq#4739)

## Summary

Adds E2E test configuration and capability definitions for the `bedrock_mantle` provider, enabling it to be tested through the Bifrost V1 API test suite.

## Changes

- Added `bedrock_mantle` to `provider-capabilities.json` with `chat_completions`, `chat_completions_with_tools`, `responses`, `responses_with_tools`, and `list_models` enabled
- Added a new Postman environment file (`bifrost-v1-bedrock-mantle.postman_environment.json`) configured to use `anthropic.claude-opus-4-8` as the default model and `us-east-1` as the default region, with secret placeholders for API key, access key, secret key, and session token

## Type of change

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

## Affected areas

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

## How to test

Run the E2E test suite targeting the `bedrock_mantle` provider using the new Postman environment:

```sh
# Ensure the Bifrost server is running locally on port 8080
# Load the environment file and run the collection against bedrock_mantle

newman run tests/e2e/api/bifrost-v1.postman_collection.json \
  -e tests/e2e/api/provider_config/bifrost-v1-bedrock-mantle.postman_environment.json \
  --env-var "bedrock_mantle_api_key=<your_api_key>" \
  --env-var "bedrock_mantle_access_key=<your_access_key>" \
  --env-var "bedrock_mantle_secret_key=<your_secret_key>"
```

Expected outcome: chat completions, tool-use, responses, and model listing tests pass; all unsupported capability tests are skipped or return expected errors.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

The Postman environment file stores API key, access key, secret key, and session token as `secret` type fields with empty default values, ensuring credentials are not committed to the repository.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
…d toggle when budget is alignable (maximhq#4724)

## Summary

The calendar alignment toggle in the provider governance form was previously shown whenever any budget existed. This PR restricts its visibility and submission to only when at least one budget uses a calendar-alignable reset period (day, week, month, or year).

## Changes

- Introduced a `showCalendarAlignment` derived boolean that checks whether any configured budget has a reset duration supported by `supportsCalendarAlignment`.
- Replaced the previous condition (`watchedBudgets.length > 0`) with `showCalendarAlignment` to control rendering of the calendar alignment toggle.
- Updated the form submission payload so that `calendar_aligned` is only set to `true` when at least one budget actually supports calendar alignment — preventing the flag from being submitted for incompatible budget configurations.

## Type of change

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

## Affected areas

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

## How to test

1. Navigate to a provider's governance settings in the UI.
2. Add a budget with a reset duration that does **not** support calendar alignment (e.g., hourly). Verify the calendar alignment toggle does **not** appear.
3. Add or change a budget to use a calendar-alignable period (e.g., daily, weekly, monthly, yearly). Verify the toggle **does** appear.
4. Enable the toggle and save. Confirm `calendar_aligned: true` is included in the submitted payload.
5. Remove all calendar-alignable budgets and save. Confirm `calendar_aligned` is not set to `true` in the payload.

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

## Screenshots/Recordings

_Before:_ Calendar alignment toggle appears whenever any budget is present, regardless of reset period.

_After:_ Calendar alignment toggle only appears when at least one budget uses a day/week/month/year reset period.

## Breaking changes

- [x] No

## Related issues

## Security considerations

None.

## 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
…hq#4725)

## Summary

Fixes a bug where updating or deleting provider-level governance for a custom provider whose name contains a space (e.g. `"OpenRouter Base"`) would return a 404. The UI percent-encodes the provider name in the URL path (`OpenRouter%20Base`), but the handler was comparing the raw encoded string directly against the stored provider name, causing the lookup to fail. Closes maximhq#4689

## Changes

- `updateProviderGovernance` and `deleteProviderGovernance` now call `url.PathUnescape` on the `provider_name` path parameter before using it, matching the decoded name against what is stored in the config store.
- Returns a `400` if the path parameter contains an invalid percent-encoding sequence.
- Added a regression test (`TestProviderGovernance_DecodesEncodedProviderName`) that seeds a provider with a space in its name, issues a PUT and DELETE using the percent-encoded path param, and asserts both succeed and persist correctly.
- Added a guard test (`TestProviderGovernance_UnknownProviderStill404`) to confirm that a genuinely unknown provider still returns 404 after the decode change.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./transports/bifrost-http/handlers/... -run TestProviderGovernance
```

Expected output: all three `TestProviderGovernance_*` tests pass. Specifically:

- `TestProviderGovernance_DecodesEncodedProviderName` — PUT and DELETE with `OpenRouter%20Base` return `200`.
- `TestProviderGovernance_UnknownProviderStill404` — PUT with an unknown encoded name returns `404`.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

- Resolves maximhq#4689

## Security considerations

`url.PathUnescape` is used rather than `url.QueryUnescape` to correctly handle path-encoded characters. Invalid encoding sequences are rejected with a `400` rather than passed through, preventing malformed input from reaching the config store.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
… (maximhq#4568)

Signed-off-by: Akshay Deo <akshay@akshaydeo.com>
Co-authored-by: Akshay Deo <akshay@akshaydeo.com>
* Fix mcp reconnect failure on startup

* test: assert failed MCP client cleanup

---------

Co-authored-by: Gowtham <692171+HackToHell@users.noreply.github.com>
…put items (maximhq#4121)

* fix(responses): preserve codex tool_search_call/tool_search_output input items

Bifrost's Responses input deserializer rejected codex's tool-search follow-up
request with HTTP 400 "openai responses request input is neither a string nor an
array of responses messages", which hung/failed the agent turn. The fix teaches
ResponsesMessage about the two tool_search item types and round-trips them
verbatim. Background, since tool_search is non-obvious:

How codex's tool_search works (the path that hits this bug)
-----------------------------------------------------------
codex normally sends every MCP tool inline in the request `tools[]` as
`{type:"function", ...}`. But when a model's catalog has
`supports_search_tool: true` AND the tool count crosses
DIRECT_MCP_TOOL_EXPOSURE_THRESHOLD (= 100) — e.g. an agent wired to several MCP
servers — codex stops sending them inline and "defers" them behind a discovery
tool:
  should_defer = supports_search_tool && (ToolSearchAlwaysDeferMcpTools || n >= 100)

The deferred flow is a two-request round-trip:

  1. Request 1: codex hides the deferred tools and instead declares one tool:
       {"type":"tool_search","execution":"client","description":"...",
        "parameters":{query, limit}}
     `execution:"client"` means the model does NOT run the search — codex does.

  2. The model emits a `tool_search_call` with `arguments` = {query, limit}.

  3. codex runs the search CLIENT-SIDE: a BM25 index over the deferred tool
     metadata (codex's ToolSearchHandler, core/src/tools/handlers/tool_search.rs,
     using the `bm25` crate). It picks the top-N matching tools.

  4. Request 2 (follow-up): codex appends two items to `input[]`:
       - {"type":"tool_search_call",   "call_id":..., "execution":"client",
          "arguments":{...}}
       - {"type":"tool_search_output", "call_id":..., "status":"completed",
          "execution":"client", "tools":[ {type:"function", ...the matches} ]}
     and also surfaces the discovered tools in `tools[]`. The model can now call
     them. This repeats as the model needs more tools.

Root cause
----------
ResponsesMessage (the element type of the Responses `input` array AND the
response `Output` array) doesn't model `tool_search_call` / `tool_search_output`:

  - The call's `arguments` is a JSON OBJECT, whereas function_call's `arguments`
    is a JSON STRING. So it cannot decode into ResponsesToolMessage.Arguments
    (*string) -> sonic.Unmarshal of the whole []ResponsesMessage errors ->
    OpenAIResponsesRequestInput.UnmarshalJSON falls through to the "neither a
    string nor an array" 400. The entire request dies before reaching OpenAI.
  - The output's `tools` array is also unmodeled (would be dropped/mangled,
    which OpenAI then rejects with "Missing input[N].tools[0].type").

OpenAI's Responses API supports both items natively (verified end-to-end against
the gateway: the tool_search tool spec is accepted and echoed; OpenAI validates
arguments-as-object and tools[].type). So this is purely a Bifrost modelling gap,
in the same family as the tool-type allowlist that already lists
ResponsesToolTypeToolSearch / ResponsesToolTypeNamespace — just a different code
path (input-item deserialization vs the request tools[] allowlist).

Fix
---
Add ResponsesMessageTypeToolSearchCall / ResponsesMessageTypeToolSearchOutput and
give ResponsesMessage custom (Un)MarshalJSON that preserves these two item types
verbatim (original bytes in, original bytes out), so the object `arguments` and
the `tools` array survive intact. Every other item type defers to the default
struct (de)coding, unchanged. One change covers both directions because request
input and response Output are both []ResponsesMessage.

Impact: unblocks codex tool-search deferral (multi-MCP-server / >=100-tool agents)
through Bifrost. Verified with a round-trip test reproducing the exact follow-up
payload, plus the existing providers/openai and schemas suites (no regressions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(responses): reset ResponsesMessage receiver in UnmarshalJSON

Clear the receiver at the top of ResponsesMessage.UnmarshalJSON so a reused
instance never retains a stale rawToolSearch (or other field) from a prior
decode. Without this, unmarshalling a tool_search item and then a normal
message into the same value would leave the preserved bytes in place, and
MarshalJSON would re-emit them. Not reachable via the array-decode path (each
element starts zero), but a cheap, defensive correctness fix.

Addresses CodeRabbit review on PR maximhq#4121.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(openapi): correct prompt_cache_retention enum to in_memory

The chat schema declared the enum as [in-memory, 24h], but OpenAI's
actual accepted values are in_memory (underscore) and 24h. The hyphenated
form was a typo from when the enum was first added and never matched
OpenAI, so spec-generated clients produced Literal['in-memory', '24h']
and rejected the valid value with a pydantic literal_error.

The Go runtime treats prompt_cache_retention as a pass-through *string,
so no behavior changes — only the spec enum, the regenerated openapi.json,
and the doc comment are corrected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Signed-off-by: Akshay Deo <akshay@akshaydeo.com>
Co-authored-by: Suresh Kumar Ponnusamy <suresh@atomicwork.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Akshay Deo <akshay@akshaydeo.com>
@Prateek-Gupta001
Prateek-Gupta001 requested a review from a team as a code owner June 29, 2026 08:07
@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review. (119 files found, 100 file limit)

@CLAassistant

CLAassistant commented Jun 29, 2026

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 all sign our Contributor License Agreement before we can accept your contribution.
7 out of 9 committers have signed the CLA.

✅ impoiler
✅ akshaydeo
✅ G-XD
✅ roroghost17
✅ raghu-nandan-bs
✅ Prateek-Gupta001
✅ HackToHell
❌ TejasGhatte
❌ Pratham-Mishra04
You have signed the CLA already but the status is still pending? Let us recheck it.

## Summary

Fixes a bug in the Vertex provider where the code path for handling Gemini/Gemma model families was duplicated, with the non-streaming branch incorrectly using `ToGeminiChatCompletionRequest` (without image URL scheme support) while the streaming branch used `ToGeminiChatCompletionRequestWithImageURLSchemes`. This consolidates the logic so both paths use the image URL scheme-aware converter.

## Changes

- Replaced `ToGeminiChatCompletionRequest` with `ToGeminiChatCompletionRequestWithImageURLSchemes` in the non-streaming Gemini/Gemma branch, making it consistent with the streaming branch
- Removed the duplicate non-streaming Gemini/Gemma and OpenAI handler blocks that had been incorrectly separated from the streaming path, consolidating them into a single unified code path

## Type of change

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

## Affected areas

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

## How to test

Send a chat completion request to the Vertex provider using a Gemini or Gemma model with image URL content. Verify that image URLs are correctly processed in both streaming and non-streaming modes.

```sh
go test ./core/providers/vertex/...
```

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None.

## 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 Jun 29, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for AWS Bedrock Mantle across provider setup, routing, and documentation.
    • Introduced dynamic worker scaling for better provider throughput and responsiveness.
    • Expanded image URL handling to support additional schemes where applicable.
  • Bug Fixes

    • Improved handling of streaming, tool-search, transcription, and request/response edge cases.
    • Fixed provider key updates and governance paths for more reliable configuration changes.
  • UI Improvements

    • Added clearer label truncation in several workspace views and improved tag list collapsing behavior.

Walkthrough

This PR introduces the AWS Bedrock Mantle provider end-to-end (schema, implementation, UI, persistence, docs), implements dynamic per-provider worker pool autoscaling, refactors the OpenAI/Anthropic request pipelines to centralize bearer auth via BearerAuthHeader and add a BodySigner hook, adds GCS (gs://) image URL support for Gemini/Vertex, and includes several independent fixes (MCP list_tools failure propagation, Responses tool_search passthrough, transcription ExtraParams forwarding, hybrid logstore token reconstruction, governance URL decoding, in_memory enum correction) plus UI improvements (collapsible TagInput, TruncatedLabel, safe URL parsers).

Changes

BedrockMantle Provider

Layer / File(s) Summary
Schema constants and key config
core/schemas/bifrost.go, core/schemas/account.go, core/schemas/utils.go, core/utils.go
Adds BedrockMantle ModelProvider constant and StandardProviders entry; introduces BedrockMantleKeyConfig struct; adds IsOpenAIModel/IsOpenAIModelFamily; extends dynamicallyConfigurableProviders, CanProviderKeyValueBeEmpty, validateKey.
Provider implementation
core/providers/bedrockmantle/bedrockmantle.go, core/providers/bedrockmantle/utils.go, core/providers/bedrockmantle/bedrockmantle_test.go
New provider that routes Claude-family requests to the Anthropic Messages API and others to OpenAI-compatible endpoints; selects SigV4 signing via signer closure or Bearer auth per request; implements ListModels, Chat, Responses (streaming/non-streaming); stubs unsupported operations; integration test harness with AWS credential guard.
Bedrock provider Mantle routing and signing refactor
core/providers/bedrock/mantle.go, core/providers/bedrock/bedrock.go, core/providers/bedrock/mantle_test.go, core/providers/bedrock/...test.go
Makes isMantleModel context-aware via IsOpenAIModelFamily; renames mantleURLmantleOpenAIURL; exports SignMantleV4Headers; rewrites Mantle handlers to delegate signing to OpenAI handlers via signer closures; unifies signAWSRequest to accept *BedrockKeyConfig; updates all S3/batch signing call sites and streaming tests.
Anthropic provider BedrockMantle feature flags
core/providers/anthropic/types.go, core/providers/anthropic/chat.go, core/providers/anthropic/responses.go, core/bifrost.go, transports/bifrost-http/integrations/anthropic.go
Adds ProviderFeatures[schemas.BedrockMantle]; extends structured-output tool conversion to BedrockMantle; treats BedrockMantle as native in passthrough gating; classifies BedrockMantle Claude models as isClaudeModel; wires createBaseProvider.
Framework persistence (migration, hooks, transport)
framework/configstore/migrations.go, framework/configstore/tables/key.go, framework/configstore/clientconfig.go, transports/bifrost-http/handlers/provider_keys.go, transports/bifrost-http/lib/config.go
Adds add_bedrock_mantle_key_columns DB migration; extends TableKey with seven BedrockMantle* SecretVar columns and BeforeSave/AfterFind encrypt/decrypt/reconstruct hooks; redacts Mantle keys; extends mergeUpdatedKey and legacy hash computation.
UI forms and constants
ui/lib/types/config.ts, ui/lib/types/schemas.ts, ui/lib/schemas/providerForm.ts, ui/app/workspace/providers/fragments/apiKeysFormFragment.tsx, ui/app/workspace/providers/fragments/betaHeadersFormFragment.tsx, ui/lib/constants/*, ui/app/workspace/providers/...
Adds BedrockMantleKeyConfig type and Zod schemas with three-mode auth validation; renders tabbed auth UI in apiKeysFormFragment; updates beta headers, provider config sheet, key form submission, icons, logs/config constants.
Config schema and E2E fixtures
transports/config.schema.json, tests/e2e/api/provider-capabilities.json, tests/e2e/api/provider_config/bifrost-v1-bedrock-mantle.postman_environment.json, tests/e2e/api/runners/*
Adds bedrock_mantle_key/provider_with_bedrock_mantle_config JSON schema defs; extends semantic_cache and custom provider type enums; adds E2E capability matrix, Postman environment, filter partition, and harness-monitor underscore regex fix.

Dynamic Worker Autoscaling

Layer / File(s) Summary
Schema extension and validation
core/schemas/provider.go, core/utils.go
Extends ConcurrencyAndBufferSize with DynamicScaling, ScalingInterval (ms↔Duration JSON), MinWorkers, MaxWorkers, ScaleUpThreshold, ScaleDownThreshold; adds ValidateDynamicScalingConfig with constraint checks and interval clamping.
Autoscaler goroutine and worker cooperation
core/bifrost.go
Adds quit chan struct{} and ActiveWorkers atomic.Int32 to ProviderQueue; implements DynamicWorkerScaling that samples queue utilization and enqueues/drains kill tokens; updates requestWorker to decrement ActiveWorkers and handle kill tokens (ignoring them during shutdown); wires into prepareProvider and UpdateProvider.
Unit tests
core/bifrost_test.go
Adds TestDynamicWorkerScalingDown (polls to MinWorkers), TestDynamicWorkerScalingUp (saturates queue, polls to MaxWorkers), and TestDynamicWorkerScalingConfig (table-driven constraint and interval-default validation).

OpenAI Auth Refactor, Anthropic Request Builder, and BodySigner

Layer / File(s) Summary
BodySigner type and BearerAuthHeader
core/providers/utils/bodysigner.go, core/providers/openai/openai.go, core/providers/openai/large_payload.go
Defines BodySigner func([]byte) (map[string]string, *BifrostError); adds BearerAuthHeader(key) helper; refactors handleOpenAILargePayloadPassthrough to accept authHeader map[string]string.
OpenAI handler signature refactor
core/providers/openai/openai.go
Refactors all HandleOpenAI* exported functions to accept authHeader map[string]string and optional signer providerUtils.BodySigner; invokes signer before body send; updates wrapper call sites.
Anthropic request builder AnthropicProviderRequestDefaultsMap
core/providers/anthropic/requestbuilder.go, core/providers/anthropic/requestbuilder_test.go
Moves per-provider request-shaping flags into AnthropicProviderRequestDefaults keyed by ModelProvider; removes corresponding fields from AnthropicRequestBuildConfig (replaces Deployment with Model); updates test call sites.
Anthropic provider centralized request flow
core/providers/anthropic/anthropic.go, core/providers/anthropic/responses.go, core/providers/anthropic/utils.go, core/providers/vertex/utils.go, core/providers/vertex/types.go
Introduces shared anthropicRequestHeaders/completeRequest helpers; refactors all Anthropic entrypoints to use centralized builders; exports pool helpers; adds AddMissingBetaHeadersToContext; removes now-redundant Vertex/Azure local helpers.
Azure provider delegation
core/providers/azure/azure.go, core/providers/azure/utils.go
Removes local completeRequest; all Azure methods now dispatch to anthropic.HandleAnthropic* or openai.HandleOpenAI* shared handlers.
Vertex Anthropic builder integration
core/providers/vertex/vertex.go, core/providers/vertex/utils_test.go, core/providers/vertex/vertex_test.go
Vertex Anthropic paths use centralized builders; adds inlineDocumentURLsResponses; skips inlining on raw passthrough; switches Gemini conversion to WithImageURLSchemes variants; adds GCS URL and unsupported-scheme tests.
All other providers BearerAuthHeader adoption
core/providers/cerebras/..., core/providers/fireworks/..., core/providers/groq/..., core/providers/huggingface/..., core/providers/mistral/..., core/providers/nebius/..., core/providers/ollama/..., core/providers/openrouter/..., core/providers/parasail/..., core/providers/perplexity/..., core/providers/sgl/..., core/providers/vllm/..., core/providers/xai/..., core/providers/opencode/...
Removes local authHeader map construction across 14 providers; passes openai.BearerAuthHeader(key) directly into shared handlers.

Gemini/Vertex GCS Image URL Allowlist

Layer / File(s) Summary
SanitizeImageURLWithAllowedSchemes
core/schemas/utils.go, core/schemas/utils_test.go
Refactors URL sanitization to support configurable non-data URL scheme allowlists; rejects disallowed schemes with descriptive errors; adds tests.
Gemini allowlist propagation
core/providers/gemini/utils.go, core/providers/gemini/chat.go, core/providers/gemini/responses.go, core/providers/gemini/videos.go, core/providers/gemini/batch.go, core/providers/gemini/gemini_test.go
Threads allowedImageURLSchemes through all Gemini conversion paths; fixes batch conversion error handling; adds tests rejecting gs:// for default Gemini and accepting it for Vertex.

Independent Bug Fixes

Layer / File(s) Summary
MCP list_tools failure as connection error
core/mcp/clientmanager.go, core/internal/mcptests/connect_ping_listtools_test.go
connectToMCPClient tears down the connection and returns an error when list_tools fails; test updated to assert AddClient failure.
Responses tool_search verbatim passthrough
core/schemas/responses.go, core/providers/openai/tool_search_roundtrip_test.go
Adds ResponsesMessageTypeToolSearchCall/Output; stores and re-emits raw JSON bytes for tool_search items to preserve object-typed arguments; adds round-trip test.
Transcription ExtraParams → multipart form
core/providers/openai/transcription.go, core/providers/openai/transcription_test.go, transports/bifrost-http/integrations/openai.go
Forwards ExtraParams into multipart fields (sorted, JSON-encoded for non-strings); parses chunking_strategy from multipart input; tests for string and object variants.
Hybrid logstore token reconstruction
framework/logstore/tables.go, framework/logstore/tables_test.go, framework/logstore/hybrid_test.go
DeserializeFields rebuilds TokenUsageParsed from denormalized token columns when TokenUsage JSON is missing; unit and integration tests.
Governance URL-decode provider_name
transports/bifrost-http/handlers/governance.go, transports/bifrost-http/handlers/governance_test.go
url.PathUnescape decodes the provider_name path param; returns HTTP 400 on malformed encoding; tests cover encoded names, 404 for unknown providers, 400 for bad encoding.
prompt_cache_retention enum correction
core/schemas/chatcompletions.go, docs/openapi/openapi.json, docs/openapi/schemas/inference/chat.yaml
Renames enum value in-memoryin_memory across schema, OpenAPI spec, and comment.

UI Improvements

Layer / File(s) Summary
TruncatedLabel component
ui/components/ui/truncatedLabel.tsx, ui/app/workspace/providers/page.tsx, ui/components/filters/logsFilterSidebar.tsx, ui/components/filters/mcpFilterSidebar.tsx
New component uses ResizeObserver to detect overflow and shows a tooltip when truncated; replaces inline truncation in provider sidebar and filter sidebars.
TagInput collapsible tags
ui/components/ui/tagInput.tsx, ui/app/workspace/complexity-router/page.tsx
Adds collapsedTagLimit/expandButtonTestId props; renders gradient-overlaid collapsed layout with expand/collapse toggle; adopted in complexity-router with KEYWORD_COLLAPSED_LIMIT.
Safe array URL query parsers
ui/lib/queryParamsParser.ts, ui/lib/queryParamsParser.test.ts, ui/app/workspace/logs/page.tsx
Adds parseAsSafeArrayOf derived from parseAsSafeString; replaces parseAsArrayOf(parseAsString) on all log filter fields; adds round-trip tests for ://-containing model names.
Calendar alignment governance fix
ui/app/workspace/providers/fragments/governanceFormFragment.tsx, ui/app/workspace/audit-logs/page.tsx
Derives showCalendarAlignment from configured budgets with alignable durations; resets toggle via effect when unavailable; only submits calendar_aligned when applicable; minor audit logs layout fix.

Docs, Changelogs, and CI

Layer / File(s) Summary
BedrockMantle docs
docs/providers/supported-providers/bedrock-mantle.mdx, docs/providers/supported-providers/overview.mdx, docs/deployment-guides/config-json/providers.mdx, docs/docs.json
New provider page covering routing, auth modes, and usage; adds support matrix row; deployment guide section; navigation entries.
Changelogs and version bumps
docs/changelogs/ent-v1.5.0.mdx, docs/changelogs/helm-v2.1.25.mdx, core/changelog.md, framework/changelog.md, helm-charts/bifrost/README.md, tests/cmd/*/go.mod
Enterprise v1.5.0 and Helm v2.1.25 changelogs; core/framework changelog entries; Helm README version badge; bumps bifrost/core to v1.6.0 in three test go.mod files.
CI egress allowlists
.github/workflows/release-pipeline.yml
Adds 127.0.0.1:8000/8080, getbifrost.ai:443, and www.getbifrost.ai:443 to test-cost-accuracy and test-load-performance harden-runner endpoints.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant BedrockMantleProvider
    participant mantleSigner
    participant AnthropicHandler
    participant OpenAIHandler

    Client->>BedrockMantleProvider: ChatCompletion(ctx, key, request)
    BedrockMantleProvider->>BedrockMantleProvider: resolveRegion(ctx, key, model)
    BedrockMantleProvider->>BedrockMantleProvider: IsAnthropicModel(model)?
    alt Claude family
        BedrockMantleProvider->>mantleSigner: key.Value empty → build SigV4 signer closure
        BedrockMantleProvider->>AnthropicHandler: HandleAnthropicChatCompletionRequest(cfg, signer)
        AnthropicHandler->>mantleSigner: signer(jsonBody)
        mantleSigner-->>AnthropicHandler: signed headers (Authorization, X-Amz-*)
        AnthropicHandler-->>BedrockMantleProvider: BifrostChatResponse
    else OpenAI family / Gemma
        BedrockMantleProvider->>OpenAIHandler: HandleOpenAIChatCompletionRequest(authHeader, signer)
        OpenAIHandler-->>BedrockMantleProvider: BifrostChatResponse
    end
    BedrockMantleProvider-->>Client: BifrostChatResponse
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~180 minutes

Possibly related PRs

  • maximhq/bifrost#4736: Introduces BedrockMantle provider wiring in core/bifrost.go and Anthropic passthrough gating for schemas.BedrockMantle, directly overlapping with this PR's provider registration and passthrough logic.
  • maximhq/bifrost#4735: Introduces the BodySigner callback and threads the optional signer parameter through OpenAI/Anthropic shared request and streaming handlers, which this PR builds upon for Mantle SigV4 signing.
  • maximhq/bifrost#4568: Adds SanitizeImageURLWithAllowedSchemes and threads the gs:// allowlist through Gemini/Vertex conversion paths, which this PR consolidates and completes.

Suggested reviewers

  • akshaydeo
  • danpiths
  • roroghost17

Poem

🐇 A rabbit hops through provider land,
New Mantle routes at its command.
Workers scale up, then scale back down,
Bearer headers flow without a frown.
GCS images pass with glee —
v1.6.0 ships, wild and free! 🚀

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes many unrelated Bedrock Mantle, Gemini, OpenAI, UI, docs, and transport changes beyond dynamic autoscaling. Split the autoscaler work from the unrelated provider/UI/docs changes, or justify those additions in the linked issue scope.
Docstring Coverage ⚠️ Warning Docstring coverage is 62.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly describes the main change: dynamic worker autoscaling.
Description check ✅ Passed The description follows the template well and covers summary, changes, testing, breaking changes, security, and issue linkage.
Linked Issues check ✅ Passed The worker-pool autoscaling objective is implemented with config, scaling logic, and tests; buffer resizing is explicitly out of scope.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

## Summary

Consolidates the two separate `UnmarshalJSON` implementations on `ResponsesMessage` into a single method that handles both the verbatim `tool_search` preservation and the `arguments` normalization logic. Previously, the file contained a duplicate `UnmarshalJSON` definition — the first handled `tool_search` items and fell back to a plain `sonic.Unmarshal`, while the second (the correct one) handled argument normalization. The duplicate caused the normalization path to be unreachable for non-`tool_search` items, meaning `tool_search_call` items with object-typed `arguments` would silently fail mid-stream and hang streaming clients.

## Changes

- Removed the redundant first `UnmarshalJSON` that short-circuited to `sonic.Unmarshal` without normalizing `arguments`, leaving only the correct implementation that handles both the `rawToolSearch` early-return and the `arguments` object-to-string normalization.
- Relocated `MarshalJSON` to follow `UnmarshalJSON` for logical grouping.
- The fix ensures `tool_search_call` items whose `arguments` field is a JSON object (e.g. `{}` while in-progress, `{"query":"...","limit":10}` when completed) are correctly stringified into the `*string` field expected by `ResponsesToolMessage`, preventing decode failures that previously dropped items silently.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./core/schemas/...
```

Validate by sending a request that triggers `tool_search_call` streaming events and confirming that items with both `{}` (in-progress) and `{"query":"...","limit":10}` (completed) `arguments` values are decoded without error and do not hang the streaming client.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None.

## 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 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: 10

Caution

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

⚠️ Outside diff range comments (1)
core/bifrost.go (1)

3533-3608: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Validate autoscaling config on UpdateProvider before using it.

This hot-reload path bypasses ValidateDynamicScalingConfig, unlike prepareProvider. A reload with ScalingInterval <= 0 will panic in time.NewTicker, and a negative MaxWorkers will panic when newPq.quit is allocated. Apply the same validate/clamp/disable step here before touching DynamicScaling, MaxWorkers, or ScalingInterval.

Suggested change
 	// Step 2: Create new ProviderQueue and wait group with updated settings.
+	providerConfig.ConcurrencyAndBufferSize.DynamicScaling =
+		ValidateDynamicScalingConfig(providerConfig, providerKey, bifrost.logger)
+
 	newPq := &ProviderQueue{
 		queue:      make(chan *ChannelMessage, providerConfig.ConcurrencyAndBufferSize.BufferSize),
 		done:       make(chan struct{}),
 		signalOnce: sync.Once{},
 	}
🤖 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/bifrost.go` around lines 3533 - 3608, Validate and normalize the
autoscaling settings in UpdateProvider before using DynamicScaling, MaxWorkers,
or ScalingInterval, since this hot-reload path currently bypasses the same
checks used by prepareProvider. Apply the existing
ValidateDynamicScalingConfig-style clamping/disabling logic on the
providerConfig.ConcurrencyAndBufferSize values before creating newPq, allocating
newPq.quit, or starting DynamicWorkerScaling, so invalid reload values cannot
trigger ticker or channel panics.
🧹 Nitpick comments (1)
core/schemas/provider.go (1)

230-238: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix comment typos and improve clarity.

  • Line 230: "reponses" → "responses"
  • Line 232: Rephrase to "Enable dynamic worker pool scaling for this provider"
  • Line 233: "nesscary" → "necessary", "go routine" → "goroutine"
  • Line 234-235: Use "Number" instead of "No." for consistency
🤖 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/provider.go` around lines 230 - 238, The struct field comments
in provider schema contain typos and inconsistent wording that should be cleaned
up for clarity. Update the comments on Concurrency, DynamicScaling,
ScalingInterval, MinWorkers, MaxWorkers, ScaleUpThreshold, and
ScaleDownThreshold to use correct spelling (responses, necessary, goroutine) and
consistent phrasing, especially the DynamicScaling description and the “Number
of workers” wording. Keep the meaning the same while making the comment text
professional and easy to read.
🤖 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/bifrost_test.go`:
- Around line 3057-3094: The scaling test reuses a single mutable ChannelMessage
across many queue submissions, which can race because requestWorker mutates
per-request state on the message and its context. Update the enqueue loop in the
test to create a fresh ChannelMessage for each send while still deriving each
one from the same cancelable parent context (reqCtx/cancelReq), and keep the
existing cleanup/shutdown logic around testDone and cancelReq.

In `@docs/docs.json`:
- Around line 488-494: The Google Workspace navigation entry is still pointing
to the legacy redirect source instead of the renamed OIDC page. Update the page
reference in docs/docs.json under the Google Workspace group to use the new
enterprise/setting-up-google-workspace/oidc slug so the nav matches the current
page layout and stays aligned with the renamed Mintlify page.

In `@docs/enterprise/setting-up-entra/oidc.mdx`:
- Around line 203-217: The manifest-based path in the OIDC setup is incomplete:
the note references a nonexistent later step and does not show how to configure
the required roles claim. Update the guidance around the Token configuration /
Manifest editor flow to either remove the shortcut or explicitly document the
manifest settings, including the `optionalClaims.idToken` `roles` entry and any
related claim/version fields, so readers can follow the manifest route without
missing the `roles` claim. Use the existing OIDC setup section and the manifest
note as the anchors for this fix.

In `@docs/enterprise/setting-up-entra/scim.mdx`:
- Line 6: The intro and related SCIM sections overstate immediate “real-time”
propagation, which conflicts with the later cycle-based timing details. Update
the affected prose in scim.mdx around the SCIM overview and the sections
referenced by the comment to describe Entra sync as incremental/cycle-based, and
make the wording consistent with the documented ~40 minute cycles and initial
sync delay. Use the SCIM overview text and the later timing explanation as the
source of truth, and keep terminology aligned with the provider behavior.

In `@docs/enterprise/setting-up-generic-oidc/scim.mdx`:
- Line 6: The SCIM overview text in the docs overstates provider behavior by
implying real-time push semantics for all compatible IdPs. Update the wording in
the SCIM guide to describe cycle-based provisioning unless the behavior is
guaranteed across all supported providers, and keep the description aligned with
the provider-specific behavior noted later in the same document. Refer to the
SCIM intro copy in the generic OIDC SCIM page and ensure it matches the
documented provisioning flow used by the relevant SCIM provider sections.

In `@docs/enterprise/setting-up-google-workspace/scim.mdx`:
- Around line 2-6: The page metadata and intro in scim.mdx are misleading
because they describe real-time SCIM provisioning, but the documented behavior
is Google Workspace reconciliation via Directory API and session refreshes.
Update the title, description, and opening copy in the SCIM page to match the
actual implementation, and reframe it around Google Workspace provisioning or
SCIM-equivalent sync rather than a true SCIM endpoint. Use the existing section
content in the page to align the wording with the implemented sync flow.
- Around line 132-135: The troubleshooting note in the Google Workspace SCIM
docs uses the wrong scope name for group membership syncing. In the “Group
memberships not syncing” guidance, replace the Microsoft Graph permission
reference with the Google Directory API Domain-Wide Delegation scope used by
this integration, and keep the wording aligned with the existing SCIM/provider
setup guidance so admins verify the correct authorization in Google Admin
Console.

In `@docs/enterprise/setting-up-okta/scim.mdx`:
- Around line 169-172: The Okta SCIM mapping example is inconsistent between the
body text and the figure caption, so update the example in the surrounding prose
and the Frame caption to use the same source field. In the section describing
the attribute mapping, align the `user.employeeNumber`/`user.employeeID`
reference with the actual example shown, or explicitly note that `employeeID` is
a custom Okta profile field. Make the wording in the SCIM mapping instructions
and the caption for the employeeID image match exactly so the flow stays
unambiguous.

In `@docs/enterprise/setting-up-zitadel/oidc.mdx`:
- Around line 68-87: The Step 2 content in the Zitadel OIDC guide is marked
optional, but it also contains the only instruction to capture the Project ID
that later setup requires unconditionally. Update the wording around the Step 2
section and the “Note the Project ID” guidance so readers are told to record it
even if they skip role-claim setup, while keeping the optional note limited to
the role-claim-specific parts of the step. Use the existing Step/Note/Frame
structure in oidc.mdx to keep the flow consistent with the later provider
configuration steps.

In `@docs/enterprise/user-provisioning.mdx`:
- Around line 46-47: The Google Workspace card is pointing to a route that does
not exist in the current docs structure. Update the Card in the user
provisioning page so its href matches the actual Google Workspace guide
entrypoint, using the existing OIDC/SCIM docs path pattern rather than the
outdated setting-up-google-workspace link.

---

Outside diff comments:
In `@core/bifrost.go`:
- Around line 3533-3608: Validate and normalize the autoscaling settings in
UpdateProvider before using DynamicScaling, MaxWorkers, or ScalingInterval,
since this hot-reload path currently bypasses the same checks used by
prepareProvider. Apply the existing ValidateDynamicScalingConfig-style
clamping/disabling logic on the providerConfig.ConcurrencyAndBufferSize values
before creating newPq, allocating newPq.quit, or starting DynamicWorkerScaling,
so invalid reload values cannot trigger ticker or channel panics.

---

Nitpick comments:
In `@core/schemas/provider.go`:
- Around line 230-238: The struct field comments in provider schema contain
typos and inconsistent wording that should be cleaned up for clarity. Update the
comments on Concurrency, DynamicScaling, ScalingInterval, MinWorkers,
MaxWorkers, ScaleUpThreshold, and ScaleDownThreshold to use correct spelling
(responses, necessary, goroutine) and consistent phrasing, especially the
DynamicScaling description and the “Number of workers” wording. Keep the meaning
the same while making the comment text professional and easy to read.
🪄 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: c16e0618-49bc-4b90-a638-25e291c43d41

📥 Commits

Reviewing files that changed from the base of the PR and between 87110ad and 1bb215a.

⛔ Files ignored due to path filters (145)
  • docs/media/auth0-card.svg is excluded by !**/*.svg
  • docs/media/auth0-icon.svg is excluded by !**/*.svg
  • docs/media/keycloak-card.svg is excluded by !**/*.svg
  • docs/media/keycloak-icon.svg is excluded by !**/*.svg
  • docs/media/okta-card.svg is excluded by !**/*.svg
  • docs/media/okta-icon.svg is excluded by !**/*.svg
  • docs/media/ui-provider-key-vault-ref.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/auth0-action-code.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/auth0-action-flow.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/auth0-actions-triggers.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/auth0-app-credentials.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/auth0-app-settings.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/auth0-applications.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/auth0-callback-urls.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/auth0-m2m-credentials.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/bifrost-attribute-mapping.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/bifrost-choose-provider.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/bifrost-discover-claims.png is excluded by !**/*.png
  • docs/media/user-provisioning/auth0/bifrost-review-enable.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-api-permissions.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-app-information.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-bifrost-attribute-mappings.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-bifrost-choose-provider.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-bifrost-discover-claims.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-create-app-roles.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-create-client-secret.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-enable-assignment.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-enterprise-applications-list.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-redirect-uri-config.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-register-application.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-token-configuration.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra-user-assignments.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/bifrost-attribute-setup.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/bifrost-discover-claims.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/bifrost-provider-selection.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-api-permissions.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-app-overview.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-app-roles.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-client-secret.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-enable-assignment.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-enterprise-apps-list.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-redirect-uri.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-register-app.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-token-configuration.png is excluded by !**/*.png
  • docs/media/user-provisioning/entra/entra-oidc-user-assignments.png is excluded by !**/*.png
  • docs/media/user-provisioning/generic-oidc/bifrost-attribute-setup.png is excluded by !**/*.png
  • docs/media/user-provisioning/generic-oidc/bifrost-discover-claims.png is excluded by !**/*.png
  • docs/media/user-provisioning/generic-oidc/bifrost-enable-scim.png is excluded by !**/*.png
  • docs/media/user-provisioning/generic-oidc/bifrost-provider-config.png is excluded by !**/*.png
  • docs/media/user-provisioning/generic-oidc/bifrost-provider-dashboard.png is excluded by !**/*.png
  • docs/media/user-provisioning/generic-oidc/bifrost-provider-selection.png is excluded by !**/*.png
  • docs/media/user-provisioning/generic-oidc/bifrost-review-enable.png is excluded by !**/*.png
  • docs/media/user-provisioning/generic-oidc/bifrost-scim-token-dialog.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/bifrost-keycloak-attribute-mapping.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/bifrost-keycloak-discover-claims.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/bifrost-keycloak-provider-config.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/bifrost-sync-users.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/bifrost-user-provisioning.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/bifrost-users-page.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-client-config.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-client-creation.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-client-scopes.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-configure-new-mapper.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-create-client.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-groups-mapping.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-login-settings.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-realm-role-config.png is excluded by !**/*.png
  • docs/media/user-provisioning/keycloak/keycloak-realm-role-mapping.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-api-token-created.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-app-configuration.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-app-group-claim-setup.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-app-integration-main-page.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-assign-custom-role.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-assign-users.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-authorization-server.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-claim-addition.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-create-app.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-create-groups.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-create-token-form.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-custom-attribute-creation.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-form.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-group-claim-mapping.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-group-configuration.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-groups-created.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-groups-page.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-org-server-group-in-claims.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-profile-editor-screen.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-scim-assignments.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-scim-configure-api.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-scim-configure-provisioning.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-scim-profile-editor-add-attribute.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-scim-profile-editor-mapping.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-scim-profile-editor-page.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-scim-push-groups.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-select-auth-server.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-tokens-screen.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta-user-type-creation.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-attribute-setup.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-custom-user-attribute-scim.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-discover-claims.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-enable-scim.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-okta-provider-config.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-provider-selection.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-provider-setting.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-review-oidc.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/bifrost-scim-provisioning-token-dialog.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-api-custom-claim-oauth.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-api-custom-oauth.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-app-settings-signon.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-browse-app-catalog.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-choose-scim-header-auth.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-custom-attribute-employee-id.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-custom-attribute-mapping-employeeid.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-custom-attribute-mapping.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-oidc-api-token.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-oidc-app-settings.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-oidc-applications.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-oidc-assignments.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-oidc-create-app.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-oidc-credentials.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-oidc-group-assignment.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-profile-editor-add-attribute.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-scim-assignments.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-scim-custom-attribute-mapping-button.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-scim-provisioning-setup.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-scim-provisioning-to-app.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-scim-push-groups-active.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-scim-push-groups-by-rule.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-scim-push-groups.png is excluded by !**/*.png
  • docs/media/user-provisioning/okta/okta-token-claims.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/bifrost-choose-provider.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-attribute-mapping.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-client-id.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-create-app.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-project-roles.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-provider-config.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-redirect-uris.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-return-user-roles.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-review-enable.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-role-assignments.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-service-account-key.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-service-account-role.png is excluded by !**/*.png
  • docs/media/user-provisioning/zitadel/zitadel-token-settings.png is excluded by !**/*.png
  • docs/media/zitadel-card.svg is excluded by !**/*.svg
  • docs/media/zitadel-icon.svg is excluded by !**/*.svg
📒 Files selected for processing (38)
  • .github/workflows/release-pipeline.yml
  • core/bifrost.go
  • core/bifrost_test.go
  • core/schemas/provider.go
  • core/utils.go
  • docs/changelogs/ent-v1.5.0.mdx
  • docs/changelogs/helm-v2.1.25.mdx
  • docs/deployment-guides/config-json.mdx
  • docs/deployment-guides/config-json/secret-management.mdx
  • docs/deployment-guides/helm.mdx
  • docs/deployment-guides/helm/secret-management.mdx
  • docs/docs.json
  • docs/enterprise/clustering.mdx
  • docs/enterprise/secret-management.mdx
  • docs/enterprise/setting-up-auth0/oidc.mdx
  • docs/enterprise/setting-up-entra.mdx
  • docs/enterprise/setting-up-entra/oidc.mdx
  • docs/enterprise/setting-up-entra/scim.mdx
  • docs/enterprise/setting-up-generic-oidc/oidc.mdx
  • docs/enterprise/setting-up-generic-oidc/scim.mdx
  • docs/enterprise/setting-up-google-workspace/oidc.mdx
  • docs/enterprise/setting-up-google-workspace/scim.mdx
  • docs/enterprise/setting-up-keycloak.mdx
  • docs/enterprise/setting-up-keycloak/oidc.mdx
  • docs/enterprise/setting-up-okta.mdx
  • docs/enterprise/setting-up-okta/oidc.mdx
  • docs/enterprise/setting-up-okta/scim.mdx
  • docs/enterprise/setting-up-zitadel.mdx
  • docs/enterprise/setting-up-zitadel/oidc.mdx
  • docs/enterprise/user-provisioning.mdx
  • docs/mcp/auth/headers.mdx
  • docs/openapi/openapi.json
  • docs/openapi/openapi.yaml
  • docs/openapi/paths/management/vault.yaml
  • helm-charts/bifrost/README.md
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seed/go.mod
  • tests/cmd/seedvks/go.mod
💤 Files with no reviewable changes (4)
  • docs/enterprise/setting-up-zitadel.mdx
  • docs/enterprise/setting-up-okta.mdx
  • docs/enterprise/setting-up-keycloak.mdx
  • docs/enterprise/setting-up-entra.mdx

Comment thread core/bifrost_test.go
Comment on lines +3057 to +3094
testDone := make(chan struct{})
reqCtx, cancelReq := context.WithCancel(context.Background())
dummyReq := &ChannelMessage{
Context: schemas.NewBifrostContext(reqCtx, time.Time{}),
Err: make(chan schemas.BifrostError, 1),
Response: make(chan *schemas.BifrostResponse, 1),
}
go func() {

//Using the same dummyReq pauses other workers while they push their errors in the Err chan. This keeps the
//provider queue full and allows us to test our scale up feature. At the end we call cancel to cancel all the
//requests, free our workers and shutdown.
for i := 0; i < test.NumRequests; i++ {
select {
case <-testDone:
return
case pq.queue <- dummyReq:
}
}

}()
time.Sleep(100 * time.Millisecond)

assert.Eventually(t, func() bool {
return int(pq.ActiveWorkers.Load()) == test.MaxWorkers
}, 3*time.Second, 250*time.Millisecond,
"test %q: workers failed to scale up to %d within timeout. Final count: %d",
test.Name, test.MaxWorkers, pq.ActiveWorkers.Load())
close(testDone)
cancelReq()
go func() {
for {
select {
case <-dummyReq.Err:
case <-dummyReq.Response:
}
}
}()

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Queue fresh requests here instead of reusing one ChannelMessage.

This enqueues the same mutable request into the worker pool dozens of times. requestWorker writes per-request state back onto the message/context, so the test can race and turn flaky under concurrency. Create a fresh ChannelMessage per enqueue and share only the cancelable parent context.

As per coding guidelines, Go review should enforce race-safe shared state and deterministic tests.

Suggested change
-				testDone := make(chan struct{})
-				reqCtx, cancelReq := context.WithCancel(context.Background())
-				dummyReq := &ChannelMessage{
-					Context:  schemas.NewBifrostContext(reqCtx, time.Time{}),
-					Err:      make(chan schemas.BifrostError, 1),
-					Response: make(chan *schemas.BifrostResponse, 1),
-				}
+				testDone := make(chan struct{})
+				reqCtx, cancelReq := context.WithCancel(context.Background())
 				go func() {
-
-					//Using the same dummyReq pauses other workers while they push their errors in the Err chan. This keeps the
-					//provider queue full and allows us to test our scale up feature. At the end we call cancel to cancel all the
-					//requests, free our workers and shutdown.
 					for i := 0; i < test.NumRequests; i++ {
+						dummyReq := &ChannelMessage{
+							Context:  schemas.NewBifrostContext(reqCtx, time.Time{}),
+							Err:      make(chan schemas.BifrostError),
+							Response: make(chan *schemas.BifrostResponse),
+						}
 						select {
 						case <-testDone:
 							return
 						case pq.queue <- dummyReq:
 						}
 					}
 
 				}()
@@
-				go func() {
-					for {
-						select {
-						case <-dummyReq.Err:
-						case <-dummyReq.Response:
-						}
-					}
-				}()
-
 				bifrost.Shutdown()
🤖 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/bifrost_test.go` around lines 3057 - 3094, The scaling test reuses a
single mutable ChannelMessage across many queue submissions, which can race
because requestWorker mutates per-request state on the message and its context.
Update the enqueue loop in the test to create a fresh ChannelMessage for each
send while still deriving each one from the same cancelable parent context
(reqCtx/cancelReq), and keep the existing cleanup/shutdown logic around testDone
and cancelReq.

Source: Coding guidelines

Comment thread docs/docs.json Outdated
Comment on lines +488 to +494
{
"group": "Google Workspace",
"icon": "google",
"collapsed": true,
"pages": [
"enterprise/setting-up-google-workspace"
]

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the Google Workspace nav slug to the renamed OIDC page.

This stack adds enterprise/setting-up-google-workspace/oidc and keeps a redirect for the legacy slug, but the navigation still points at enterprise/setting-up-google-workspace. Keeping the menu on the redirect source leaves docs/docs.json out of sync with the actual page layout.

As per path instructions, "Verify new or renamed Mintlify pages are reflected in docs/docs.json where appropriate."

🤖 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 `@docs/docs.json` around lines 488 - 494, The Google Workspace navigation entry
is still pointing to the legacy redirect source instead of the renamed OIDC
page. Update the page reference in docs/docs.json under the Google Workspace
group to use the new enterprise/setting-up-google-workspace/oidc slug so the nav
matches the current page layout and stays aligned with the renamed Mintlify
page.

Source: Path instructions

Comment on lines +203 to +217
<Note>
If you prefer to configure claims via the App Manifest JSON in Step 7, you can skip this step — the manifest overrides UI-based token configuration.
</Note>

In your app registration, go to **Token configuration** and click **Add groups claim**.

Select **Security groups** or **Groups assigned to the application**, enable **ID** and **Access** token types, and click **Add**.

<Frame caption="Token configuration — groups claim added for ID and Access tokens.">
<img src="/media/user-provisioning/entra/entra-oidc-token-configuration.png" alt="Token configuration page showing the groups claim configured for ID, Access, and SAML tokens" />
</Frame>

<Note>
If you configure claims via the **Manifest** editor instead, also set `"requestedAccessTokenVersion": 2` (or `"accessTokenAcceptedVersion": 2` for legacy registrations) and `"groupMembershipClaims": "ApplicationGroup"` to restrict the groups claim to only app-assigned groups.
</Note>

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Document the manifest-based roles claim path or drop the manifest shortcut.

Step 6 tells readers they can skip the UI flow and configure claims via the app manifest, but it points to a nonexistent “Step 7” manifest step. Later, troubleshooting requires roles under optionalClaims.idToken, yet this page never shows that manifest entry. Following the manifest path as written can leave Entra users without a roles claim and blocked at login.

As per path instructions, "Check docs for parity with code, config.schema.json, and provider behavior."

Also applies to: 401-405

🤖 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 `@docs/enterprise/setting-up-entra/oidc.mdx` around lines 203 - 217, The
manifest-based path in the OIDC setup is incomplete: the note references a
nonexistent later step and does not show how to configure the required roles
claim. Update the guidance around the Token configuration / Manifest editor flow
to either remove the shortcut or explicitly document the manifest settings,
including the `optionalClaims.idToken` `roles` entry and any related
claim/version fields, so readers can follow the manifest route without missing
the `roles` claim. Use the existing OIDC setup section and the manifest note as
the anchors for this fix.

Source: Path instructions

description: "Enable real-time user and group provisioning from Microsoft Entra ID to Bifrost Enterprise using SCIM 2.0."
---

SCIM (System for Cross-domain Identity Management) keeps Bifrost in sync with Entra in real time - new users are provisioned, deactivated users are suspended, and group memberships are updated without waiting for the next login or background sync.

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align the sync-timing claims with the later cycle-based explanation.

This page promises “real-time” provisioning/deactivation early on, but later says Entra applies changes on incremental cycles (~40 minutes) and that the initial sync can take up to 4 hours. Please reword the earlier sections to match that cycle-based behavior so operators do not expect immediate propagation. As per path instructions, "Check docs for parity with code, config.schema.json, and provider behavior."

Also applies to: 156-156, 184-195

🤖 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 `@docs/enterprise/setting-up-entra/scim.mdx` at line 6, The intro and related
SCIM sections overstate immediate “real-time” propagation, which conflicts with
the later cycle-based timing details. Update the affected prose in scim.mdx
around the SCIM overview and the sections referenced by the comment to describe
Entra sync as incremental/cycle-based, and make the wording consistent with the
documented ~40 minute cycles and initial sync delay. Use the SCIM overview text
and the later timing explanation as the source of truth, and keep terminology
aligned with the provider behavior.

Source: Path instructions

description: "Enable real-time user and group provisioning from any SCIM 2.0-capable identity provider to Bifrost Enterprise."
---

Bifrost exposes a SCIM 2.0 endpoint that any compatible identity provider can push user and group changes to in real time — new users are provisioned, deactivated users are suspended, and group memberships are updated without waiting for the next background sync cycle.

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Avoid promising real-time SCIM behavior for every IdP.

This guide is provider-agnostic, but it currently claims immediate push semantics while also noting that many IdPs apply changes on their next provisioning cycle. Please soften the wording to cycle-based behavior unless real-time sync is guaranteed across all supported SCIM providers. As per path instructions, "Check docs for parity with code, config.schema.json, and provider behavior."

Also applies to: 115-115, 156-158

🤖 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 `@docs/enterprise/setting-up-generic-oidc/scim.mdx` at line 6, The SCIM
overview text in the docs overstates provider behavior by implying real-time
push semantics for all compatible IdPs. Update the wording in the SCIM guide to
describe cycle-based provisioning unless the behavior is guaranteed across all
supported providers, and keep the description aligned with the provider-specific
behavior noted later in the same document. Refer to the SCIM intro copy in the
generic OIDC SCIM page and ensure it matches the documented provisioning flow
used by the relevant SCIM provider sections.

Source: Path instructions

Comment on lines +2 to +6
title: "Setup SCIM"
description: "Enable real-time user and group provisioning from Google Workspace to Bifrost Enterprise."
---

SCIM keeps Bifrost in sync with Google Workspace in real time - new users are provisioned, deactivated accounts are suspended, and group memberships are updated without waiting for the next background sync cycle.

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

This page is not actually describing SCIM.

The title/description promise real-time SCIM provisioning, but the body says Google Workspace does not push SCIM and that Bifrost relies on 24-hour Directory API reconciliation plus 15-minute session refreshes. Please rename/reframe this as Google Workspace provisioning or SCIM-equivalent sync so readers do not expect a true SCIM endpoint. Based on learnings, I checked the surrounding stack first; as per path instructions, docs should match the implemented behavior.

Also applies to: 16-23

🤖 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 `@docs/enterprise/setting-up-google-workspace/scim.mdx` around lines 2 - 6, The
page metadata and intro in scim.mdx are misleading because they describe
real-time SCIM provisioning, but the documented behavior is Google Workspace
reconciliation via Directory API and session refreshes. Update the title,
description, and opening copy in the SCIM page to match the actual
implementation, and reframe it around Google Workspace provisioning or
SCIM-equivalent sync rather than a true SCIM endpoint. Use the existing section
content in the page to align the wording with the implemented sync flow.

Sources: Path instructions, Learnings

Comment on lines +132 to +135
**Users not appearing in Import Preview** - confirm the service account has the three Directory API scopes authorized in Domain-Wide Delegation. Check that the `adminEmail` is a Super Admin or has the **User Management Admin** role.

**Group memberships not syncing** - verify `GroupMember.Read.All` scope is included in Domain-Wide Delegation. Groups must be assigned to the Bifrost application in the Google Admin Console for the `groups` claim to appear in the token.

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the Google Directory API scope name here.

GroupMember.Read.All is a Microsoft Graph permission, not a Google Workspace Domain-Wide Delegation scope. This troubleshooting step should point back to https://www.googleapis.com/auth/admin.directory.group.member.readonly, otherwise admins will search for the wrong permission and fail setup. As per path instructions, docs should stay aligned with the actual provider behavior and configuration surface.

🤖 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 `@docs/enterprise/setting-up-google-workspace/scim.mdx` around lines 132 - 135,
The troubleshooting note in the Google Workspace SCIM docs uses the wrong scope
name for group membership syncing. In the “Group memberships not syncing”
guidance, replace the Microsoft Graph permission reference with the Google
Directory API Domain-Wide Delegation scope used by this integration, and keep
the wording aligned with the existing SCIM/provider setup guidance so admins
verify the correct authorization in Google Admin Console.

Source: Path instructions

Comment on lines +169 to +172
Scroll to find your attribute and set its source from the Okta user profile — e.g. `user.employeeNumber` → `employeeID`. Click **Save Mappings**.

<Frame caption="Mapping user.employeeID from the Okta user profile to the employeeID SCIM attribute.">
<img src="/media/user-provisioning/okta/okta-custom-attribute-mapping-employeeid.png" alt="Attribute mapping row showing user.employeeID mapped to the employeeID SCIM attribute" />

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use one source-field example here.

This step switches from user.employeeNumber in the text to user.employeeID in the caption. Please make both examples match, or explicitly call out that employeeID is a custom Okta profile field, otherwise the mapping instructions are ambiguous.

🤖 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 `@docs/enterprise/setting-up-okta/scim.mdx` around lines 169 - 172, The Okta
SCIM mapping example is inconsistent between the body text and the figure
caption, so update the example in the surrounding prose and the Frame caption to
use the same source field. In the section describing the attribute mapping,
align the `user.employeeNumber`/`user.employeeID` reference with the actual
example shown, or explicitly note that `employeeID` is a custom Okta profile
field. Make the wording in the SCIM mapping instructions and the caption for the
employeeID image match exactly so the flow stays unambiguous.

Comment on lines +68 to +87
## Step 2: Enable role claims on the project (optional)

<Note>
Skip this step if you plan to map roles using a different claim (e.g. groups or a custom attribute) rather than Zitadel project roles.
</Note>

<Steps>

<Step title="Enable Return user roles during authentication">

Open **Projects → your project → General** and enable:

- **Return user roles during authentication** - required for role claims to appear in the token
- **Only authorized users can authenticate** - enforces that every user has at least one project role

<Frame caption="Project General settings - enable Return user roles during authentication to include role claims in the token.">
<img src="/media/user-provisioning/zitadel/zitadel-return-user-roles.png" alt="Zitadel project General settings showing Return user roles during authentication checkbox enabled" />
</Frame>

Note the **Project ID** - you will need it for the Bifrost configuration.

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't hide Project ID behind an optional step.

Step 6 requires Project ID unconditionally, but Step 2 is marked optional and is currently the only place this page tells readers to capture that value. Anyone skipping the role-claim setup still has to do Step 2 to finish provider configuration.

As per path instructions, "Check docs for parity with code, config.schema.json, and provider behavior."

Also applies to: 215-219

🤖 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 `@docs/enterprise/setting-up-zitadel/oidc.mdx` around lines 68 - 87, The Step 2
content in the Zitadel OIDC guide is marked optional, but it also contains the
only instruction to capture the Project ID that later setup requires
unconditionally. Update the wording around the Step 2 section and the “Note the
Project ID” guidance so readers are told to record it even if they skip
role-claim setup, while keeping the optional note limited to the
role-claim-specific parts of the step. Use the existing Step/Note/Frame
structure in oidc.mdx to keep the flow consistent with the later provider
configuration steps.

Source: Path instructions

Comment on lines 46 to 47
<Card title="Google Workspace" icon="google" href="/enterprise/setting-up-google-workspace">
Google Workspace domains with OAuth login plus optional Directory API sync via a service account.

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Point the Google Workspace card at the actual guide page.

href="/enterprise/setting-up-google-workspace" does not match the docs structure introduced in this stack, which exposes .../oidc and .../scim pages. As written, this card is likely to land on a missing route instead of the OIDC entrypoint. As per path instructions, docs should stay in parity with the actual docs structure.

🤖 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 `@docs/enterprise/user-provisioning.mdx` around lines 46 - 47, The Google
Workspace card is pointing to a route that does not exist in the current docs
structure. Update the Card in the user provisioning page so its href matches the
actual Google Workspace guide entrypoint, using the existing OIDC/SCIM docs path
pattern rather than the outdated setting-up-google-workspace link.

Source: Path instructions

Introduces autonomous scaling for provider queues to handle traffic spikes and scale down during idle periods. A dedicated background goroutine periodically evaluates queue capacity against configurable thresholds to spin up or terminate workers.

- Refactored `ConcurrencyAndBufferSize` in schemas to include scaling bounds (MinWorkers, MaxWorkers), thresholds, and intervals.
- Implemented custom JSON marshal/unmarshal for the config struct to safely handle `time.Duration` conversion to/from milliseconds.
- Integrated scaling lifecycle logic into `prepareProvider`, `updateProvider`, and `requestWorker`.
- Added initial test coverage validating configuration bounds and extreme load scenarios (0% and 100% capacity).

Affected packages:
- core/bifrost.go - Scaling goroutine and worker lifecycle integration
- core/schemas/provider.go - Configuration structs and JSON serialization
- core/utils.go - Utility support for scaling logic
- core/bifrost_test.go - Boundary and configuration validation tests
@Prateek-Gupta001
Prateek-Gupta001 force-pushed the feat/dynamic-worker-autoscaler-v2 branch from 73a12ad to 16f1871 Compare June 30, 2026 07:41

@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

Caution

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

⚠️ Outside diff range comments (1)
ui/app/workspace/providers/views/modelProviderKeysTableView.tsx (1)

234-241: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include all Bedrock Mantle secret fields in the warning detector.

Line 239 only checks region; unresolved secret refs for access_key, secret_key, session_token, role_arn, external_id, or session_name will still show as a generic list-model error instead of the actionable secret-resolution warning.

Proposed fix
 														const hasSecretVarConfig =
 															(key.azure_key_config?.endpoint?.type && key.azure_key_config.endpoint.type !== "plain_text") ||
 															(key.vertex_key_config?.project_id?.type && key.vertex_key_config.project_id.type !== "plain_text") ||
 															(key.vertex_key_config?.region?.type && key.vertex_key_config.region.type !== "plain_text") ||
 															(key.bedrock_key_config?.region?.type && key.bedrock_key_config.region.type !== "plain_text") ||
-															(key.bedrock_mantle_key_config?.region?.type && key.bedrock_mantle_key_config.region.type !== "plain_text") ||
+															(key.bedrock_mantle_key_config?.access_key?.type && key.bedrock_mantle_key_config.access_key.type !== "plain_text") ||
+															(key.bedrock_mantle_key_config?.secret_key?.type && key.bedrock_mantle_key_config.secret_key.type !== "plain_text") ||
+															(key.bedrock_mantle_key_config?.session_token?.type && key.bedrock_mantle_key_config.session_token.type !== "plain_text") ||
+															(key.bedrock_mantle_key_config?.region?.type && key.bedrock_mantle_key_config.region.type !== "plain_text") ||
+															(key.bedrock_mantle_key_config?.role_arn?.type && key.bedrock_mantle_key_config.role_arn.type !== "plain_text") ||
+															(key.bedrock_mantle_key_config?.external_id?.type && key.bedrock_mantle_key_config.external_id.type !== "plain_text") ||
+															(key.bedrock_mantle_key_config?.session_name?.type && key.bedrock_mantle_key_config.session_name.type !== "plain_text") ||
 															(key.vllm_key_config?.url?.type && key.vllm_key_config.url.type !== "plain_text") ||
 															(key.value?.type && key.value.type !== "plain_text");

As per path instructions, “For ui/**, check interactive workflows for loading, empty, error, and success states.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/app/workspace/providers/views/modelProviderKeysTableView.tsx` around lines
234 - 241, The warning detector in modelProviderKeysTableView.tsx only checks
bedrock_mantle_key_config.region, so unresolved Bedrock Mantle secret refs in
access_key, secret_key, session_token, role_arn, external_id, and session_name
are missed. Update the hasSecretVarConfig logic in the relevant render path to
include all Bedrock Mantle key config fields alongside the existing Azure,
Vertex, Bedrock, VLLM, and value checks so these cases surface the actionable
secret-resolution warning instead of the generic list-model error.

Source: Path instructions

🧹 Nitpick comments (2)
core/bifrost.go (2)

143-143: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the leftover dev TODO.

// TODO: Now just write the nc.Copy things in the provider.go files!! reads like a personal note and references nothing concrete in this function. It will confuse future readers of the autoscaler.
Want me to open a tracking issue if this references unfinished work, or should it just be deleted?

🤖 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/bifrost.go` at line 143, Remove the leftover dev TODO comment from the
relevant area in bifrost-related code, since it is an undocumented personal note
rather than actionable guidance. If there is still unfinished work, replace it
with a concrete, scoped note tied to the specific provider.go or nc.Copy logic;
otherwise delete it entirely so the surrounding code in the bifrost/autoscaler
path remains clean.

175-178: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Boundary log lines will spam at Info on every tick.

When a provider sits at MaxWorkers under sustained load (or MinWorkers while idle), these branches emit an Info log on every ScalingInterval tick indefinitely. Consider logging the "already at max/min" cases at Debug, or only when the state transitions.

Also applies to: 201-204

🤖 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/bifrost.go` around lines 175 - 178, The boundary cases in bifrost
scaling are logging too loudly on every tick, so adjust the logging in the
worker-scaling branches around the MaxWorkers and MinWorkers checks inside
bifrost’s scaling logic to avoid Info-level spam. Update the relevant messages
in the Bifrost scaling path (including the max-worker and min-worker “already at
limit” branches) to Debug, or gate them so they only log on state transitions,
while keeping the existing scaling 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.

Inline comments:
In `@core/bifrost.go`:
- Around line 150-151: The provider goroutine is reloading the wait group from
bifrost.waitGroups instead of using the waitGroup argument already tied to this
pq, which can point workers at the wrong shutdown barrier if the map entry
changes. Update the logic in the provider-handling flow to use the existing
waitGroup parameter directly where currentWaitGroup is set, and remove the extra
Load from bifrost.waitGroups in that path.

In `@core/providers/anthropic/requestbuilder.go`:
- Around line 99-114: The comment above the schemas.Bedrock entry is mislabeled
and currently describes Bedrock Mantle instead of Bedrock itself. Update the
block comment in RequestBuilder’s provider-features map so it clearly documents
schemas.Bedrock behavior, and leave the separate schemas.BedrockMantle comment
to explain the Mantle-specific entry; this keeps the two adjacent
RemapToolVersions settings unambiguous.

---

Outside diff comments:
In `@ui/app/workspace/providers/views/modelProviderKeysTableView.tsx`:
- Around line 234-241: The warning detector in modelProviderKeysTableView.tsx
only checks bedrock_mantle_key_config.region, so unresolved Bedrock Mantle
secret refs in access_key, secret_key, session_token, role_arn, external_id, and
session_name are missed. Update the hasSecretVarConfig logic in the relevant
render path to include all Bedrock Mantle key config fields alongside the
existing Azure, Vertex, Bedrock, VLLM, and value checks so these cases surface
the actionable secret-resolution warning instead of the generic list-model
error.

---

Nitpick comments:
In `@core/bifrost.go`:
- Line 143: Remove the leftover dev TODO comment from the relevant area in
bifrost-related code, since it is an undocumented personal note rather than
actionable guidance. If there is still unfinished work, replace it with a
concrete, scoped note tied to the specific provider.go or nc.Copy logic;
otherwise delete it entirely so the surrounding code in the bifrost/autoscaler
path remains clean.
- Around line 175-178: The boundary cases in bifrost scaling are logging too
loudly on every tick, so adjust the logging in the worker-scaling branches
around the MaxWorkers and MinWorkers checks inside bifrost’s scaling logic to
avoid Info-level spam. Update the relevant messages in the Bifrost scaling path
(including the max-worker and min-worker “already at limit” branches) to Debug,
or gate them so they only log on state transitions, while keeping the existing
scaling behavior unchanged.
🪄 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: 78968ae9-76af-4c22-9bef-dc9766505005

📥 Commits

Reviewing files that changed from the base of the PR and between 73a12ad and 16f1871.

📒 Files selected for processing (119)
  • .github/workflows/release-pipeline.yml
  • core/bifrost.go
  • core/bifrost_test.go
  • core/changelog.md
  • core/internal/llmtests/account.go
  • core/internal/mcptests/connect_ping_listtools_test.go
  • core/mcp/clientmanager.go
  • core/providers/anthropic/advisor_test.go
  • core/providers/anthropic/anthropic.go
  • core/providers/anthropic/chat.go
  • core/providers/anthropic/requestbuilder.go
  • core/providers/anthropic/requestbuilder_test.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/types.go
  • core/providers/anthropic/utils.go
  • core/providers/anthropic/utils_test.go
  • core/providers/azure/azure.go
  • core/providers/azure/utils.go
  • core/providers/bedrock/bedrock.go
  • core/providers/bedrock/mantle.go
  • core/providers/bedrock/mantle_test.go
  • core/providers/bedrock/streambuffering_test.go
  • core/providers/bedrock/transport_test.go
  • core/providers/bedrockmantle/bedrockmantle.go
  • core/providers/bedrockmantle/bedrockmantle_test.go
  • core/providers/bedrockmantle/utils.go
  • core/providers/cerebras/cerebras.go
  • core/providers/fireworks/fireworks.go
  • core/providers/gemini/batch.go
  • core/providers/gemini/chat.go
  • core/providers/gemini/gemini_test.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/utils.go
  • core/providers/gemini/videos.go
  • core/providers/groq/groq.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/nebius/nebius.go
  • core/providers/ollama/ollama.go
  • core/providers/openai/large_payload.go
  • core/providers/openai/openai.go
  • core/providers/openai/tool_search_roundtrip_test.go
  • core/providers/openai/transcription.go
  • core/providers/openai/transcription_test.go
  • core/providers/opencode/opencode.go
  • core/providers/openrouter/openrouter.go
  • core/providers/parasail/parasail.go
  • core/providers/perplexity/perplexity.go
  • core/providers/sgl/sgl.go
  • core/providers/utils/bodysigner.go
  • core/providers/vertex/types.go
  • core/providers/vertex/utils.go
  • core/providers/vertex/utils_test.go
  • core/providers/vertex/vertex.go
  • core/providers/vertex/vertex_test.go
  • core/providers/vllm/vllm.go
  • core/providers/xai/xai.go
  • core/schemas/account.go
  • core/schemas/account_test.go
  • core/schemas/bifrost.go
  • core/schemas/chatcompletions.go
  • core/schemas/provider.go
  • core/schemas/responses.go
  • core/schemas/utils.go
  • core/schemas/utils_test.go
  • core/utils.go
  • docs/changelogs/ent-v1.5.0.mdx
  • docs/changelogs/helm-v2.1.25.mdx
  • docs/deployment-guides/config-json/providers.mdx
  • docs/docs.json
  • docs/openapi/openapi.json
  • docs/openapi/schemas/inference/chat.yaml
  • docs/providers/supported-providers/bedrock-mantle.mdx
  • docs/providers/supported-providers/overview.mdx
  • framework/changelog.md
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/tables/key.go
  • framework/logstore/hybrid_test.go
  • framework/logstore/tables.go
  • framework/logstore/tables_test.go
  • helm-charts/bifrost/README.md
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seed/go.mod
  • tests/cmd/seedvks/go.mod
  • tests/e2e/api/collections/provider-harness.json
  • tests/e2e/api/provider-capabilities.json
  • tests/e2e/api/provider_config/bifrost-v1-bedrock-mantle.postman_environment.json
  • tests/e2e/api/runners/filter-collection.mjs
  • tests/e2e/api/runners/harness-monitor.mjs
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/governance_test.go
  • transports/bifrost-http/handlers/provider_keys.go
  • transports/bifrost-http/integrations/anthropic.go
  • transports/bifrost-http/integrations/openai.go
  • transports/bifrost-http/lib/config.go
  • transports/config.schema.json
  • ui/app/workspace/audit-logs/page.tsx
  • ui/app/workspace/complexity-router/page.tsx
  • ui/app/workspace/logs/page.tsx
  • ui/app/workspace/providers/dialogs/providerConfigSheet.tsx
  • ui/app/workspace/providers/fragments/apiKeysFormFragment.tsx
  • ui/app/workspace/providers/fragments/betaHeadersFormFragment.tsx
  • ui/app/workspace/providers/fragments/governanceFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/components/filters/logsFilterSidebar.tsx
  • ui/components/filters/mcpFilterSidebar.tsx
  • ui/components/ui/tagInput.tsx
  • ui/components/ui/truncatedLabel.tsx
  • ui/lib/constants/config.ts
  • ui/lib/constants/icons.tsx
  • ui/lib/constants/logs.ts
  • ui/lib/queryParamsParser.test.ts
  • ui/lib/queryParamsParser.ts
  • ui/lib/schemas/providerForm.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts
💤 Files with no reviewable changes (3)
  • core/providers/vertex/types.go
  • core/providers/vertex/utils.go
  • core/providers/anthropic/utils.go
✅ Files skipped from review due to trivial changes (15)
  • helm-charts/bifrost/README.md
  • ui/app/workspace/audit-logs/page.tsx
  • core/changelog.md
  • framework/changelog.md
  • core/providers/openai/tool_search_roundtrip_test.go
  • ui/app/workspace/providers/dialogs/providerConfigSheet.tsx
  • core/schemas/chatcompletions.go
  • ui/lib/constants/config.ts
  • ui/components/filters/mcpFilterSidebar.tsx
  • docs/docs.json
  • docs/providers/supported-providers/bedrock-mantle.mdx
  • ui/components/filters/logsFilterSidebar.tsx
  • docs/changelogs/helm-v2.1.25.mdx
  • docs/deployment-guides/config-json/providers.mdx
  • docs/changelogs/ent-v1.5.0.mdx
🚧 Files skipped from review as they are similar to previous changes (6)
  • tests/cmd/seedvks/go.mod
  • tests/cmd/e2eseed/go.mod
  • tests/cmd/seed/go.mod
  • core/schemas/provider.go
  • .github/workflows/release-pipeline.yml
  • core/bifrost_test.go

Comment thread core/bifrost.go
Comment on lines +150 to +151
waitGroupValue, _ := bifrost.waitGroups.Load(providerName)
currentWaitGroup := waitGroupValue.(*sync.WaitGroup)

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
ast-grep run --lang go --pattern 'go bifrost.DynamicWorkerScaling($$$)' core/bifrost.go
rg -nP -C3 'DynamicWorkerScaling|waitGroups\.(Store|Load)' core/bifrost.go

Repository: maximhq/bifrost

Length of output: 3621


🏁 Script executed:

#!/bin/bash
sed -n '144,206p' core/bifrost.go
printf '\n----\n'
sed -n '3516,3610p' core/bifrost.go
printf '\n----\n'
sed -n '4200,4248p' core/bifrost.go

Repository: maximhq/bifrost

Length of output: 8230


🏁 Script executed:

#!/bin/bash
python3 - <<'PY'
from pathlib import Path
p = Path('core/bifrost.go')
text = p.read_text()
for needle in [
    'func (bifrost *Bifrost) DynamicWorkerScaling',
    'waitGroupValue, _ := bifrost.waitGroups.Load(providerName)',
    'currentWaitGroup := waitGroupValue.(*sync.WaitGroup)',
    'go bifrost.DynamicWorkerScaling(provider, providerConfig, newPq, newWaitGroup)',
    'go bifrost.DynamicWorkerScaling(provider, config, pq, currentWaitGroup)',
]:
    print(needle, text.find(needle))
PY

Repository: maximhq/bifrost

Length of output: 490


Use the waitGroup parameter here instead of reloading from bifrost.waitGroups. A later provider update can swap the map entry before this goroutine starts, which sends workers to the wrong shutdown barrier. waitGroup is already the group tied to this pq.

🤖 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/bifrost.go` around lines 150 - 151, The provider goroutine is reloading
the wait group from bifrost.waitGroups instead of using the waitGroup argument
already tied to this pq, which can point workers at the wrong shutdown barrier
if the map entry changes. Update the logic in the provider-handling flow to use
the existing waitGroup parameter directly where currentWaitGroup is set, and
remove the extra Load from bifrost.waitGroups in that path.

Source: Linters/SAST tools

Comment on lines +99 to +114
// Bedrock Mantle native-Anthropic endpoint (/anthropic/v1/messages): the
// request is the native Anthropic Messages body, so model stays in the body
// (set to the bare Bedrock model id), the version is sent as an
// "anthropic-version" HTTP header rather than a body field, and stream is a
// body field. Tool type versions are still remapped to the canonical pair
// the hosted Claude generation expects.
schemas.Bedrock: {
RemapToolVersions: true,
},
// Bedrock Mantle shares the Bedrock native-Anthropic request shape (model in
// body, anthropic-version HTTP header, tool versions remapped). It has its own
// entry so its feature surface in ProviderFeatures can diverge from Bedrock's
// Converse path without coupling the two.
schemas.BedrockMantle: {
RemapToolVersions: true,
},

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Mislabeled comment on the schemas.Bedrock map entry.

The block comment above schemas.Bedrock opens with "Bedrock Mantle native-Anthropic endpoint…", yet there is a distinct schemas.BedrockMantle entry directly below it. This makes it ambiguous which provider the comment actually documents and obscures why both entries currently carry identical defaults (RemapToolVersions: true). Please retarget the comment to describe the Bedrock entry's behavior (and let the existing schemas.BedrockMantle comment cover Mantle).

🤖 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/anthropic/requestbuilder.go` around lines 99 - 114, The
comment above the schemas.Bedrock entry is mislabeled and currently describes
Bedrock Mantle instead of Bedrock itself. Update the block comment in
RequestBuilder’s provider-features map so it clearly documents schemas.Bedrock
behavior, and leave the separate schemas.BedrockMantle comment to explain the
Mantle-specific entry; this keeps the two adjacent RemapToolVersions settings
unambiguous.

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.

Dynamic Scaling of Worker Pool and Buffer Sizes per Provider

10 participants