Skip to content

move to schemas.BifrostContext#1262

Merged
akshaydeo merged 1 commit into
v1.4.0from
01-07-move_to_schemas.bifrostcontext
Jan 7, 2026
Merged

move to schemas.BifrostContext#1262
akshaydeo merged 1 commit into
v1.4.0from
01-07-move_to_schemas.bifrostcontext

Conversation

@akshaydeo
Copy link
Copy Markdown
Contributor

@akshaydeo akshaydeo commented Jan 6, 2026

Summary

Moves entire internal of Bifrost to use schemas.BifrostContext vs context.Context.

Changes

  • Moves entire internal of Bifrost to use schemas.BifrostContext vs context.Context.

Type of change

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

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

Describe the steps to validate this change. Include commands and expected outcomes.

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

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

If adding new configs or environment variables, document them here.

Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

Breaking changes

  • Yes
  • No

If yes, describe impact and migration instructions.

Related issues

Link related issues and discussions. Example: Closes #123

Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

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
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 6, 2026

Warning

Rate limit exceeded

@akshaydeo has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 2 minutes and 41 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 5d1fcf4 and 6010e56.

⛔ Files ignored due to path filters (2)
  • examples/plugins/hello-world-wasm-rust/Cargo.lock is excluded by !**/*.lock
  • tests/core-mcp/go.sum is excluded by !**/*.sum
📒 Files selected for processing (132)
  • .gitignore
  • core/bifrost.go
  • core/bifrost_test.go
  • core/chatbot_test.go
  • core/internal/testutil/account.go
  • core/internal/testutil/automatic_function_calling.go
  • core/internal/testutil/batch.go
  • core/internal/testutil/chat_audio.go
  • core/internal/testutil/chat_completion_stream.go
  • core/internal/testutil/complete_end_to_end.go
  • core/internal/testutil/count_tokens.go
  • core/internal/testutil/cross_provider_scenarios.go
  • core/internal/testutil/embedding.go
  • core/internal/testutil/end_to_end_tool_calling.go
  • core/internal/testutil/file_base64.go
  • core/internal/testutil/file_url.go
  • core/internal/testutil/image_base64.go
  • core/internal/testutil/image_url.go
  • core/internal/testutil/list_models.go
  • core/internal/testutil/multi_turn_conversation.go
  • core/internal/testutil/multiple_images.go
  • core/internal/testutil/multiple_tool_calls.go
  • core/internal/testutil/prompt_caching.go
  • core/internal/testutil/reasoning.go
  • core/internal/testutil/responses_stream.go
  • core/internal/testutil/setup.go
  • core/internal/testutil/simple_chat.go
  • core/internal/testutil/speech_synthesis.go
  • core/internal/testutil/speech_synthesis_stream.go
  • core/internal/testutil/structured_outputs.go
  • core/internal/testutil/tests.go
  • core/internal/testutil/text_completion.go
  • core/internal/testutil/text_completion_stream.go
  • core/internal/testutil/tool_calls.go
  • core/internal/testutil/tool_calls_streaming.go
  • core/internal/testutil/transcription.go
  • core/internal/testutil/transcription_stream.go
  • core/internal/testutil/utils.go
  • core/mcp/agent.go
  • core/mcp/agent_test.go
  • core/mcp/agentadaptors.go
  • core/mcp/mcp.go
  • core/mcp/toolmanager.go
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/bedrock/bedrock.go
  • core/providers/bedrock/bedrock_test.go
  • core/providers/bedrock/chat.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/utils.go
  • core/providers/cerebras/cerebras.go
  • core/providers/cohere/cohere.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/gemini/gemini.go
  • core/providers/groq/groq.go
  • core/providers/groq/groq_test.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/mistral/transcription_test.go
  • core/providers/nebius/nebius.go
  • core/providers/ollama/ollama.go
  • core/providers/openai/openai.go
  • core/providers/openrouter/openrouter.go
  • core/providers/parasail/parasail.go
  • core/providers/perplexity/perplexity.go
  • core/providers/sgl/sgl.go
  • core/providers/utils/utils.go
  • core/providers/vertex/vertex.go
  • core/providers/xai/xai.go
  • core/schemas/account.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/context_native.go
  • core/schemas/context_wasm.go
  • core/schemas/mcp.go
  • core/schemas/plugin.go
  • core/schemas/plugin_native.go
  • core/schemas/plugin_wasm.go
  • core/schemas/provider.go
  • docs/docs.json
  • docs/plugins/getting-started.mdx
  • docs/plugins/writing-go-plugin.mdx
  • docs/plugins/writing-wasm-plugin.mdx
  • examples/plugins/hello-world-wasm-go/main.go
  • examples/plugins/hello-world-wasm-rust/src/lib.rs
  • examples/plugins/hello-world-wasm-rust/src/types.rs
  • examples/plugins/hello-world-wasm-typescript/assembly/index.ts
  • examples/plugins/hello-world-wasm-typescript/assembly/types.ts
  • examples/plugins/hello-world-wasm-typescript/package.json
  • framework/streaming/accumulator.go
  • plugins/governance/main.go
  • plugins/jsonparser/plugin_test.go
  • plugins/maxim/main.go
  • plugins/maxim/plugin_test.go
  • plugins/mocker/plugin_test.go
  • plugins/semanticcache/main.go
  • plugins/semanticcache/plugin_cache_type_test.go
  • plugins/semanticcache/plugin_cross_cache_test.go
  • plugins/semanticcache/plugin_edge_cases_test.go
  • plugins/semanticcache/plugin_no_store_test.go
  • plugins/semanticcache/search.go
  • plugins/semanticcache/test_utils.go
  • plugins/semanticcache/utils.go
  • plugins/telemetry/main.go
  • tests/core-mcp/agent_mode_test.go
  • tests/core-mcp/auto_execute_config_test.go
  • tests/core-mcp/client_config_test.go
  • tests/core-mcp/codemode_auto_execute_test.go
  • tests/core-mcp/edge_cases_test.go
  • tests/core-mcp/go.mod
  • tests/core-mcp/integration_test.go
  • tests/core-mcp/mcp_connection_test.go
  • tests/core-mcp/responses_test.go
  • tests/core-mcp/setup.go
  • tests/core-mcp/tool_execution_test.go
  • tests/core-mcp/utils.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/mcp.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/integrations/anthropic.go
  • transports/bifrost-http/integrations/bedrock.go
  • transports/bifrost-http/integrations/bedrock_test.go
  • transports/bifrost-http/integrations/cohere.go
  • transports/bifrost-http/integrations/genai.go
  • transports/bifrost-http/integrations/openai.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/integrations/utils.go
  • transports/bifrost-http/lib/account.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/server/server.go
  • ui/app/clientLayout.tsx
📝 Walkthrough

Walkthrough

Replaces stdlib context.Context with *schemas.BifrostContext across core APIs, providers, MCP/agent/tooling, HTTP router/converters, streaming utilities, plugins, tests, and examples; adds BifrostContext helpers (WithValue/SetValue/BlockRestrictedWrites) and threads the new context type through tracing, hooks, streaming, and cancellation.

Changes

Cohort / File(s) Summary
Core API & runtime
core/bifrost.go, core/bifrost_test.go
Public Bifrost entry points and internal handlers now accept *schemas.BifrostContext; ChannelMessage.Context and Bifrost.ctx types updated; Init uses NewBifrostContextWithCancel. Tests updated to construct and pass BifrostContext.
Schemas & Context API
core/schemas/*
core/schemas/context.go, core/schemas/bifrost.go, core/schemas/provider.go, core/schemas/account.go, core/schemas/mcp.go, core/schemas/plugin_*.go, core/schemas/context_native.go, core/schemas/context_wasm.go
Added/changed BifrostContext APIs (NewBifrostContextWithCancel/WithValue/BlockRestrictedWrites); replaced many type signatures to use *BifrostContext; introduced platform-specific helpers and moved PluginShortCircuit between files.
MCP / Agents / Tooling
core/mcp/*
core/mcp/agent.go, core/mcp/agentadaptors.go, core/mcp/mcp.go, core/mcp/toolmanager.go
Agent execution, adapters, MCPManager and ToolsManager APIs refactored to accept/propagate *schemas.BifrostContext; adapter interfaces and makeReq/makeLLMCall signatures updated.
Providers (bulk)
core/providers/*/* (OpenAI, Anthropic, Azure, Bedrock, Gemini, Mistral, Cohere, HuggingFace, etc.)
All providers updated to accept *schemas.BifrostContext for public/internal methods. Streaming end signaling and context value ops migrated from context.WithValue/dereference patterns to ctx.SetValue/ctx.Value. Expect widespread signature changes.
HTTP transports & router
transports/bifrost-http/...
integrations/*.go, integrations/router.go, lib/ctx.go, handlers/*.go, server/server.go, handlers/inference.go, integrations/*
Router converters, pre/post hooks, request converters, stream handlers and ConvertToBifrostContext now use *schemas.BifrostContext. Request value population moved to SetValue; handlers pass bifrostCtx directly.
Core utils & streaming helpers
core/providers/utils/utils.go, framework/streaming/*
Streaming/event helpers, post-hook orchestration, deferred-span finalizers, and list-model aggregation updated to accept/propagate *schemas.BifrostContext; postHookRunner and finalizer call sites adjusted.
Transports integrations (per-provider)
transports/bifrost-http/integrations/* (openai, cohere, anthropic, genai, bedrock, etc.)
Per-integration Request/Response/Error converters and PreRequest callbacks migrated to *schemas.BifrostContext; extraction helpers and query-parsers updated accordingly.
Plugins
plugins/* (semanticcache, jsonparser, maxim, mocker, governance, telemetry, etc.)
Plugin hooks and account GetKeysForProvider signatures changed to accept *schemas.BifrostContext; tests and plugin helpers updated to use ctx.Value/SetValue and new context constructors.
Tests & test utilities
core/internal/testutil/*, provider tests, transport tests, plugin tests
Many test helpers and mocks updated to accept/construct *schemas.BifrostContext (NewBifrostContext, WithTimeout, NewBifrostContextWithValue). Call-sites adjusted (no pointer-dereference).
Examples & plugin SDKs
examples/plugins/*
Example plugin SDKs (Rust/TS/Go) updated: WASM/TypeScript examples changed I/O handling; Rust BifrostContext reworked to map-backed API; tests adapted to new context use.
Miscellaneous
.gitignore, ui/*, docs/*, build/test infra
UI dev-only dynamic import change, docs reorganized (writing plugins), small .gitignore tweaks, build/script updates in example packages; no functional backend behavior changes beyond context refactor.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • danpiths
  • roroghost17

Poem

🐇 I hopped through code both far and near,

swapped contexts so each request is clear.
SetValue I carry, Value I keep,
no more pointers to dig or to heap.
A rabbit cheers: new context, now dear! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 3
❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning Description provides a summary and test instructions but is incomplete and partly inaccurate (misstated affected areas) and lacks migration instructions for the declared breaking change. Expand the PR description: enumerate exact affected modules/files, provide concrete migration steps and breaking-change impact, link related issues, add security considerations, and include test results.
Linked Issues check ⚠️ Warning PR migrates many APIs to BifrostContext but does not implement the Files API endpoints or provider-side file upload functionality required by linked issue #123. Implement Files API work or clearly scope it: add POST /v1/files endpoint, provider upload handlers and storage integration, tests, examples, and reference issue #123 in the PR.
Out of Scope Changes check ⚠️ Warning The change set is very broad — context migration touches providers, transports, plugins, UI, docs and examples — and includes edits that appear unrelated to the linked Files API objective. Split or justify scope: either separate the BifrostContext migration from Files API and UI/docs/example edits into focused PRs, or document why cross-cutting changes are required and list the out-of-scope files.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed Title succinctly and accurately summarizes the main change (migration to schemas.BifrostContext).
Docstring Coverage ✅ Passed Docstring coverage is 92.79% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 01-07-move_to_schemas.bifrostcontext

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

Copy link
Copy Markdown
Contributor Author

akshaydeo commented Jan 6, 2026

@akshaydeo akshaydeo mentioned this pull request Jan 6, 2026
18 tasks
@akshaydeo akshaydeo marked this pull request as ready for review January 6, 2026 23:37
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (4)
transports/bifrost-http/integrations/router.go (4)

507-519: Critical: Undefined variable requestCtx causes compilation error.

The function signature was updated to use bifrostCtx *schemas.BifrostContext, but the code on line 519 (and subsequent lines 539, 562, 585, 608, 631, 665, 688) references requestCtx which is never defined. This will fail to compile.

Based on the pattern in handleBatchRequest (lines 738, 760, etc.) where bifrostCtx is passed directly to client methods, the references to requestCtx should be replaced with bifrostCtx.

🔎 Proposed fix
 func (g *GenericRouter) handleNonStreamingRequest(ctx *fasthttp.RequestCtx, config RouteConfig, req interface{}, bifrostReq *schemas.BifrostRequest, bifrostCtx *schemas.BifrostContext) {
-	// Use the cancellable context from ConvertToBifrostContext
-	// While we can't detect client disconnects until we try to write, having a cancellable context
-	// allows providers that check ctx.Done() to cancel early if needed. This is less critical than
-	// streaming requests (where we actively detect write errors), but still provides a mechanism
-	// for providers to respect cancellation.
 	var response interface{}
-
 	var err error
 
 	switch {
 	case bifrostReq.ListModelsRequest != nil:
-		listModelsResponse, bifrostErr := g.client.ListModelsRequest(requestCtx, bifrostReq.ListModelsRequest)
+		listModelsResponse, bifrostErr := g.client.ListModelsRequest(bifrostCtx, bifrostReq.ListModelsRequest)

Apply similar changes for all occurrences of requestCtxbifrostCtx in this function.


857-858: Inconsistent context type: handleFileRequest still uses *context.Context.

The function signature on line 857 uses bifrostCtx *context.Context instead of *schemas.BifrostContext, which is inconsistent with the rest of the refactoring in this file (e.g., handleNonStreamingRequest, handleBatchRequest). Line 858 then dereferences it to get requestCtx.

This appears to be an incomplete migration. The signature should be updated to match the pattern used elsewhere in this PR.

🔎 Proposed fix
-func (g *GenericRouter) handleFileRequest(ctx *fasthttp.RequestCtx, config RouteConfig, req interface{}, fileReq *FileRequest, bifrostCtx *context.Context) {
-	requestCtx := *bifrostCtx
+func (g *GenericRouter) handleFileRequest(ctx *fasthttp.RequestCtx, config RouteConfig, req interface{}, fileReq *FileRequest, bifrostCtx *schemas.BifrostContext) {

Then update all internal calls to use bifrostCtx directly instead of requestCtx.


1019-1040: Inconsistent context type: handleStreamingRequest still uses *context.Context.

The function signature on line 1019 uses bifrostCtx *context.Context instead of *schemas.BifrostContext, and line 1040 dereferences it as streamCtx := *bifrostCtx. This is inconsistent with the broader migration to *schemas.BifrostContext.

🔎 Proposed fix
-func (g *GenericRouter) handleStreamingRequest(ctx *fasthttp.RequestCtx, config RouteConfig, bifrostReq *schemas.BifrostRequest, bifrostCtx *context.Context, cancel context.CancelFunc) {
+func (g *GenericRouter) handleStreamingRequest(ctx *fasthttp.RequestCtx, config RouteConfig, bifrostReq *schemas.BifrostRequest, bifrostCtx *schemas.BifrostContext, cancel context.CancelFunc) {

Then update all internal calls to use bifrostCtx directly.


1134-1134: Inconsistent context type: handleStreaming still uses *context.Context.

The function signature uses bifrostCtx *context.Context, which is inconsistent with the rest of the refactoring.

🔎 Proposed fix
-func (g *GenericRouter) handleStreaming(ctx *fasthttp.RequestCtx, bifrostCtx *context.Context, config RouteConfig, streamChan chan *schemas.BifrostStream, cancel context.CancelFunc) {
+func (g *GenericRouter) handleStreaming(ctx *fasthttp.RequestCtx, bifrostCtx *schemas.BifrostContext, config RouteConfig, streamChan chan *schemas.BifrostStream, cancel context.CancelFunc) {
🤖 Fix all issues with AI Agents
In @core/schemas/context.go:
- Around line 74-80: Update the function doc comment for
NewBifrostContextWithCancel to replace the incorrect "PluginContext" reference
with "BifrostContext" so the comment accurately describes the returned type;
keep the rest of the comment (purpose, convenience wrapper around
NewBifrostContext, and note about calling the cancel function) unchanged and
ensure the first line still starts with the function name.
🧹 Nitpick comments (2)
transports/bifrost-http/lib/account.go (1)

38-74: Consider simplifying pointer dereference syntax.

Line 51 uses (*ctx).Value(...) to call the method. In Go, methods can be called directly on pointer receivers, so this can be simplified to ctx.Value(...). While both forms are valid, the explicit dereference is less idiomatic and unnecessarily verbose.

🔎 Proposed simplification
-	if v := (*ctx).Value(schemas.BifrostContextKey("bf-governance-include-only-keys")); v != nil {
+	if v := ctx.Value(schemas.BifrostContextKey("bf-governance-include-only-keys")); v != nil {
core/mcp/toolmanager.go (1)

385-387: Consider using BifrostContext-native timeout method.

Line 386 creates a standard context.Context with timeout from the *schemas.BifrostContext, which may lose custom context features (like the custom value storage via SetValue/Value). Consider whether BifrostContext provides its own timeout method to preserve the custom context chain.

If BifrostContext provides a timeout method, consider using it:

// Instead of stdlib context.WithTimeout, use BifrostContext method if available
toolCtx, cancel := ctx.WithTimeout(toolExecutionTimeout)
// OR
toolCtx, cancel := schemas.NewBifrostContextWithTimeout(ctx, toolExecutionTimeout)
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between afd603c and f3775fb.

📒 Files selected for processing (15)
  • core/bifrost.go
  • core/mcp/agent.go
  • core/mcp/agentadaptors.go
  • core/mcp/mcp.go
  • core/mcp/toolmanager.go
  • core/schemas/account.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/mcp.go
  • core/schemas/provider.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/integrations/utils.go
  • transports/bifrost-http/lib/account.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/server/server.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

always check the stack if there is one for the current PR. do not give localized reviews for the PR, always see all changes in the light of the whole stack of PRs (if there is a stack, if there is no stack you can continue to make localized suggestions/reviews)

Files:

  • core/schemas/context.go
  • core/schemas/account.go
  • transports/bifrost-http/lib/account.go
  • transports/bifrost-http/integrations/router.go
  • core/schemas/mcp.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/integrations/utils.go
  • core/schemas/bifrost.go
  • core/mcp/agentadaptors.go
  • core/mcp/agent.go
  • core/mcp/mcp.go
  • core/mcp/toolmanager.go
  • transports/bifrost-http/server/server.go
  • core/schemas/provider.go
  • core/bifrost.go
🧠 Learnings (4)
📚 Learning: 2025-12-09T17:07:42.007Z
Learnt from: qwerty-dvorak
Repo: maximhq/bifrost PR: 1006
File: core/schemas/account.go:9-18
Timestamp: 2025-12-09T17:07:42.007Z
Learning: In core/schemas/account.go, the HuggingFaceKeyConfig field within the Key struct is currently unused and reserved for future Hugging Face inference endpoint deployments. Do not flag this field as missing from OpenAPI documentation or require its presence in the API spec until the feature is actively implemented and used. When the feature is added, update the OpenAPI docs accordingly; otherwise, treat this field as non-breaking and not part of the current API surface.

Applied to files:

  • core/schemas/context.go
  • core/schemas/account.go
  • transports/bifrost-http/lib/account.go
  • transports/bifrost-http/integrations/router.go
  • core/schemas/mcp.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/integrations/utils.go
  • core/schemas/bifrost.go
  • core/mcp/agentadaptors.go
  • core/mcp/agent.go
  • core/mcp/mcp.go
  • core/mcp/toolmanager.go
  • transports/bifrost-http/server/server.go
  • core/schemas/provider.go
  • core/bifrost.go
📚 Learning: 2025-12-29T11:54:55.836Z
Learnt from: akshaydeo
Repo: maximhq/bifrost PR: 1153
File: framework/configstore/rdb.go:2221-2246
Timestamp: 2025-12-29T11:54:55.836Z
Learning: In Go reviews, do not flag range-over-int patterns like for i := range n as compile-time errors, assuming Go 1.22+ semantics. Only flag actual range-capable values (slices, arrays, maps, channels, strings) and other compile-time issues. This applies to all Go files across the repository.

Applied to files:

  • core/schemas/context.go
  • core/schemas/account.go
  • transports/bifrost-http/lib/account.go
  • transports/bifrost-http/integrations/router.go
  • core/schemas/mcp.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/integrations/utils.go
  • core/schemas/bifrost.go
  • core/mcp/agentadaptors.go
  • core/mcp/agent.go
  • core/mcp/mcp.go
  • core/mcp/toolmanager.go
  • transports/bifrost-http/server/server.go
  • core/schemas/provider.go
  • core/bifrost.go
📚 Learning: 2025-12-12T08:25:02.629Z
Learnt from: Pratham-Mishra04
Repo: maximhq/bifrost PR: 1000
File: transports/bifrost-http/integrations/router.go:709-712
Timestamp: 2025-12-12T08:25:02.629Z
Learning: In transports/bifrost-http/**/*.go, update streaming response handling to align with OpenAI Responses API: use typed SSE events such as response.created, response.output_text.delta, response.done, etc., and do not rely on the legacy data: [DONE] termination marker. Note that data: [DONE] is only used by the older Chat Completions and Text Completions streaming APIs. Ensure parsers, writers, and tests distinguish SSE events from the [DONE] sentinel and handle each event type accordingly for correct stream termination and progress updates.

Applied to files:

  • transports/bifrost-http/lib/account.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/integrations/utils.go
  • transports/bifrost-http/server/server.go
📚 Learning: 2025-12-29T09:14:16.633Z
Learnt from: akshaydeo
Repo: maximhq/bifrost PR: 888
File: transports/bifrost-http/handlers/middlewares.go:246-256
Timestamp: 2025-12-29T09:14:16.633Z
Learning: In the bifrost HTTP transport, fasthttp.RequestCtx is the primary context carrier and should be passed directly to functions that expect a context.Context. Do not convert to context.Context unless explicitly required. Ensure tracer implementations and related components are designed to accept fasthttp.RequestCtx directly, and document this architectural decision for maintainers.

Applied to files:

  • transports/bifrost-http/lib/account.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/integrations/utils.go
  • transports/bifrost-http/server/server.go
🧬 Code graph analysis (14)
core/schemas/account.go (2)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/schemas/bifrost.go (1)
  • ModelProvider (30-30)
transports/bifrost-http/lib/account.go (3)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/schemas/bifrost.go (1)
  • ModelProvider (30-30)
ui/lib/types/config.ts (1)
  • ModelProvider (206-209)
transports/bifrost-http/integrations/router.go (2)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/schemas/bifrost.go (3)
  • BifrostContextKeySendBackRawResponse (136-136)
  • BifrostContextKeyIntegrationType (137-137)
  • BifrostContextKeyDirectKey (125-125)
core/schemas/mcp.go (1)
core/schemas/context.go (1)
  • BifrostContext (31-41)
transports/bifrost-http/lib/ctx.go (2)
core/schemas/context.go (2)
  • BifrostContext (31-41)
  • NewBifrostContextWithCancel (77-80)
core/schemas/bifrost.go (7)
  • BifrostContextKeyRequestID (123-123)
  • BifrostContextKey (117-117)
  • BifrostContextKeyVirtualKey (121-121)
  • BifrostContextKeyAPIKeyName (122-122)
  • BifrostContextKeySendBackRawResponse (136-136)
  • BifrostContextKeyExtraHeaders (132-132)
  • BifrostContextKeyDirectKey (125-125)
transports/bifrost-http/integrations/utils.go (2)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/schemas/bifrost.go (1)
  • BifrostError (490-499)
core/schemas/bifrost.go (1)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/mcp/agentadaptors.go (4)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/schemas/bifrost.go (1)
  • BifrostError (490-499)
core/schemas/chatcompletions.go (1)
  • BifrostChatRequest (10-17)
core/schemas/responses.go (1)
  • BifrostResponsesRequest (30-37)
core/mcp/agent.go (3)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/schemas/bifrost.go (2)
  • BifrostContextKeyRequestID (123-123)
  • BifrostMCPAgentOriginalRequestID (139-139)
core/mcp/toolmanager.go (1)
  • ClientManager (16-20)
core/mcp/mcp.go (3)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/schemas/chatcompletions.go (2)
  • BifrostChatRequest (10-17)
  • BifrostChatResponse (25-40)
core/schemas/responses.go (2)
  • BifrostResponsesRequest (30-37)
  • BifrostResponsesResponse (43-83)
core/mcp/toolmanager.go (2)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/schemas/mcp.go (1)
  • MCPToolManagerConfig (27-31)
transports/bifrost-http/server/server.go (3)
core/schemas/context.go (4)
  • BifrostContext (31-41)
  • NewBifrostContext (46-64)
  • NoDeadline (10-10)
  • NewBifrostContextWithCancel (77-80)
core/schemas/bifrost.go (1)
  • ListModelsRequest (90-90)
core/schemas/models.go (1)
  • BifrostListModelsRequest (21-32)
core/schemas/provider.go (1)
core/schemas/context.go (1)
  • BifrostContext (31-41)
core/bifrost.go (3)
core/schemas/context.go (2)
  • BifrostContext (31-41)
  • NewBifrostContextWithCancel (77-80)
core/schemas/bifrost.go (17)
  • BifrostContextKeyTracer (146-146)
  • TextCompletionStreamRequest (92-92)
  • ChatCompletionStreamRequest (94-94)
  • ResponsesStreamRequest (96-96)
  • SpeechStreamRequest (99-99)
  • TranscriptionStreamRequest (101-101)
  • BifrostContextKeyFallbackIndex (129-129)
  • BifrostContextKeyRequestID (123-123)
  • BifrostContextKeyFallbackRequestID (124-124)
  • BifrostContextKeySpanID (143-143)
  • BifrostContextKeyStreamEndIndicator (130-130)
  • BifrostContextKeyStreamStartTime (145-145)
  • RequestType (87-87)
  • BifrostContextKeySelectedKeyID (126-126)
  • BifrostContextKeySelectedKeyName (127-127)
  • BifrostContextKeyPostHookSpanFinalizer (149-149)
  • BifrostContextKeyDirectKey (125-125)
core/utils.go (1)
  • IsStreamRequestType (197-199)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Graphite / mergeability_check
  • GitHub Check: Graphite / mergeability_check
  • GitHub Check: Graphite / mergeability_check
  • GitHub Check: Graphite / mergeability_check
  • GitHub Check: Graphite / mergeability_check
🔇 Additional comments (29)
core/schemas/mcp.go (1)

24-24: LGTM! Public API migration to BifrostContext is consistent.

The function signature update aligns with the broader context migration across the codebase. This is a breaking change but appears coordinated across the stack.

core/schemas/bifrost.go (1)

13-13: LGTM! KeySelector migration to BifrostContext is correct.

The signature update is consistent with the broader migration. Note that the original signature used *context.Context (pointer to interface), while the new signature uses *BifrostContext (pointer to struct), which is the correct pattern for the custom context type.

core/schemas/account.go (1)

89-89: LGTM! Account interface updated consistently with BifrostContext migration.

The method signature change is part of the coordinated context migration. All implementations must be updated to match this interface change.

transports/bifrost-http/integrations/router.go (3)

101-211: LGTM on type signature updates.

The converter function type signatures have been consistently updated from context.Context to *schemas.BifrostContext, aligning with the broader migration across the codebase.


396-399: LGTM on context value setting pattern.

The migration from context.WithValue to bifrostCtx.SetValue(...) is correctly applied for setting context values like BifrostContextKeySendBackRawResponse, BifrostContextKeyIntegrationType, and BifrostContextKeyDirectKey.

Also applies to: 435-436


728-854: LGTM on handleBatchRequest implementation.

The function correctly uses bifrostCtx directly in all client method calls (lines 738, 760, 782, 804, 826), properly leveraging the new *schemas.BifrostContext type.

transports/bifrost-http/lib/ctx.go (2)

80-94: LGTM on ConvertToBifrostContext signature and initialization.

The function signature correctly returns (*schemas.BifrostContext, context.CancelFunc), and the initialization properly uses schemas.NewBifrostContextWithCancel(ctx) to create the cancellable Bifrost context. The SetValue pattern is consistently applied for setting context values.


157-407: LGTM on context value population.

All context.WithValue calls have been uniformly replaced with bifrostCtx.SetValue(...) for various context keys including:

  • Prometheus labels
  • Maxim tracing headers
  • MCP control headers
  • Virtual key and API key headers
  • Cache-related values
  • Extra headers
  • Direct keys
  • Fallback context

The function correctly returns the bifrost context directly at line 407.

transports/bifrost-http/server/server.go (3)

86-86: LGTM on server context field type change.

The ctx field in BifrostHTTPServer is correctly updated to *schemas.BifrostContext, aligning with the new context type used throughout the codebase.


930-934: LGTM on RefetchModelsForProvider context handling.

The method correctly creates a new BifrostContext using schemas.NewBifrostContext(ctx, schemas.NoDeadline), defers bfCtx.Cancel() for proper cleanup, and passes the context to ListModelsRequest.


1185-1185: LGTM on Bootstrap context initialization and usage.

  • Line 1185: Correctly initializes server context using schemas.NewBifrostContextWithCancel(ctx).
  • Lines 1242-1244: MCP config's FetchNewRequestIDFunc signature is properly updated to accept *schemas.BifrostContext.
  • Line 1264: ListAllModels correctly uses s.ctx (now a *schemas.BifrostContext).

Also applies to: 1242-1244, 1264-1264

transports/bifrost-http/integrations/utils.go (1)

138-198: LGTM on utility function signature updates.

The sendStreamError, sendError, and sendSuccess functions have been correctly updated to accept bifrostCtx *schemas.BifrostContext, aligning with the broader migration. The context package import has been appropriately removed since it's no longer needed.

core/mcp/agentadaptors.go (1)

54-54: LGTM on agent adaptor context type updates.

The agentAPIAdapter interface and its implementations (chatAPIAdapter, responsesAPIAdapter) have been correctly updated:

  • Interface method makeLLMCall now accepts *schemas.BifrostContext
  • makeReq field types updated to use *schemas.BifrostContext in the callback signatures
  • Concrete implementations on lines 159-162 and 372-375 correctly use the new context type

The context package import has been appropriately removed.

Also applies to: 69-70, 89-90, 159-162, 372-375

core/mcp/mcp.go (2)

133-147: LGTM on ExecuteChatTool and ExecuteResponsesTool signature updates.

Both methods now correctly accept ctx *schemas.BifrostContext, aligning with the broader context type migration.


180-201: LGTM on agent execution entry point signatures.

CheckAndExecuteAgentForChatRequest and CheckAndExecuteAgentForResponsesRequest have been correctly updated:

  • The ctx parameter now accepts *schemas.BifrostContext
  • The makeReq callback signatures are updated to accept *schemas.BifrostContext

This aligns with the changes in agent.go and agentadaptors.go.

Also applies to: 231-252

core/mcp/agent.go (5)

29-63: LGTM on ExecuteAgentForChatRequest context type updates.

The function signature and callback types are correctly updated to use *schemas.BifrostContext, enabling the new context semantics throughout the agent execution flow.


82-116: LGTM on ExecuteAgentForResponsesRequest context type updates.

Consistent with the Chat API counterpart, this function correctly uses *schemas.BifrostContext throughout.


134-160: LGTM on executeAgent helper context handling.

The internal helper correctly:

  • Accepts *schemas.BifrostContext as the context parameter
  • Uses ctx.Value() to retrieve the original request ID (line 156)
  • Uses ctx.SetValue() to store the agent's original request ID (line 158)

336-343: LGTM on request ID propagation.

The agent loop correctly uses ctx.SetValue() to update the request ID before making subsequent LLM calls, maintaining proper request tracking across agent iterations.


428-430: No issues found. *schemas.BifrostContext fully implements the context.Context interface with all four required methods (Deadline(), Done(), Err(), and Value()), so passing it to GetToolPerClient() is valid and compatible.

core/mcp/toolmanager.go (2)

322-322: LGTM: Systematic context type migration.

The method signatures have been consistently updated to use *schemas.BifrostContext. The changes maintain the same logical flow while adopting the new context type.

Also applies to: 436-437, 481-485, 512-516


19-19: No action needed—BifrostContext properly implements context.Context interface.

*schemas.BifrostContext fully implements the context.Context interface with all required methods (Deadline, Done, Err, Value), so passing it to ClientManager.GetToolPerClient(ctx context.Context) is valid and correct. The implementation is sound.

core/schemas/provider.go (1)

314-365: LGTM: Systematic Provider interface migration to BifrostContext.

The Provider interface and PostHookRunner have been consistently updated to use *schemas.BifrostContext instead of context.Context. This is a breaking change that requires all provider implementations to be updated, but given this is part of a broader stack migration (PR #1262 building on #1242), the systematic approach is appropriate.

Note: As per the coding guidelines to review in light of the whole stack, this change aligns with the broader BifrostContext migration across the codebase.

core/bifrost.go (6)

136-139: LGTM: Proper BifrostContext initialization.

The Init function correctly wraps the incoming context.Context in a BifrostContext using NewBifrostContextWithCancel. This establishes the context lifecycle for the entire Bifrost instance.


302-304: LGTM: Consistent nil context handling.

The code defensively handles nil contexts by falling back to bifrost.ctx throughout public API methods. This prevents nil pointer panics and provides a sensible default context.

Also applies to: 632-634, 728-730


2884-2926: LGTM: executeRequestWithRetries correctly uses BifrostContext.

The generic executeRequestWithRetries function properly:

  • Accepts *schemas.BifrostContext as parameter (line 2885)
  • Uses SetValue to track retry attempts (line 2898)
  • Retrieves tracer from context with type assertion (lines 2921-2925)
  • Updates span context appropriately (line 2949)

3364-3380: Note: Plugin interface breaking change.

The PluginPipeline.RunPreHooks and RunPostHooks methods now pass *schemas.BifrostContext to plugin hooks (lines 3380, 3428, 3446). This is a breaking change that requires all plugin implementations to update their hook signatures.

This aligns with the broader migration strategy across the stack.

Also applies to: 3408-3446


3917-3939: LGTM: KeySelector signature updated for consistency.

WeightedRandomKeySelector signature updated to accept *schemas.BifrostContext (line 3917), though the context is not used in the implementation. This is appropriate for interface consistency with the KeySelector type definition (line 75 in the broader code).


367-367: SetValue is already properly synchronized.

The BifrostContext.SetValue() method in core/schemas/context.go correctly implements thread-safe synchronization using sync.RWMutex. The implementation properly acquires bc.valuesMu lock for the entire duration of the write operation and uses defer to guarantee unlock on exit. The code even includes a comment confirming: "This is thread-safe and can be called concurrently." No concurrency issues exist with the current implementation.

Likely an incorrect or invalid review comment.

@akshaydeo akshaydeo force-pushed the 01-07-move_to_schemas.bifrostcontext branch from f3775fb to bd2418a Compare January 7, 2026 04:14
@coderabbitai coderabbitai Bot requested review from danpiths and roroghost17 January 7, 2026 04:16
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

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

51-51: Remove explicit dereferencing in BifrostContext.Value() call.

The BifrostContext.Value() method is defined with a pointer receiver. In Go, you can call pointer receiver methods directly on the pointer variable without explicit dereferencing—use ctx.Value(...) instead of (*ctx).Value(...) for idiomatic code. Go automatically handles the dereferencing.

core/bifrost_test.go (1)

703-710: Update line 656 to remove unnecessary context wrapping.

The Init function signature is func Init(ctx context.Context, config schemas.BifrostConfig) (*Bifrost, error) and internally wraps the context via schemas.NewBifrostContextWithCancel(ctx) at line 136 of core/bifrost.go. Line 656 unnecessarily pre-wraps context.Background() in schemas.NewBifrostContext before passing it to Init, causing double-wrapping. Lines 703, 729, 771, 831, 884, and 937 correctly pass context.Background() directly. Update line 656 to match this pattern:

ctx := context.Background()
bifrost, err := Init(ctx, schemas.BifrostConfig{
core/bifrost.go (1)

2353-2450: PluginPipeline reuse in streaming short-circuit can race after being returned to the pool

In tryStreamRequest, a PluginPipeline is acquired and scheduled for releasePluginPipeline via defer, but in the shortCircuit.Stream != nil path you start a goroutine that continues to call pipeline.RunPostHooks via pipelinePostHookRunner after tryStreamRequest returns. At that point the deferred releasePluginPipeline has already reset and put the pipeline back into the pool, so the goroutine can mutate a reused instance, causing data races and corrupted hook state.

You’re already handling streaming lifetime correctly in requestWorker by tying pipeline release to a finalizer callback; here you need analogous ownership for the short-circuit streaming path.

Proposed fix: release PluginPipeline only after streaming goroutine finishes

One way to fix this is to avoid deferring the release for the streaming short‑circuit branch and instead release the pipeline in the goroutine when the stream ends:

 func (bifrost *Bifrost) tryStreamRequest(ctx *schemas.BifrostContext, req *schemas.BifrostRequest) (chan *schemas.BifrostStream, *schemas.BifrostError) {
-    pipeline := bifrost.getPluginPipeline()
-    defer bifrost.releasePluginPipeline(pipeline)
+    pipeline := bifrost.getPluginPipeline()
+    pipelineReleased := false
+    defer func() {
+        if !pipelineReleased {
+            bifrost.releasePluginPipeline(pipeline)
+        }
+    }()

@@
-        if shortCircuit.Stream != nil {
+        if shortCircuit.Stream != nil {
             outputStream := make(chan *schemas.BifrostStream)
@@
-            pipelinePostHookRunner := func(ctx *schemas.BifrostContext, result *schemas.BifrostResponse, err *schemas.BifrostError) (*schemas.BifrostResponse, *schemas.BifrostError) {
+            pipelinePostHookRunner := func(ctx *schemas.BifrostContext, result *schemas.BifrostResponse, err *schemas.BifrostError) (*schemas.BifrostResponse, *schemas.BifrostError) {
                 return pipeline.RunPostHooks(ctx, result, err, preCount)
             }
 
-            go func() {
-                defer close(outputStream)
+            go func() {
+                defer func() {
+                    close(outputStream)
+                    bifrost.releasePluginPipeline(pipeline)
+                }()
@@
             }()
 
+            // Ownership of the pipeline has moved to the goroutine.
+            pipelineReleased = true
             return outputStream, nil
         }

This keeps the existing defer for all non-streaming and non-short‑circuit paths, but ensures that in the streaming short‑circuit case the pipeline is only reset and returned to the pool after the goroutine finishes processing the stream.

Also applies to: 2467-2564, 2727-2793

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

176-198: ChatCompletionStream should honor context-derived path overrides

ChatCompletion uses providerUtils.GetPathFromContext(ctx, "/v1/chat/completions"), but ChatCompletionStream still hardcodes "/v1/chat/completions" without going through GetPathFromContext. That means any path overrides injected via BifrostContext (e.g., integration-specific routing) will apply to non-streaming requests but not to streaming ones.

To keep routing consistent and avoid subtle bugs when paths are customized, consider updating the streaming path to mirror the non-streaming variant:

Proposed fix
 func (provider *GroqProvider) ChatCompletionStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, key schemas.Key, request *schemas.BifrostChatRequest) (chan *schemas.BifrostStream, *schemas.BifrostError) {
@@
-	return openai.HandleOpenAIChatCompletionStreaming(
-		ctx,
-		provider.client,
-		provider.networkConfig.BaseURL+"/v1/chat/completions",
+	return openai.HandleOpenAIChatCompletionStreaming(
+		ctx,
+		provider.client,
+		provider.networkConfig.BaseURL+providerUtils.GetPathFromContext(ctx, "/v1/chat/completions"),
 		request,
core/providers/cerebras/cerebras.go (1)

79-92: Align Cerebras streaming paths with context-aware routing

For Cerebras, non-streaming endpoints already use providerUtils.GetPathFromContext, but the streaming variants still hardcode paths:

  • TextCompletionStream uses BaseURL+"/v1/completions".
  • ChatCompletionStream uses BaseURL+"/v1/chat/completions".

This means any per-request path override injected via BifrostContext applies to synchronous calls but not to streaming calls, which can break integrations that rely on GetPathFromContext for routing.

Updating the streaming functions to mirror the non-streaming path construction will make behavior consistent:

Proposed fix
 func (provider *CerebrasProvider) TextCompletionStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, key schemas.Key, request *schemas.BifrostTextCompletionRequest) (chan *schemas.BifrostStream, *schemas.BifrostError) {
@@
-	return openai.HandleOpenAITextCompletionStreaming(
-		ctx,
-		provider.client,
-		provider.networkConfig.BaseURL+"/v1/completions",
+	return openai.HandleOpenAITextCompletionStreaming(
+		ctx,
+		provider.client,
+		provider.networkConfig.BaseURL+providerUtils.GetPathFromContext(ctx, "/v1/completions"),
@@
 func (provider *CerebrasProvider) ChatCompletionStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, key schemas.Key, request *schemas.BifrostChatRequest) (chan *schemas.BifrostStream, *schemas.BifrostError) {
@@
-	return openai.HandleOpenAIChatCompletionStreaming(
-		ctx,
-		provider.client,
-		provider.networkConfig.BaseURL+"/v1/chat/completions",
+	return openai.HandleOpenAIChatCompletionStreaming(
+		ctx,
+		provider.client,
+		provider.networkConfig.BaseURL+providerUtils.GetPathFromContext(ctx, "/v1/chat/completions"),

Also applies to: 97-117, 119-133, 139-161

🤖 Fix all issues with AI agents
In @core/internal/testutil/speech_synthesis.go:
- Around line 16-17: The unused parameter ctx in both RunSpeechSynthesisTest and
RunSpeechSynthesisAdvancedTest causes a Go compile error; to fix it with no
runtime change, rename the parameter from ctx to _ in both function signatures
so the incoming *schemas.BifrostContext is ignored; leave the existing creation
of requestCtx := context.Background() and other code paths unchanged (this is
the minimal change to compile without threading the BifrostContext into
SpeechRequest calls).
🧹 Nitpick comments (22)
core/providers/utils/utils.go (1)

835-874: Pointer-based BifrostContext in streaming utilities improves safety and matches new span-finalization flow

Switching Send*ResponsesChunk, ProcessAndSend* helpers, and completeDeferredSpan to accept *schemas.BifrostContext (and invoking postHookRunner(ctx, ...) directly) removes the prior by-value copies of BifrostContext, which is safer given the embedded mutexes and Once fields. The checks for BifrostContextKeyStreamEndIndicator before calling completeDeferredSpan now line up with providers setting this flag via ctx.SetValue, and the finalizer invocation using context.WithValue(ctx, BifrostContextKeySpanID, spanID) remains correct assuming *BifrostContext implements context.Context. Overall, the streaming + tracing pipeline remains logically intact with a cleaner context model.

Also applies to: 881-931, 939-981, 988-1033, 1284-1325, 1428-1513

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

123-251: Anthropic: BifrostContext wiring, Files/Batch/CountTokens look correct, with a small URL-building inconsistency

The switch to *schemas.BifrostContext in buildRequestURL, completeRequest, list models, text/chat/response completions, batch operations, file APIs, and CountTokens consistently passes ctx into helpers like GetRequestPath, SetExtraHeaders, MakeRequestWithContext, and CheckContextAndGetRequestBody, so behavior is preserved while enabling Bifrost-specific context values. New File APIs (upload/list/retrieve/delete/content) and Batch helpers use Anthropic’s expected endpoints, headers (including anthropic-version and anthropic-beta where needed), and standardized HandleProviderResponse + NewUnsupportedOperationError patterns, with pagination handled via NewSerialListHelper where appropriate.

One minor inconsistency: some endpoints (BatchCancel, BatchResults, FileDelete, FileContent) still construct URLs with provider.networkConfig.BaseURL + "/..." instead of going through buildRequestURL(...). That means they won’t respect per-request path overrides or custom provider path mappings the way other methods do. If you intend all Anthropic endpoints to be configurable in the same way, consider routing these through buildRequestURL as well for consistency.

Also applies to: 176-231, 237-374, 693-742, 1033-1329, 1547-1576, 1579-1783, 1785-2057, 2059-2125

core/mcp/agent_test.go (1)

19-19: Update MockLLMCaller to use BifrostContext for type consistency.

The MockLLMCaller methods still accept context.Context, but the test closures now pass *schemas.BifrostContext (lines 223-225, 283-285, 397-399, 445-447). While BifrostContext likely implements the context.Context interface (allowing this to work), the mock should be updated for type safety and consistency with the real BifrostLLMCaller interface.

🔎 Proposed update to MockLLMCaller signatures
-func (m *MockLLMCaller) ChatCompletionRequest(ctx context.Context, req *schemas.BifrostChatRequest) (*schemas.BifrostChatResponse, *schemas.BifrostError) {
+func (m *MockLLMCaller) ChatCompletionRequest(ctx *schemas.BifrostContext, req *schemas.BifrostChatRequest) (*schemas.BifrostChatResponse, *schemas.BifrostError) {
 	if m.chatCallCount >= len(m.chatResponses) {
 		return nil, &schemas.BifrostError{
 			IsBifrostError: false,
 			Error: &schemas.ErrorField{
 				Message: "no more mock chat responses available",
 			},
 		}
 	}
 
 	response := m.chatResponses[m.chatCallCount]
 	m.chatCallCount++
 	return response, nil
 }
 
-func (m *MockLLMCaller) ResponsesRequest(ctx context.Context, req *schemas.BifrostResponsesRequest) (*schemas.BifrostResponsesResponse, *schemas.BifrostError) {
+func (m *MockLLMCaller) ResponsesRequest(ctx *schemas.BifrostContext, req *schemas.BifrostResponsesRequest) (*schemas.BifrostResponsesResponse, *schemas.BifrostError) {
 	if m.responsesCallCount >= len(m.responsesResponses) {
 		return nil, &schemas.BifrostError{
 			IsBifrostError: false,
 			Error: &schemas.ErrorField{
 				Message: "no more mock responses api responses available",
 			},
 		}
 	}
 
 	response := m.responsesResponses[m.responsesCallCount]
 	m.responsesCallCount++
 	return response, nil
 }

Also applies to: 34-34

core/providers/bedrock/bedrock_test.go (2)

680-680: Add space after comma for Go formatting conventions.

Missing whitespace after the comma in the NewBifrostContext call. This pattern appears in multiple locations throughout the file.

🔎 Suggested formatting fix
-			ctx := schemas.NewBifrostContext(context.Background(),schemas.NoDeadline)
+			ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)

708-708: Apply consistent spacing after commas.

The same formatting issue (missing space after comma) appears on lines 708, 1778, 1989, and 2016. Apply the same fix to maintain consistent Go formatting throughout the test file.

Also applies to: 1778-1778, 1989-1989, 2016-2016

core/providers/bedrock/chat.go (1)

50-50: Migrate ToBifrostChatResponse parameter to use BifrostContext for consistency.

ToBedrockChatCompletionRequest (line 15) and other bedrock response converters (ToBifrostResponsesRequest, ToBifrostResponsesResponse in responses.go) now use *schemas.BifrostContext, but ToBifrostChatResponse still accepts context.Context. The call site at line 724 in bedrock.go already passes BifrostContext, so this migration aligns with the ongoing refactoring effort and eliminates the inconsistency across the provider.

plugins/mocker/plugin_test.go (1)

24-32: Unused ctx in test account mock is acceptable

BaseAccount.GetKeysForProvider correctly matches the updated Account interface but does not use ctx. That's fine for a test stub; if linters start complaining, consider renaming the parameter to _ *schemas.BifrostContext to make the intent explicit.

transports/bifrost-http/integrations/openai.go (1)

38-97: Pre‑request hooks now accept BifrostContext but don’t use it yet

AzureEndpointPreHook, setQueryParamsAndAzureEndpointPreHook, and the various extract* helpers correctly plumb *schemas.BifrostContext through their signatures and into nested hooks, but the value isn’t read yet. That’s fine for now; if you later need per‑request flags (e.g. structured output, tracing, or direct-key hints), you can store them on bifrostCtx instead of fasthttp.RequestCtx.UserValue.

Also applies to: 454-479, 976-1013, 1015-1058, 1060-1137, 1139-1221

core/internal/testutil/speech_synthesis_stream.go (1)

17-118: Streaming speech tests correctly construct per‑scenario BifrostContexts (but ignore the incoming ctx)

Both streaming helpers now create a fresh *schemas.BifrostContext via schemas.NewBifrostContext(context.Background(), schemas.NoDeadline) for each scenario and use that with SpeechStreamRequest, which is consistent with the new API. The ctx *schemas.BifrostContext parameter on the helpers is currently unused; if the testutil API doesn’t rely on it elsewhere, consider either wiring it into the per‑scenario context creation or removing it to avoid confusion.

Also applies to: 251-255, 309-313, 455-466

transports/bifrost-http/integrations/anthropic.go (2)

227-235: Redundant pointer dereference in context value access.

ctx is already *schemas.BifrostContext, so (*ctx).Value(...) can be simplified to ctx.Value(...). The dereference is unnecessary and reduces readability.

This pattern appears in multiple places in this file (lines 229, 323, 394, 436, 472, 508, 732, 777, 818, 855).

🔎 Proposed fix
 func shouldUsePassthrough(ctx *schemas.BifrostContext, provider schemas.ModelProvider, model string, deployment string) bool {
 	isClaudeCode := false
-	if userAgent, ok := (*ctx).Value(schemas.BifrostContextKeyUserAgent).(string); ok {
+	if userAgent, ok := ctx.Value(schemas.BifrostContextKeyUserAgent).(string); ok {
 		if strings.Contains(userAgent, "claude-cli") {
 			isClaudeCode = true
 		}
 	}
 	return isClaudeCode && isClaudeModel(model, deployment, string(provider))
 }

317-326: Same redundant dereference pattern in BatchRequestConverter.

Line 323 uses (*ctx).Value(bifrostContextKeyProvider) - should be ctx.Value(...).

🔎 Proposed fix
-			if provider, ok = (*ctx).Value(bifrostContextKeyProvider).(schemas.ModelProvider); ok && provider != schemas.Anthropic {
+			if provider, ok = ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider); ok && provider != schemas.Anthropic {
core/schemas/provider.go (1)

314-366: Provider/PostHookRunner API now explicitly depends on BifrostContext

Updating PostHookRunner and all Provider methods to take *BifrostContext aligns the public provider API with the new context abstraction (needed for things like per‑request values and stream end markers). This is a clean, consistent change, just be aware it’s a breaking interface update for any out‑of‑tree Provider or PostHookRunner implementations.

core/providers/openai/openai.go (2)

78-205: Non‑streaming OpenAI provider methods are cleanly migrated to BifrostContext

All primary OpenAIProvider entry points (list models, text/chat, responses, embedding, speech, transcription, count tokens, file, and batch ops) now take *schemas.BifrostContext and pass ctx through to providerUtils.* and HTTP helpers without altering behavior. Using BifrostContext here gives hooks and internal plumbing access to per‑request values while remaining compatible with helpers that still accept context.Context.

The one notable inconsistency is HandleOpenAIResponsesRequest, which still takes ctx context.Context while its siblings use *schemas.BifrostContext. That’s functionally fine (BifrostContext should satisfy the interface) but you may want to align its signature for API regularity and to allow direct use of BifrostContext-specific helpers inside it if needed later.

Also applies to: 216-314, 613-715, 1101-1204, 1460-1665, 1916-2044, 2278-2378, 2382-3342


319-608: Stream end signalling via BifrostContext is sensible; consider clarifying context reuse assumptions

The streaming helpers now set ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true) on terminal paths (error chunks and final completion/usage chunks) before invoking ProcessAndSendResponse/ProcessAndSendBifrostError. That’s a good fit for PostHookRunner’s new *BifrostContext signature and lets hooks reliably detect the final event.

This does, however, rely on the implicit contract that each API call uses a fresh *BifrostContext (or that any consumers of this flag treat it as strictly per‑stream and ignore stale values). If there’s any chance a single BifrostContext instance is reused across multiple requests, it might be worth either clearing this key at the start of each streaming call or constructing a per‑stream child context to avoid leaking a true flag into subsequent operations.

Also applies to: 720-1094, 1207-1455, 1669-1910, 2047-2273

core/internal/testutil/structured_outputs.go (1)

203-355: Streaming and Responses structured‑output tests use BifrostContext consistently

All four helpers (RunStructuredOutputChatStreamTest, RunStructuredOutputResponsesTest, RunStructuredOutputResponsesStreamTest) now:

  • Take ctx *schemas.BifrostContext and pass it (or a reqCtx derived by setting BifrostContextKeyExtraHeaders for Claude) into the bifrost client calls.
  • Continue to use context.WithTimeout(ctx, …) only for local test timeouts, not as the actual request context, preserving prior behavior.
  • Keep retry configs and validation logic unchanged, now just riding on BifrostContext instead of plain context.Context.

This is a straightforward, correct migration, and the extra‑header pattern is consistent across chat and responses tests.

Also applies to: 359-488, 491-712

core/bifrost.go (1)

278-380: Tracer reliance on BifrostContext values is consistent but tightly coupled

ListModelsRequest now sets BifrostContextKeyTracer on ctx before calling executeRequestWithRetries, and executeRequestWithRetries expects to read a non-nil schemas.Tracer from that key. Current call sites (this method and the request-worker paths) all set the key first, so behavior matches the previous global-tracer usage, but any future caller of executeRequestWithRetries must remember to populate this key or will see a “tracer not found in context” error.

Consider documenting this contract near executeRequestWithRetries or guarding with a fallback to schemas.DefaultTracer() to make the function safer to reuse.

Also applies to: 2885-2956

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

21-23: Consider centralizing the response-format context key

BifrostContextKeyResponseFormat is defined locally in this file and used in Speech via ctx.SetValue to drive ToBifrostSpeechResponse(ctx). If you expect other providers or transports to read or set this key, it may be worth moving the constant into core/schemas/bifrost.go alongside the other BifrostContextKey definitions to avoid duplication and mismatched literals later.

Also applies to: 969-1015

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

902-1150: Azure SpeechStream: consider marking stream end on [DONE] sentinel as well

SpeechStream now uses ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true) when:

  • Emitting a JSON error decoded from the stream (Line 1076).
  • Sending the final SpeechStreamResponseTypeDone chunk (Line 1140).

However, when the SSE payload is exactly [DONE], the goroutine returns immediately without setting the end-indicator and without emitting a final “done” response (Lines 1055–1061). If any downstream code relies on BifrostContextKeyStreamEndIndicator to know the stream has fully terminated (especially for non‑[DONE] providers), it may miss this early‑exit path.

Consider also setting the end-indicator in the [DONE] branch, for example:

Possible tweak to cover the `[DONE]` path
-                    if bytes.Equal(audioData, []byte("[DONE]")) {
-                        return
-                    }
+                    if bytes.Equal(audioData, []byte("[DONE]")) {
+                        ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true)
+                        return
+                    }

Please double‑check how BifrostContextKeyStreamEndIndicator is consumed in the HTTP/router layer for Azure speech streams to confirm whether this additional marker is desirable, and adjust if tests around stream completion expect it.

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

681-751: Bedrock ChatCompletion/ChatCompletionStream: BifrostContext integration is good; minor consistency nit on error end-flag

ChatCompletion and ChatCompletionStream now pass *schemas.BifrostContext into the Bedrock converters (ToBedrockChatCompletionRequest(ctx, ...)), completeRequest, and the eventstream decoder. Stream state (usage, finishReason, IDs, etc.) is unchanged.

In ChatCompletionStream you mark the stream end via ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true):

  • When ToBifrostChatCompletionStream reports a BifrostError (Lines 871–881).
  • Before emitting the final aggregated chunk response (Lines 913–915).

You do not set the flag on low‑level decode errors from decoder.Decode (Lines 799–808), where you instead log and forward an error response. For symmetry with TextCompletionStream and ResponsesStream, you may want to also set the end‑indicator in that decode‑error path so all terminal cases set the same flag.

Optional consistency tweak for the decode-error path
-            message, err := decoder.Decode(resp.Body, payloadBuf)
-            if err != nil {
-                if err == io.EOF {
-                    // End of stream - this is normal
-                    break
-                }
-                provider.logger.Warn(fmt.Sprintf("Error decoding %s EventStream message: %v", providerName, err))
-                providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ChatCompletionStreamRequest, providerName, request.Model, provider.logger)
-                return
-            }
+            message, err := decoder.Decode(resp.Body, payloadBuf)
+            if err != nil {
+                if err == io.EOF {
+                    // End of stream - this is normal
+                    break
+                }
+                ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true)
+                provider.logger.Warn(fmt.Sprintf("Error decoding %s EventStream message: %v", providerName, err))
+                providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ChatCompletionStreamRequest, providerName, request.Model, provider.logger)
+                return
+            }

Please verify how the router checks BifrostContextKeyStreamEndIndicator for Bedrock chat streams; if it treats any channel close as sufficient, this tweak is optional, but aligning behavior across all error/EOF cases can simplify reasoning and debugging.

Also applies to: 755-918

transports/bifrost-http/lib/ctx.go (1)

80-91: ConvertToBifrostContext migration looks correct; consider updating docs

The switch to schemas.NewBifrostContextWithCancel(ctx) plus bifrostCtx.SetValue(...) for all header- and key-derived values keeps behavior consistent while centralizing on *schemas.BifrostContext. Key usages (BifrostContextKeyRequestID, virtual/api keys, cache keys/TTL/threshold/type, extra headers, Maxim tags, direct key, fallback flag) all map cleanly to the new context type.

The function comment above still describes returning *context.Context, which is now outdated; you may want to update it to mention *schemas.BifrostContext and that values are stored via SetValue.

Also applies to: 157-205, 207-213, 223-225, 227-234, 238-259, 264-287, 290-307, 313-337, 339-342, 348-356, 391-400, 403-405, 407-407

transports/bifrost-http/server/server.go (1)

86-87: Server ctx migration to BifrostContext is coherent; small consistency tweak optional

Using *schemas.BifrostContext as the server’s root ctx and wiring it through Bootstrap, model listing, and route registration aligns with the new client API, and RefetchModelsForProvider correctly wraps the incoming context.Context in a BifrostContext before calling ListModelsRequest.

For helpers like ExecuteChatMCPTool / ExecuteResponsesMCPTool, you might optionally standardize on NewBifrostContextWithCancel and defer cancel() rather than calling NewBifrostContext without any explicit cancellation, to keep lifecycle management uniform across these entry points.

Also applies to: 498-507, 932-935, 1185-1188, 1243-1247, 1266-1267, 1292-1293, 1318-1319

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

48-60: Bedrock parameter converters now correctly use BifrostContext; minor robustness tweak optional

Switching convertChatParameters and the structured-output helpers to take a *schemas.BifrostContext and record BifrostContextKeyStructuredOutputToolName via ctx.SetValue(...) preserves the previous behavior while aligning with the new context type. Tool insertion and forced ToolChoice wiring remain unchanged.

To harden against accidental nil usage in the future, you might optionally guard the SetValue calls:

if ctx != nil {
    ctx.SetValue(schemas.BifrostContextKeyStructuredOutputToolName, toolName)
}

but this isn’t strictly necessary if all call sites guarantee a non-nil ctx.

Also applies to: 182-185, 678-721, 735-757

Comment thread core/internal/testutil/speech_synthesis.go
@akshaydeo akshaydeo force-pushed the 01-07-move_to_schemas.bifrostcontext branch from bd2418a to a061a86 Compare January 7, 2026 06:55
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (4)
plugins/jsonparser/plugin_test.go (1)

153-181: Inconsistent context usage: bifrost.Init receives context.Context instead of *schemas.BifrostContext.

Line 154 uses plain context.Background() which is then passed to bifrost.Init at line 173. However, based on the PR's migration pattern, bifrost.Init should receive a *schemas.BifrostContext. This creates inconsistency with TestJsonParserPluginEndToEnd which properly uses a BifrostContext.

🔎 Suggested fix
 func TestJsonParserPluginPerRequest(t *testing.T) {
-	ctx := context.Background()
+	ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
 	// Check if OpenAI API key is set
 	if os.Getenv("OPENAI_API_KEY") == "" {
 		t.Skip("OPENAI_API_KEY is not set, skipping per-request test")
core/bifrost_test.go (1)

698-711: Incomplete migration: several UpdateProvider tests still use context.Background() directly.

Multiple tests in this file still use plain context.Background() when calling bifrost.Init:

  • TestUpdateProvider_UpdateNonExistentProvider (line 703)
  • TestUpdateProvider_UpdateInactiveProvider (line 729)
  • TestUpdateProvider_MultipleProviderUpdates (line 771)
  • TestUpdateProvider_ConcurrentProviderUpdates (line 831)
  • TestUpdateProvider_ProviderSliceIntegrity (lines 884, 937)

This is inconsistent with TestUpdateProvider_SuccessfulUpdate (line 656) which correctly uses schemas.NewBifrostContext.

🔎 Suggested fixes (apply to each occurrence)
-	ctx := context.Background()
+	ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)

Also applies to: 725-737, 764-778, 826-838, 878-892, 933-945

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

1122-1204: Fix inconsistent context type in HandleOpenAIResponsesRequest.

The HandleOpenAIResponsesRequest function signature still uses context.Context instead of *schemas.BifrostContext. This is inconsistent with:

  • The calling function Responses (line 1101) which passes *schemas.BifrostContext
  • All other HandleOpenAI*Request functions in this file which use *schemas.BifrostContext
  • The broader migration pattern across the codebase

This will cause compilation errors or type mismatches.

🔎 Proposed fix
 func HandleOpenAIResponsesRequest(
-	ctx context.Context,
+	ctx *schemas.BifrostContext,
 	client *fasthttp.Client,
 	url string,
 	request *schemas.BifrostResponsesRequest,
core/bifrost.go (1)

385-518: Guard against nil ctx in ListAllModels to avoid panics

ListAllModels uses ctx.Done() in the worker goroutines but never normalizes a nil ctx, unlike most other public APIs that fall back to bifrost.ctx. Calling ListAllModels(nil, req) will panic.

Consider aligning this with the rest of the API by defaulting a nil ctx to bifrost.ctx up front.

Proposed fix
 func (bifrost *Bifrost) ListAllModels(ctx *schemas.BifrostContext, request *schemas.BifrostListModelsRequest) (*schemas.BifrostListModelsResponse, *schemas.BifrostError) {
-	if request == nil {
+	if ctx == nil {
+		ctx = bifrost.ctx
+	}
+
+	if request == nil {
 		request = &schemas.BifrostListModelsRequest{}
 	}
🧹 Nitpick comments (10)
core/internal/testutil/setup.go (1)

34-48: Potential type mismatch between getBifrost and SetupTest.

SetupTest creates a *schemas.BifrostContext (line 52) and passes it to getBifrost (line 53), but getBifrost declares its parameter as context.Context (line 34). Since BifrostContext implements the context.Context interface, this will compile, but it creates an inconsistency with the PR's migration goal.

Consider updating getBifrost to accept *schemas.BifrostContext for consistency:

🔎 Suggested change
-func getBifrost(ctx context.Context) (*bifrost.Bifrost, error) {
+func getBifrost(ctx *schemas.BifrostContext) (*bifrost.Bifrost, error) {

Also applies to: 51-59

core/providers/bedrock/bedrock_test.go (1)

680-680: Fix formatting: missing space after comma in NewBifrostContext calls.

Multiple NewBifrostContext calls are missing a space after the comma, making the code less readable.

🔎 Proposed formatting fix
-			ctx := schemas.NewBifrostContext(context.Background(),schemas.NoDeadline)
+			ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)

Apply this formatting fix at lines 680, 708, 1778, 1989, and 2016.

Also applies to: 708-708, 1778-1778, 1989-1989, 2016-2016

core/internal/testutil/structured_outputs.go (1)

103-134: Avoid leaking Anthropic extra headers across calls by deriving a per‑request context

reqCtx := ctx followed by reqCtx.SetValue(BifrostContextKeyExtraHeaders, extraHeaders) mutates the shared *schemas.BifrostContext. If the same ctx is reused across multiple tests or operations (especially with t.Parallel), Anthropic headers set for claude models can inadvertently affect subsequent non‑claude calls.

Consider deriving a per‑request context instead of mutating the caller’s context (e.g., a NewBifrostContextWithValue helper or equivalent) so header scope is confined to the current operation.

Also applies to: 219-247, 375-431, 512-563

transports/bifrost-http/integrations/openai.go (1)

38-97: Verify direct‑key propagation from Azure HTTP layer into BifrostContext

AzureEndpointPreHook and the batch/file pre‑callbacks still record direct keys on the fasthttp.RequestCtx (via SetUserValue), while core key‑selection logic now checks ctx.Value(schemas.BifrostContextKeyDirectKey) on *schemas.BifrostContext.

Please double‑check that the HTTP router (or middleware) copies this direct‑key value from the request context into the BifrostContext before invoking core APIs; otherwise, Azure direct‑key flows may bypass the new BifrostContext‑based key selection path.

Also applies to: 455-479, 976-1013, 1060-1137, 1140-1221

core/bifrost.go (1)

3794-3915: Make selectKeyFromProviderForModel nil‑safe for future callers

selectKeyFromProviderForModel uses ctx.Value(...) without guarding against ctx == nil in the skipKeySelection check:

if skipKeySelection, ok := ctx.Value(schemas.BifrostContextKeySkipKeySelection).(bool); ok && skipKeySelection ...

Today it’s only called with non‑nil req.Context, so this isn’t an immediate bug, but adding a ctx != nil guard will prevent accidental panics if the function is reused elsewhere and brings it in line with the checks already used in getAllSupportedKeys/getKeysForBatchAndFileOps.

Proposed tweak
-	// Check if key skipping is allowed
-	if skipKeySelection, ok := ctx.Value(schemas.BifrostContextKeySkipKeySelection).(bool); ok && skipKeySelection && isKeySkippingAllowed(providerKey) {
-		return schemas.Key{}, nil
-	}
+	// Check if key skipping is allowed
+	if ctx != nil {
+		if skipKeySelection, ok := ctx.Value(schemas.BifrostContextKeySkipKeySelection).(bool); ok && skipKeySelection && isKeySkippingAllowed(providerKey) {
+			return schemas.Key{}, nil
+		}
+	}
core/providers/anthropic/anthropic.go (3)

502-511: Scanner error path doesn’t currently mark stream end or complete spans

For the happy path and most error conditions you set BifrostContextKeyStreamEndIndicator and go through ProcessAndSendResponse / ProcessAndSendBifrostError, which in turn call completeDeferredSpan. However, when scanner.Err() is non-nil you call ProcessAndSendError without setting the stream-end indicator, and ProcessAndSendError itself never finalizes the deferred span. That means streaming spans may be left open (and trace state retained) on lower-level read failures.

Consider either:

  • Setting BifrostContextKeyStreamEndIndicator before ProcessAndSendError, and/or
  • Extending ProcessAndSendError to mirror the stream-end handling used in ProcessAndSendBifrostError (including completeDeferredSpan when the end indicator is set).

The same applies to HandleAnthropicResponsesStream’s scanner.Err() branch.

Also applies to: 665-684


744-785: Responses streaming: BifrostContext integration and end-indicator usage

HandleAnthropicResponsesStream now takes *schemas.BifrostContext and correctly:

  • Uses SetExtraHeaders with the new context type,
  • Marks BifrostContextKeyStreamEndIndicator on empty-body and ToBifrostResponsesStream error paths,
  • Marks it again on the final chunk before calling ProcessAndSendResponse.

This matches the tracing pattern used for chat streaming and should integrate cleanly with completeDeferredSpan. Only the scanner.Err() path (discussed earlier) currently bypasses that end-indicator logic.

Also applies to: 790-1031


1313-1419: BatchCancel/BatchResults and Files endpoints could share buildRequestURL

BatchCancel, BatchResults, FileDelete, and FileContent build request URIs using provider.networkConfig.BaseURL + ".../..." instead of the centralized buildRequestURL. That’s functionally fine, but it bypasses any RequestPathOverrides configured via CustomProviderConfig and is slightly inconsistent with the rest of the file where buildRequestURL is used.

If you want uniform behavior for custom Anthropic endpoints across all operations, consider switching these to buildRequestURL as well (adding the appropriate path and RequestType), and using url.PathEscape for IDs where applicable.

Also applies to: 1421-1526

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

987-1033: ProcessAndSendError still bypasses span completion

ProcessAndSendError now also takes *BifrostContext and wraps scanner errors into a BifrostError, but unlike ProcessAndSendBifrostError it doesn’t look at BifrostContextKeyStreamEndIndicator or call completeDeferredSpan. Given it’s used in streaming readers (e.g., scanner.Err in provider streams), you may want to consider aligning it with the other two helpers so tracing is properly finalized even when the underlying scanner fails.

transports/bifrost-http/integrations/router.go (1)

857-859: Minor: Remove extraneous blank line.

Extra blank line at line 858 can be removed for consistency.

🔎 Proposed fix
 func (g *GenericRouter) handleFileRequest(ctx *fasthttp.RequestCtx, config RouteConfig, req interface{}, fileReq *FileRequest, bifrostCtx *schemas.BifrostContext) {
-	
-
 	var response interface{}

@akshaydeo akshaydeo force-pushed the 01-07-move_to_schemas.bifrostcontext branch 2 times, most recently from ebe3f5a to 5d1fcf4 Compare January 7, 2026 10:41
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (4)
core/internal/testutil/cross_provider_scenarios.go (1)

3-11: Critical: Missing context import for context.WithTimeout usage.

The file removes the context import but still uses context.WithTimeout at lines 568 and 633. This will cause a compilation error.

🐛 Fix: Add context import
 import (
+	"context"
 	"encoding/json"
 	"fmt"
 	"strings"
 	"testing"
core/providers/bedrock/chat.go (1)

50-50: *Update ToBifrostChatResponse to use schemas.BifrostContext for consistency with ToBedrockChatCompletionRequest.

ToBifrostChatResponse accepts context.Context while ToBedrockChatCompletionRequest uses *schemas.BifrostContext. Beyond this asymmetry within Bedrock, ToBifrostChatResponse is also unique—no other provider's response converter takes a context parameter at all. The method uses ctx.Value() to access structured output configuration, which works with the interface type, but the signature should be explicit about *schemas.BifrostContext to align with the request converter and the broader pattern of migrating to BifrostContext throughout the codebase.

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

1122-1133: Inconsistent context type: HandleOpenAIResponsesRequest still uses context.Context.

This function signature uses context.Context while all other Handle* functions in this file have been migrated to *schemas.BifrostContext. This breaks consistency and will cause type mismatches when calling providerUtils.ShouldSendBackRawRequest(ctx, ...) at line 1194, which likely expects *schemas.BifrostContext.

🐛 Proposed fix
 // HandleOpenAIResponsesRequest handles a responses request to OpenAI's API.
 func HandleOpenAIResponsesRequest(
-	ctx context.Context,
+	ctx *schemas.BifrostContext,
 	client *fasthttp.Client,
 	url string,
 	request *schemas.BifrostResponsesRequest,
core/bifrost.go (1)

2353-2461: Document BifrostContext isolation contract to prevent concurrent request metadata interleaving

The handleRequest function mutates *BifrostContext via SetValue calls for FallbackIndex, RequestID, FallbackRequestID, and SpanID. While SetValue is thread-safe via mutex, concurrent requests reusing the same *BifrostContext instance (particularly through the if ctx == nil { ctx = bifrost.ctx } fallback in public API methods) will have their metadata writes interleave, corrupting span relationships and request tracking.

This is safe only if callers guarantee one BifrostContext per logical request. The codebase should enforce or document this invariant explicitly. Consider adding a note to the context type documentation clarifying that BifrostContext instances must not be shared across concurrent requests, and optionally extend the blockRestrictedWrites mechanism to the request boundary to catch violations early.

🤖 Fix all issues with AI agents
In @core/internal/testutil/speech_synthesis_stream.go:
- Line 17: RunSpeechSynthesisStreamTest accepts a ctx but builds new contexts
with context.Background(), breaking propagation; update the function
(RunSpeechSynthesisStreamTest) to use the passed ctx when calling client methods
and creating derived contexts (e.g., replace context.Background() with ctx or
ctxWithCancel := contexts derived from ctx), ensuring cancellation, deadlines,
and values propagate; apply the same replacement for every place in the function
where context.Background() is used (the spots creating fresh contexts during
stream setup/tear-down) so the passed ctx is actually used rather than
discarded.
- Line 252: RunSpeechSynthesisStreamAdvancedTest currently ignores the passed-in
ctx parameter and instead creates a new context locally; update the function to
use the provided ctx (only create a new context if the incoming ctx is nil) so
that context propagation and cancellation work correctly. Specifically, in
RunSpeechSynthesisStreamAdvancedTest replace the local creation of a fresh
context (the variable that was being used around the calls at the advanced test
flow) with the existing ctx parameter, and if ctx == nil then initialize it the
same way existing tests do (create a new context or call the helper used
elsewhere) before using it.
- Line 455: The multi-voice test is creating a fresh context with
schemas.NewBifrostContext(context.Background(), schemas.NoDeadline) instead of
using the incoming ctx parameter; update the code to propagate the provided ctx
into the call (i.e., replace context.Background() with ctx) so the requestCtx
uses the test's context and any cancellations/deadlines are respected; locate
the occurrence of NewBifrostContext in the multi-voice test and make the same
change applied previously at the other location.

In @core/schemas/context.go:
- Around line 88-94: The doc comment for NewBifrostContextWithCancel still
refers to "PluginContext"; update the comment text to reference "BifrostContext"
instead—e.g., change "convenience wrapper around NewPluginContext" to
"convenience wrapper around NewBifrostContext" and ensure other mentions in that
comment use BifrostContext; leave the function implementation
(NewBifrostContextWithCancel and its call to NewBifrostContext) unchanged.

In @examples/plugins/hello-world-wasm-typescript/assembly/index.ts:
- Around line 73-87: The extractJsonBool function yields false positives because
it searches for the substring "true" within an arbitrary proximity instead of
validating the actual JSON value; change extractJsonBool to locate the key token
'"' + key + '"' then find the colon ':' after that key, skip any whitespace,
ensure the next non-whitespace character is not a quote (to avoid string
values), then read the next literal token and return true only if it exactly
equals "true" and false if it equals "false"; this removes the 10-char heuristic
and correctly distinguishes boolean literals from quoted strings or other
fields.
- Around line 128-184: The three hook functions (http_intercept, pre_hook,
post_hook) use unsafe manual JSON extraction/building (via extractJsonObject,
addToJsonObject, extractJsonBool, readString, writeString) and lack
validation/error handling; fix by validating readString output and results of
extractJsonObject/extractJsonBool at the start of each function, and return a
clear error payload (e.g., set error/hook_error/has_error or short_circuit
fields and writeString that error) when parsing fails instead of continuing;
stop constructing JSON via raw concatenation—either use a safe JSON
builder/serializer helper or ensure values are properly escaped before
insertion; make the hardcoded context values ('123','789','456') configurable or
document them and move to constants; add unit tests for edge cases (escaped
characters, nested objects, empty/null fields) and update comments to document
accepted input format and failure behavior.
- Around line 28-68: The manual JSON helpers (extractJsonObject,
extractJsonBool, addToJsonObject) are fragile and incorrect (they mis-handle
keys containing truthy substrings, whitespace, string contexts, escaped
quotes/backslashes, and nullable values); fix by removing the ad-hoc parsing and
either (a) use a proper AssemblyScript JSON library (e.g., json-as with
JSON.Box<T> or assemblyscript-json) to parse/modify objects, or (b) reimplement
the functions as a correct JSON state machine that tracks string/escape context
and nested braces and properly serializes/escapes values; update all call sites
to use the library parsing/boxing APIs or the new robust functions (search for
extractJsonObject, extractJsonBool, addToJsonObject to locate spots to change).
🧹 Nitpick comments (14)
examples/plugins/hello-world-wasm-typescript/assembly/types.ts (1)

1-10: Intentional minimization aligns with the BifrostContext migration.

The decision to strip type definitions and rely on direct JSON manipulation in index.ts is well-documented and appropriate for stub WASM runtime compatibility. This aligns with the broader stack migration to schemas.BifrostContext.

Consider adding a direct file reference for discoverability:

📝 Optional: Add explicit file reference
 // This file is intentionally minimal since we use direct JSON manipulation
 // in index.ts for maximum compatibility with the stub WASM runtime.
+// See ./index.ts for the actual type handling implementation.
examples/plugins/hello-world-wasm-rust/src/lib.rs (1)

62-71: Potential panic on UTF-8 string boundary.

When input_str contains multi-byte UTF-8 characters, slicing by byte index (input_str[start..end]) may panic if start or end fall in the middle of a character. The column number from serde errors is a byte offset, but saturating_sub(50) and + 50 adjustments may land on non-character boundaries.

Consider using char_indices() or the floor_char_boundary method (nightly) for safe slicing, or wrap in a fallback:

♻️ Suggested safer approach
             let error_context = if let Some(col) = extract_column(&e.to_string()) {
-                let start = col.saturating_sub(50);
-                let end = (col + 50).min(input_str.len());
-                format!(" | context: ...{}...", &input_str[start..end])
+                let start = col.saturating_sub(50);
+                let end = (col + 50).min(input_str.len());
+                // Safe slice: find valid UTF-8 boundaries
+                let safe_start = input_str.floor_char_boundary(start);
+                let safe_end = input_str.ceil_char_boundary(end);
+                if safe_start < safe_end {
+                    format!(" | context: ...{}...", &input_str[safe_start..safe_end])
+                } else {
+                    String::new()
+                }
             } else {
                 String::new()
             };

Alternatively, for stable Rust, use .get(start..end).unwrap_or("") which returns None on invalid boundaries:

input_str.get(start..end).map_or(String::new(), |s| format!(" | context: ...{}...", s))
core/internal/testutil/setup.go (1)

34-34: Consider updating getBifrost signature for consistency.

While getBifrost still accepts context.Context (line 34) and works correctly because *schemas.BifrostContext implements the context.Context interface, updating it to accept *schemas.BifrostContext would improve consistency with the broader migration pattern across the codebase.

♻️ Optional signature update
-func getBifrost(ctx context.Context) (*bifrost.Bifrost, error) {
+func getBifrost(ctx *schemas.BifrostContext) (*bifrost.Bifrost, error) {
core/bifrost_test.go (1)

703-710: Consider simplifying context usage in tests rather than standardizing on NewBifrostContext.

Lines 656 and 703 show inconsistent context handling: line 656 pre-converts with schemas.NewBifrostContext(context.Background(), schemas.NoDeadline) while line 703 passes context.Background() directly. Since Init() accepts the context.Context interface and internally converts any context via schemas.NewBifrostContextWithCancel() at line 136 of core/bifrost.go, pre-converting in tests creates redundancy. The simpler approach—passing context.Background() directly—is clearer and avoids unnecessary double-conversion.

transports/bifrost-http/server/server.go (1)

498-501: Consider adding context cleanup.

Both ExecuteChatMCPTool and ExecuteResponsesMCPTool create a new BifrostContext but don't explicitly cancel it. While these are likely short-lived operations, it's generally good practice to clean up contexts:

 func (s *BifrostHTTPServer) ExecuteChatMCPTool(ctx context.Context, toolCall schemas.ChatAssistantMessageToolCall) (*schemas.ChatMessage, *schemas.BifrostError) {
 	bifrostCtx := schemas.NewBifrostContext(ctx, schemas.NoDeadline)
+	defer bifrostCtx.Cancel()
 	return s.Client.ExecuteChatMCPTool(bifrostCtx, toolCall)
 }

However, if the parent ctx is already properly managed (e.g., request context), and the operations are synchronous and fast, the current pattern may be acceptable.

Also applies to: 504-507

core/bifrost.go (2)

278-380: *Public API methods now uniformly accept BifrostContext; watch nil‑ctx fallback semantics

All top‑level request methods (ListModels*, Text/Chat/Responses, Embedding/Speech/Transcription, Batch*, File*) now take *schemas.BifrostContext and in some cases fall back to bifrost.ctx when ctx is nil. Logic and error handling otherwise match the prior structure.

Two minor points to keep in mind:

  • Only some methods defensively default nil ctx to bifrost.ctx (e.g., ListModelsRequest, ChatCompletionRequest, ResponsesRequest, Batch*/File*). Others (notably Text/Embedding/Speech/Transcription) assume a non‑nil ctx. If external callers might pass nil, consider either documenting that requirement or normalizing consistently.
  • When nil fallback is used under concurrency, all such calls will share the same BifrostContext instance; because SetValue is mutating, per‑request keys (request ID, retry count, span ID, etc.) will interleave. If you ever expect concurrent calls with nil ctx, it’s safer to always create a per‑request BifrostContext in the caller and pass that down.

Overall the migration itself is correct, but I’d recommend explicitly stating or enforcing that callers must pass a per‑request *BifrostContext instead of relying on the shared bifrost.ctx except for very controlled internal paths.

Also applies to: 382-518, 520-1057, 1059-1437


3684-3722: Key selection helpers now fully leverage BifrostContext; behavior preserved with extra override hooks

getAllSupportedKeys, getKeysForBatchAndFileOps, and selectKeyFromProviderForModel now all:

  • Accept *schemas.BifrostContext and first look for an explicitly injected schemas.Key via BifrostContextKeyDirectKey.
  • Use ctx.Value(BifrostContextKeySkipKeySelection) and BifrostContextKeyAPIKeyName to support key skipping and per‑name overrides.
  • Fall back to account.GetKeysForProvider(ctx, providerKey) and apply existing filtering logic.

WeightedRandomKeySelector’s signature was updated to use *BifrostContext but the implementation still ignores ctx, which is fine and keeps it usable as a default KeySelector.

These changes look correct and nicely centralize context‑driven overrides.

Also applies to: 3727-3792, 3795-3915, 3917-3939

transports/bifrost-http/integrations/router.go (2)

481-483: Unnecessary pointer dereference when calling Value().

At line 481, (*bifrostCtx).Value(...) uses explicit pointer dereference, but this is inconsistent with other usages in this file where methods are called directly on bifrostCtx (e.g., bifrostCtx.SetValue(...)). Go allows calling methods on pointer receivers without explicit dereference.

Suggested fix
-	if sendRawRequestBody, ok := (*bifrostCtx).Value(schemas.BifrostContextKeyUseRawRequestBody).(bool); ok && sendRawRequestBody {
+	if sendRawRequestBody, ok := bifrostCtx.Value(schemas.BifrostContextKeyUseRawRequestBody).(bool); ok && sendRawRequestBody {

857-858: Minor: trailing whitespace on empty line.

Line 858 appears to have trailing whitespace after the function signature which should be cleaned up for consistency.

transports/bifrost-http/integrations/bedrock.go (2)

203-268: Provider extraction via ctx.Value relies on PreCallback invariants

BatchRequestConverter and batch list/retrieve/cancel converters use:

provider := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)

This will panic if the context key is ever missing or of the wrong type (e.g., if a new route is wired without the matching PreCallback). Given you already set the provider in the corresponding PreCallbacks, this is fine today but somewhat brittle.

Consider a small defensive pattern to decouple converter safety from routing wiring:

providerVal := ctx.Value(bifrostContextKeyProvider)
provider, ok := providerVal.(schemas.ModelProvider)
if !ok {
    return nil, errors.New("provider not set in context")
}

And similarly for the other batch converters.

Also applies to: 271-281, 302-312, 313-323, 344-354, 355-365, 386-396, 397-407


532-568: Safer provider lookup when rewriting Bedrock job ARN

extractBedrockJobArnFromPath currently assumes the provider context key is always present and correctly typed:

if (*bifrostCtx).Value(bifrostContextKeyProvider).(schemas.ModelProvider) != schemas.Bedrock {
    decodedJobArn = strings.Replace(decodedJobArn, "...", "", 1)
}

Two nitpicks here:

  • The explicit (*bifrostCtx) dereference is unnecessary.
  • The unchecked type assertion will panic if the key isn’t set.

You can simplify and harden this without changing behavior:

- if (*bifrostCtx).Value(bifrostContextKeyProvider).(schemas.ModelProvider) != schemas.Bedrock {
+ if provider, ok := bifrostCtx.Value(bifrostContextKeyProvider).(schemas.ModelProvider); ok && provider != schemas.Bedrock {
     decodedJobArn = strings.Replace(decodedJobArn, "arn:aws:bedrock:us-east-1:444444444444:batch:", "", 1)
}

This keeps the cross-provider rewrite but makes the helper more robust to future routing changes.

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

379-432: Streaming helpers should mark stream-end on scanner errors as well

HandleAnthropicChatCompletionStreaming and HandleAnthropicResponsesStream correctly set BifrostContextKeyStreamEndIndicator when:

  • The provider returns an empty body stream.
  • ToBifrost*Stream returns a BifrostError.
  • The final chunk is emitted.

On the other hand, when scanner.Err() is non-nil you log and call ProcessAndSendError, but don’t mark the stream as ended in the context. If downstream cleanup logic relies on BifrostContextKeyStreamEndIndicator (in addition to channel close), this could leave the flag unset on some failure paths.

Consider also setting the indicator in the scanner error branch, e.g.:

if err := scanner.Err(); err != nil {
    logger.Warn(...)
+   ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true)
    providerUtils.ProcessAndSendError(...)
}

Same pattern for both chat and responses streaming helpers.

Also applies to: 436-452, 502-509, 619-627, 681-684

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

822-1075: Responses/ResponsesStream: new fallback flag is reasonable but context-dependent

For non-Anthropic and non-Gemini deployments, Responses continues to fall back to ChatCompletion, and ResponsesStream now:

ctx.SetValue(schemas.BifrostContextKeyIsResponsesToChatCompletionFallback, true)
return provider.ChatCompletionStream(ctx, postHookRunner, key, request.ToChatRequest())

This is a sensible way to tag the stream as a responses→chat fallback in the new context model so downstream hooks can distinguish it. Just ensure any consumers of BifrostContextKeyIsResponsesToChatCompletionFallback expect it only on streaming fallbacks (the synchronous Responses fallback does not currently set it).

Also applies to: 1077-1263

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

341-413: Mark stream-end on scanner errors for Cohere streaming as well

For both ChatCompletionStream and ResponsesStream, you now set BifrostContextKeyStreamEndIndicator on:

  • Per-event conversion errors (ToBifrost*Stream returning an error).
  • The final chunk when isLastChunk is true.

However, if the SSE scanner itself errors (scanner.Err()), you log and call ProcessAndSendError but do not set the stream-end indicator. To keep semantics consistent with the new context flag (and with other providers), consider setting it there too:

if err := scanner.Err(); err != nil {
    provider.logger.Warn(...)
+   ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true)
    providerUtils.ProcessAndSendError(...)
}

This mirrors the Anthropic recommendation and makes it easier for higher layers to reliably detect all terminal stream states via the context.

Also applies to: 432-507, 572-647, 656-762

Comment thread core/internal/testutil/speech_synthesis_stream.go
Comment thread core/internal/testutil/speech_synthesis_stream.go
Comment thread core/internal/testutil/speech_synthesis_stream.go
Comment thread core/schemas/context.go Outdated
Comment thread examples/plugins/hello-world-wasm-typescript/assembly/index.ts Outdated
Comment thread examples/plugins/hello-world-wasm-typescript/assembly/index.ts Outdated
Comment thread examples/plugins/hello-world-wasm-typescript/assembly/index.ts Outdated
Comment thread examples/plugins/hello-world-wasm-typescript/assembly/index.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

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

70-71: Outdated documentation: return type description.

The doc comment on line 70 states the function returns *context.Context, but the actual return type is now *schemas.BifrostContext. Update the documentation to reflect the new return type.

 // Returns:
-//   - *context.Context: A new cancellable context.Context containing the propagated values
+//   - *schemas.BifrostContext: A new cancellable BifrostContext containing the propagated values
 //   - context.CancelFunc: Function to cancel the context (should be called when request completes)
core/internal/testutil/speech_synthesis.go (3)

113-117: Thread the passed context instead of creating a new one.

The function receives a ctx *schemas.BifrostContext parameter but ignores it, creating a fresh context instead. For consistency with other test utilities and to fix the compile error, thread the passed context through.

-			requestCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
-
-			speechResponse, bifrostErr := WithSpeechTestRetry(t, speechRetryConfig, retryContext, expectations, "SpeechSynthesis_"+tc.name, func() (*schemas.BifrostSpeechResponse, *schemas.BifrostError) {
-				return client.SpeechRequest(requestCtx, request)
+			speechResponse, bifrostErr := WithSpeechTestRetry(t, speechRetryConfig, retryContext, expectations, "SpeechSynthesis_"+tc.name, func() (*schemas.BifrostSpeechResponse, *schemas.BifrostError) {
+				return client.SpeechRequest(ctx, request)

219-223: Thread the passed context instead of creating a new one.

Same issue: use the passed ctx parameter instead of creating a fresh context.

-		requestCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
-
-		speechResponse, bifrostErr := WithSpeechTestRetry(t, speechRetryConfig, retryContext, expectations, "SpeechSynthesis_HD", func() (*schemas.BifrostSpeechResponse, *schemas.BifrostError) {
-			return client.SpeechRequest(requestCtx, request)
+		speechResponse, bifrostErr := WithSpeechTestRetry(t, speechRetryConfig, retryContext, expectations, "SpeechSynthesis_HD", func() (*schemas.BifrostSpeechResponse, *schemas.BifrostError) {
+			return client.SpeechRequest(ctx, request)

301-305: Thread the passed context instead of creating a new one.

Same issue in the "AllVoiceOptions" subtest: use the passed ctx parameter.

-				requestCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
-
-				speechResponse, bifrostErr := WithSpeechTestRetry(t, voiceSpeechRetryConfig, voiceRetryContext, expectations, "SpeechSynthesis_VoiceType_"+voiceType, func() (*schemas.BifrostSpeechResponse, *schemas.BifrostError) {
-					return client.SpeechRequest(requestCtx, request)
+				speechResponse, bifrostErr := WithSpeechTestRetry(t, voiceSpeechRetryConfig, voiceRetryContext, expectations, "SpeechSynthesis_VoiceType_"+voiceType, func() (*schemas.BifrostSpeechResponse, *schemas.BifrostError) {
+					return client.SpeechRequest(ctx, request)
transports/bifrost-http/integrations/anthropic.go (6)

434-448: Missing nil check on type assertion for provider.

At line 436, ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider) performs a type assertion without checking if the value exists or if the assertion succeeds. If the provider is not set in the context, this will panic.

🐛 Proposed fix with nil check
 BatchRequestConverter: func(ctx *schemas.BifrostContext, req interface{}) (*BatchRequest, error) {
 	if retrieveReq, ok := req.(*anthropic.AnthropicBatchRetrieveRequest); ok {
-		provider := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		provider, ok := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		if !ok {
+			return nil, errors.New("provider not found in context")
+		}
 		if provider == schemas.Gemini {

470-484: Missing nil check on type assertion for provider in batch cancel.

Same issue as batch retrieve - line 472 performs an unchecked type assertion that could panic.

🐛 Proposed fix
 BatchRequestConverter: func(ctx *schemas.BifrostContext, req interface{}) (*BatchRequest, error) {
 	if cancelReq, ok := req.(*anthropic.AnthropicBatchCancelRequest); ok {
-		provider := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		provider, ok := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		if !ok {
+			return nil, errors.New("provider not found in context")
+		}
 		if provider == schemas.Gemini {

506-520: Missing nil check on type assertion for provider in batch results.

Line 508 has the same unchecked type assertion pattern.

🐛 Proposed fix
 BatchRequestConverter: func(ctx *schemas.BifrostContext, req interface{}) (*BatchRequest, error) {
 	if resultsReq, ok := req.(*anthropic.AnthropicBatchResultsRequest); ok {
-		provider := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		provider, ok := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		if !ok {
+			return nil, errors.New("provider not found in context")
+		}
 		if provider == schemas.Gemini {

775-789: Missing nil check on type assertion for provider in file list.

Line 777 has the same unchecked type assertion pattern that could panic.

🐛 Proposed fix
 FileRequestConverter: func(ctx *schemas.BifrostContext, req interface{}) (*FileRequest, error) {
 	if listReq, ok := req.(*anthropic.AnthropicFileListRequest); ok {
-		provider := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		provider, ok := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		if !ok {
+			return nil, errors.New("provider not found in context")
+		}
 		return &FileRequest{

816-831: Missing nil check on type assertion for provider in file retrieve.

Line 818 has the same unchecked type assertion pattern.

🐛 Proposed fix
 FileRequestConverter: func(ctx *schemas.BifrostContext, req interface{}) (*FileRequest, error) {
 	if retrieveReq, ok := req.(*anthropic.AnthropicFileRetrieveRequest); ok {
-		provider := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		provider, ok := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		if !ok {
+			return nil, errors.New("provider not found in context")
+		}
 		// Handle file id conversion for Gemini

853-868: Missing nil check on type assertion for provider in file delete.

Line 855 has the same unchecked type assertion pattern.

🐛 Proposed fix
 FileRequestConverter: func(ctx *schemas.BifrostContext, req interface{}) (*FileRequest, error) {
 	if deleteReq, ok := req.(*anthropic.AnthropicFileDeleteRequest); ok {
-		provider := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		provider, ok := ctx.Value(bifrostContextKeyProvider).(schemas.ModelProvider)
+		if !ok {
+			return nil, errors.New("provider not found in context")
+		}
 		if provider == schemas.Gemini {
core/providers/openai/openai.go (1)

1122-1133: Fix inconsistent context type in HandleOpenAIResponsesRequest.

Line 1123 still uses context.Context instead of *schemas.BifrostContext, which is inconsistent with all other handler functions in this file and will cause a compilation error when called from line 1107.

🔧 Proposed fix
 func HandleOpenAIResponsesRequest(
-	ctx context.Context,
+	ctx *schemas.BifrostContext,
 	client *fasthttp.Client,
 	url string,
 	request *schemas.BifrostResponsesRequest,
🤖 Fix all issues with AI agents
In @core/internal/testutil/speech_synthesis_stream.go:
- Line 17: RunSpeechSynthesisStreamTest and RunSpeechSynthesisStreamAdvancedTest
are creating new request contexts from context.Background() instead of
propagating the provided ctx, so cancellation, deadlines, and values are lost;
update each place that currently uses context.Background() (the streaming
request context construction inside RunSpeechSynthesisStreamTest and
RunSpeechSynthesisStreamAdvancedTest) to derive from the passed-in ctx by
calling schemas.NewBifrostContext(ctx.Context(), schemas.NoDeadline) (or another
appropriate deadline option) so the parent context is propagated to streaming
requests.

In @core/schemas/mcp.go:
- Line 24: Test implementations that assign to FetchNewRequestIDFunc still use
context.Context; change their function signatures to accept
*schemas.BifrostContext to match the type declared as FetchNewRequestIDFunc in
core/schemas/mcp.go. Locate the functions assigned to FetchNewRequestIDFunc in
the tests (the anonymous or named functions creating request IDs) and update the
parameter type to *schemas.BifrostContext, update any call sites that construct
or pass a context to pass a *schemas.BifrostContext instead, and add or adjust
imports to reference the schemas package where BifrostContext is defined.

In @core/schemas/plugin_wasm.go:
- Around line 1-10: The comment for PluginShortCircuit is inaccurate: it
mentions a Stream/streaming short-circuit even though the wasm/tinygo build of
the struct only contains Response (*BifrostResponse) and Error (*BifrostError);
update the documentation on the PluginShortCircuit type to remove any reference
to Stream/streaming short-circuits and clearly state the struct only supports
Response and Error in this build (mentioning PluginShortCircuit,
BifrostResponse, and BifrostError so the maintainer can find and edit the
correct comment).

In @docs/docs.json:
- Around line 180-187: Add a redirect object to the docs.json "redirects" array
mapping the removed path "plugins/writing-plugin" to the new page (e.g.,
"plugins/writing-go-plugin"); locate the "redirects" array and append an entry
with the old path as the source and the chosen new page as the destination so
requests to "plugins/writing-plugin" are forwarded to the new documentation.

In @docs/plugins/writing-wasm-plugin.mdx:
- Around line 26-35: The docs table lists free as `free (ptr: u32)` but the Rust
plugin implementation exposes `free(ptr: u32, size: u32)`; update the table
entry for `free` to show `(ptr: u32, size: u32)` (or add a short parenthetical
note that some language allocators require size) so the doc matches the Rust
`free` implementation and avoids confusion for plugin authors.

In @transports/bifrost-http/integrations/router.go:
- Around line 191-195: The comment for ResponsesStreamResponseConverter is
outdated and claims the function returns "the list of event types and the list
of streaming formats", but the type signature actually returns a single string
and an interface{} plus error; update the doc comment for
ResponsesStreamResponseConverter to describe the current return values (that it
returns a single event type string and a single streaming-format payload as
interface{}, along with an error) and clarify the ordering/semantics expected
for integration authors so the comment matches the signature.

In @ui/app/clientLayout.tsx:
- Around line 19-23: The comment above the DevProfiler dynamic import is
misleading about bundle exclusion; update it to explain that dynamic(() =>
import(...)) creates a separate code-split chunk and that the DevProfiler is
only excluded from production because the component is never rendered when the
NODE_ENV/dev render guard is false (and will be removed by tree-shaking), not
because dynamic() alone prevents inclusion; reference the DevProfiler symbol and
the render guard that checks NODE_ENV/dev and mention that the dynamic import is
used with ssr: false to avoid server rendering.
🧹 Nitpick comments (25)
docs/plugins/writing-wasm-plugin.mdx (1)

296-304: Go example: Exported function name mismatch.

The init function is documented as an export, but the Go implementation uses init_plugin (line 297) with the //export init directive. This is intentional because init is a reserved function name in Go. The code correctly handles this, but a brief inline comment explaining this Go-specific workaround would help developers understand why the function is named differently.

examples/plugins/hello-world-wasm-typescript/assembly/index.ts (2)

73-87: Fragile boolean extraction logic.

The extractJsonBool function checks if "true" appears within 10 characters after the key pattern. This approach has edge cases:

  1. A string value like "has_error": "true_story" would incorrectly return true
  2. Different whitespace/formatting could push true beyond 10 chars: "has_error" : true

For a hello-world example this is acceptable, but consider adding a comment noting these limitations for developers who might copy this pattern.


92-103: Edge case in addToJsonObject when object has whitespace before closing brace.

If the input JSON has trailing whitespace like {"key": "value" }, the function checks json.endsWith('}') which would be false. The function returns the original json unmodified (line 102), silently failing to add the new key-value pair.

For a hello-world example, this is minor, but worth noting for robustness.

plugins/governance/main.go (1)

501-505: Optional: Remove unnecessary nil check for context parameter.

The nil check on line 501 appears redundant since the function signature guarantees ctx is *schemas.BifrostContext and other parts of the function (lines 469-470, 498) use ctx without nil checks. Consider removing the defensive nil check for consistency.

♻️ Proposed simplification
-	if result.Decision != DecisionAllow {
-		if ctx != nil {
-			if _, ok := ctx.Value(governanceRejectedContextKey).(bool); !ok {
-				ctx.SetValue(governanceRejectedContextKey, true)
-			}
-		}
-	}
+	if result.Decision != DecisionAllow {
+		if _, ok := ctx.Value(governanceRejectedContextKey).(bool); !ok {
+			ctx.SetValue(governanceRejectedContextKey, true)
+		}
+	}
examples/plugins/hello-world-wasm-rust/src/lib.rs (1)

219-231: Consider avoiding unnecessary Some() wrapping for error field.

The post-hook wraps input.error.clone() in Some(), which means even when has_error is false, you're still cloning and passing an error value. This works but could be more explicit about intent.

Optional: More explicit error handling
     let output = PostHookOutput {
         context,
         response: Some(input.response.clone()),
-        error: Some(input.error.clone()),
+        error: if input.has_error { Some(input.error.clone()) } else { None },
         has_error: input.has_error,
         hook_error: String::new(),
     };
core/providers/bedrock/bedrock_test.go (5)

680-681: Minor formatting: add space after comma.

-		ctx := schemas.NewBifrostContext(context.Background(),schemas.NoDeadline)
+		ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)

708-708: Minor formatting: add space after comma.

-	ctx := schemas.NewBifrostContext(context.Background(),schemas.NoDeadline)
+	ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)

1778-1778: Minor formatting: add space after comma.

-	ctx := schemas.NewBifrostContext(context.Background(),schemas.NoDeadline)
+	ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)

1989-1991: Minor formatting: add space after comma.

-	ctx := schemas.NewBifrostContext(context.Background(),schemas.NoDeadline)
+	ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)

2016-2018: Minor formatting: add space after comma.

-	ctx := schemas.NewBifrostContext(context.Background(),schemas.NoDeadline)
+	ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
transports/bifrost-http/integrations/openai.go (1)

38-97: Azure direct‑key handling may no longer reach BifrostContext

AzureEndpointPreHook and the composite pre‑hooks still only stash the constructed schemas.Key in fasthttp.RequestCtx via ctx.SetUserValue(string(schemas.BifrostContextKeyDirectKey), key), while core key‑selection now reads direct keys from *schemas.BifrostContext using ctx.Value(schemas.BifrostContextKeyDirectKey).

Unless some middleware is copying this user value into the BifrostContext for each request, Azure “direct key” flows may silently stop working after this migration. A straightforward hardening would be to also write the same key into bifrostCtx:

Example adjustment inside AzureEndpointPreHook
-			ctx.SetUserValue(string(schemas.BifrostContextKeyDirectKey), key)
+			ctx.SetUserValue(string(schemas.BifrostContextKeyDirectKey), key)
+			if bifrostCtx != nil {
+				bifrostCtx.SetValue(schemas.BifrostContextKeyDirectKey, key)
+			}

Please double‑check how BifrostContextKeyDirectKey is populated for OpenAI/Azure requests across the stack and whether BifrostContext now needs to be the single source of truth.

Also applies to: 456-479, 976-1013, 1016-1058, 1060-1137, 1139-1221

transports/bifrost-http/integrations/bedrock.go (1)

41-106: Bedrock integrations: BifrostContext usage is coherent

The Bedrock converse/invoke, batch, and S3‑compatible file routes now consistently:

  • Take *schemas.BifrostContext in converters and pre‑callbacks.
  • Store provider selection and direct keys via bifrostCtx.SetValue(...).
  • Use per‑request S3 context keys (bucket/prefix/maxKeys) on the same BifrostContext instance for response shaping.

This keeps the previous behavior while aligning with the new context model. The one (*bifrostCtx).Value(...) in extractBedrockJobArnFromPath can be simplified to bifrostCtx.Value(...), but that’s purely stylistic.

Also applies to: 195-333, 381-418, 422-476, 530-568, 587-829

core/bifrost.go (1)

385-518: Consider normalizing nil BifrostContext consistently for ListAllModels and MCP tool APIs

Most public APIs either normalize a nil *schemas.BifrostContext to bifrost.ctx directly or rely on handleRequest/handleStreamRequest doing so. Two areas still assume a non‑nil context:

  • ListAllModels(ctx *schemas.BifrostContext, ...) (uses ctx.Done() in goroutines).
  • ExecuteChatMCPTool and ExecuteResponsesMCPTool (pass ctx straight into MCP manager).

For symmetry – and to make accidental nil contexts less foot‑gunny for callers migrating from the old context.Context signatures – you could add a defensive default similar to the batch/file APIs:

Illustrative change for ListAllModels and MCP tool executors
func (bifrost *Bifrost) ListAllModels(ctx *schemas.BifrostContext, request *schemas.BifrostListModelsRequest) (*schemas.BifrostListModelsResponse, *schemas.BifrostError) {
+   if ctx == nil {
+       ctx = bifrost.ctx
+   }
    ...
}

func (bifrost *Bifrost) ExecuteChatMCPTool(ctx *schemas.BifrostContext, toolCall schemas.ChatAssistantMessageToolCall) (*schemas.ChatMessage, *schemas.BifrostError) {
+   if ctx == nil {
+       ctx = bifrost.ctx
+   }
    ...
}

func (bifrost *Bifrost) ExecuteResponsesMCPTool(ctx *schemas.BifrostContext, toolCall *schemas.ResponsesToolMessage) (*schemas.ResponsesMessage, *schemas.BifrostError) {
+   if ctx == nil {
+       ctx = bifrost.ctx
+   }
    ...
}

Not mandatory, but would make the new API surface more uniform and a bit more defensive.

Also applies to: 1788-1860

core/providers/anthropic/anthropic.go (2)

436-510: Streaming chat: end‑of‑stream signaling via context is wired correctly.

HandleAnthropicChatCompletionStreaming now sets BifrostContextKeyStreamEndIndicator on empty‑body failures, chunk‑level errors, and the final summary chunk before calling ProcessAndSend{BifrostError,Response}, which allows completeDeferredSpan to close tracing spans exactly once per stream. Scanner error still goes through ProcessAndSendError without marking the stream as final; if you want spans to close on transport errors as well, consider setting the end‑indicator before calling ProcessAndSendError.

Also applies to: 619-683


791-865: Streaming responses: context flagging for final chunks mirrors chat behavior.

For SSE responses, you set StreamEndIndicator on provider‑side empty responses and on the last logical chunk before delegating to ProcessAndSendBifrostError / ProcessAndSendResponse, which keeps span finalization semantics aligned with chat streaming. As with chat, scanner errors bypass this flag and only emit via ProcessAndSendError; optionally aligning that path would improve tracing completeness.

Also applies to: 965-1013

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

163-187: Responses→chat fallback flag is a nice addition; consider mirroring for non‑streaming.

Setting BifrostContextKeyIsResponsesToChatCompletionFallback in ResponsesStream before delegating to ChatCompletionStream gives downstream hooks a clear signal that this is a responses‑via‑chat fallback. If you want identical observability for non‑streaming flows, you might also set this flag in Responses before calling ChatCompletion.

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

341-412: Chat streaming now integrates cleanly with Bifrost tracing.

ChatCompletionStream uses ctx *schemas.BifrostContext and sets StreamEndIndicator both when a stream error is converted to a BifrostError and on the final chunk before calling ProcessAndSend{BifrostError,Response}, which lets completeDeferredSpan close spans and propagate TTFT/chunk metrics. Scanner errors still route through ProcessAndSendError without marking final; aligning that path is a possible future improvement if you need spans to close on transport failure too.

Also applies to: 423-512

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

172-223: Minor nit: defers inside the pagination loop could be tightened.

In listModelsByKey, fasthttp.AcquireRequest/AcquireResponse are paired with defer‑based releases inside the pagination loop, so requests/responses are only returned to the pool when the function exits. Not a correctness issue, but releasing them at the end of each iteration instead of via defer would reduce peak resource usage during multi‑page listings.

core/providers/gemini/gemini.go (5)

271-520: Streaming chat completion: consider marking end-of-stream on scanner errors as well

The ChatCompletionStream/HandleGeminiChatCompletionStream path now:

  • Uses *schemas.BifrostContext throughout.
  • Sets BifrostContextKeyStreamEndIndicator on Gemini API errors, conversion errors, and the final completion chunk.
  • Properly sends errors and responses via the shared helpers.

One robustness gap: in the scanner.Err() branch, you log and forward the error via ProcessAndSendError but don’t set BifrostContextKeyStreamEndIndicator. If downstream consumers rely on that flag to know the stream has terminated (regardless of reason), it may be worth setting it there too for consistency.

Proposed tweak for the scanner error path
@@
-        if err := scanner.Err(); err != nil {
-            logger.Warn(fmt.Sprintf("Error reading stream: %v", err))
-            providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ChatCompletionStreamRequest, providerName, model, logger)
-        }
+        if err := scanner.Err(); err != nil {
+            logger.Warn(fmt.Sprintf("Error reading stream: %v", err))
+            ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true)
+            providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ChatCompletionStreamRequest, providerName, model, logger)
+        }

525-873: Responses and ResponsesStream: consistent BifrostContext and similar stream-end concern

Non-streaming Responses and streaming ResponsesStream correctly:

  • Use CheckContextAndGetRequestBody(ctx, ...) with the new context type.
  • Invoke completeRequest/HandleGeminiResponsesStream with ctx.
  • Populate ExtraFields and raw payloads via the context-aware helpers.

HandleGeminiResponsesStream mirrors chat streaming in how it sets BifrostContextKeyStreamEndIndicator for Gemini API errors, conversion errors, per-chunk completion, and finalization, but again omits it in the scanner.Err() branch. For symmetry with other termination paths, consider also setting the flag there, analogous to the chat-stream suggestion.

Proposed tweak for responses stream scanner error path
@@
-        if err := scanner.Err(); err != nil {
-            logger.Warn(fmt.Sprintf("Error reading stream: %v", err))
-            providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ResponsesStreamRequest, providerName, model, logger)
-        } else {
+        if err := scanner.Err(); err != nil {
+            logger.Warn(fmt.Sprintf("Error reading stream: %v", err))
+            ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true)
+            providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ResponsesStreamRequest, providerName, model, logger)
+        } else {

969-1015: Speech response format key: consider guarding against nil Params

Setting BifrostContextKeyResponseFormat from request.Params.ResponseFormat assumes request.Params is always non-nil. If upstream validation guarantees this, it’s fine; otherwise, this can panic on malformed input.

Given this is a hot path, a small defensive check would make it more robust without changing semantics when Params is present.

Defensive guard around `request.Params`
-    ctx.SetValue(BifrostContextKeyResponseFormat, request.Params.ResponseFormat)
+    if request.Params != nil {
+        ctx.SetValue(BifrostContextKeyResponseFormat, request.Params.ResponseFormat)
+    }

If Params is required by your API contract, please ignore this suggestion but consider adding an explicit validation earlier in the flow.


1017-1239: Speech streaming: good BifrostContext usage; mirror stream-end flag on IO errors

SpeechStream correctly:

  • Uses *schemas.BifrostContext for request-body building and extra headers.
  • Detects Gemini API errors and sets BifrostContextKeyStreamEndIndicator before sending a BifrostError.
  • Marks stream completion via the same key in the final “done” chunk.

As with other streaming helpers, the scanner.Err() branch currently only logs and calls ProcessAndSendError. For consistent stream termination signaling, you may want to set BifrostContextKeyStreamEndIndicator there as well.

Optional stream-end flag on speech scanner error
-        if err := scanner.Err(); err != nil {
-            provider.logger.Warn(fmt.Sprintf("Error reading stream: %v", err))
-            providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.SpeechStreamRequest, providerName, request.Model, provider.logger)
-        } else {
+        if err := scanner.Err(); err != nil {
+            provider.logger.Warn(fmt.Sprintf("Error reading stream: %v", err))
+            ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true)
+            providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.SpeechStreamRequest, providerName, request.Model, provider.logger)
+        } else {

1242-1523: Transcription and TranscriptionStream: consistent context migration; same stream-end detail

The non-streaming Transcription path and streaming TranscriptionStream both:

  • Use *schemas.BifrostContext end-to-end.
  • Set BifrostContextKeyStreamEndIndicator on Gemini API errors and on the final “done” event.

For the scanner.Err() case in TranscriptionStream, consider also setting BifrostContextKeyStreamEndIndicator before forwarding the error, mirroring the other termination paths.

Optional stream-end flag on transcription scanner error
-        if err := scanner.Err(); err != nil {
-            provider.logger.Warn(fmt.Sprintf("Error reading stream: %v", err))
-            providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.TranscriptionStreamRequest, providerName, request.Model, provider.logger)
-        } else {
+        if err := scanner.Err(); err != nil {
+            provider.logger.Warn(fmt.Sprintf("Error reading stream: %v", err))
+            ctx.SetValue(schemas.BifrostContextKeyStreamEndIndicator, true)
+            providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.TranscriptionStreamRequest, providerName, request.Model, provider.logger)
+        } else {
core/schemas/context.go (1)

73-79: Optional: clarify silent dropping of reserved-key writes

NewBifrostContextWithValue plus SetValue’s guard mean reserved keys set after BlockRestrictedWrites is enabled are silently ignored:

if bc.blockRestrictedWrites.Load() && slices.Contains(reservedKeys, key) {
    // we silently drop writes for these reserved keys
    return
}

Given that this is observable only via missing values, consider briefly documenting this behavior on SetValue (or BlockRestrictedWrites) so callers know failures won’t surface as errors or logs.

Also applies to: 218-224

core/providers/bedrock/responses.go (1)

1206-1224: Bedrock converters now properly use BifrostContext and support structured-output tools

  • ToBifrostResponsesRequest, ToBedrockResponsesRequest, and ToBifrostResponsesResponse now accept *schemas.BifrostContext and thread it through to message converters, giving Bedrock conversions access to per-request context.
  • ConvertBedrockMessagesToBifrostMessages and convertSingleBedrockMessageToBifrostMessages use ctx.Value(schemas.BifrostContextKeyStructuredOutputToolName) to detect a configured structured-output tool and, when a ToolUse block’s name matches, convert its Input payload directly into an assistant text message rather than a function_call message.
  • For all other tool uses the prior behavior is preserved (emit ResponsesMessageTypeFunctionCall / FunctionCallOutput messages), and ctx is handled safely when nil.

This is a clean extension of the Bedrock mapping that respects the new BifrostContext without regressing existing tool/streaming behaviors. Just ensure upstream code consistently sets BifrostContextKeyStructuredOutputToolName only for calls that should be treated as structured output.

Also applies to: 1436-1456, 1698-1713, 2485-2502, 2631-2643, 2644-2713

Comment thread core/internal/testutil/speech_synthesis_stream.go
Comment thread core/schemas/mcp.go
Comment thread core/schemas/plugin_wasm.go
Comment thread docs/docs.json
Comment thread docs/plugins/writing-wasm-plugin.mdx
Comment thread transports/bifrost-http/integrations/router.go
Comment thread ui/app/clientLayout.tsx
@akshaydeo akshaydeo force-pushed the 01-07-move_to_schemas.bifrostcontext branch from 5d1fcf4 to e894005 Compare January 7, 2026 12:54
@akshaydeo akshaydeo force-pushed the 01-05-plugin_loaders branch from afd603c to fbfd140 Compare January 7, 2026 12:54
@akshaydeo akshaydeo force-pushed the 01-07-move_to_schemas.bifrostcontext branch from e894005 to e6f4a43 Compare January 7, 2026 12:59
@akshaydeo akshaydeo force-pushed the 01-05-plugin_loaders branch from fbfd140 to 016cde0 Compare January 7, 2026 13:09
@akshaydeo akshaydeo force-pushed the 01-07-move_to_schemas.bifrostcontext branch 2 times, most recently from 3e6657a to 3450664 Compare January 7, 2026 13:10
@akshaydeo akshaydeo force-pushed the 01-05-plugin_loaders branch from 016cde0 to 511a030 Compare January 7, 2026 13:36
@akshaydeo akshaydeo force-pushed the 01-07-move_to_schemas.bifrostcontext branch from 3450664 to 36f0cca Compare January 7, 2026 13:36
@akshaydeo akshaydeo force-pushed the 01-07-move_to_schemas.bifrostcontext branch from 36f0cca to 6010e56 Compare January 7, 2026 14:03
@akshaydeo akshaydeo force-pushed the 01-05-plugin_loaders branch from 511a030 to 6272071 Compare January 7, 2026 14:03
Copy link
Copy Markdown
Contributor Author

akshaydeo commented Jan 7, 2026

Merge activity

  • Jan 7, 2:04 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jan 7, 2:06 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo akshaydeo changed the base branch from 01-05-plugin_loaders to graphite-base/1262 January 7, 2026 14:04
@akshaydeo akshaydeo changed the base branch from graphite-base/1262 to v1.4.0 January 7, 2026 14:05
@akshaydeo akshaydeo merged commit f9d671b into v1.4.0 Jan 7, 2026
4 of 5 checks passed
@akshaydeo akshaydeo deleted the 01-07-move_to_schemas.bifrostcontext branch January 7, 2026 14:06
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.

1 participant