Skip to content

feat: add context propagation to provider requests#52

Merged
akshaydeo merged 1 commit intomainfrom
06-03-feat_ctx_cancel_support_added
Jun 3, 2025
Merged

feat: add context propagation to provider requests#52
akshaydeo merged 1 commit intomainfrom
06-03-feat_ctx_cancel_support_added

Conversation

@Pratham-Mishra04
Copy link
Copy Markdown
Collaborator

Add context propagation and request cancellation support

This PR adds support for context propagation and request cancellation throughout the Bifrost system. It allows clients to cancel in-flight requests when their context is cancelled or times out, improving resource management and responsiveness.

Key changes:

  • Added context propagation from client requests to provider API calls
  • Implemented request cancellation handling in all providers
  • Added a new RequestCancelled error type to identify cancelled requests
  • Modified the ChannelMessage struct to include the request context
  • Improved the Cleanup method to gracefully shut down without signal handling
  • Added proper context handling in test utilities to ensure clean test termination
  • Refactored provider interfaces to accept context in method signatures

The implementation ensures that when a client cancels a request context, Bifrost will stop processing that request and return an appropriate cancellation error. This is particularly important for long-running requests or when clients need to implement timeouts.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2025

Walkthrough

This update introduces context propagation across the request lifecycle, allowing for improved cancellation and timeout handling in provider operations. Provider interfaces and implementations are refactored to accept context.Context parameters. Shutdown logic is simplified, and error handling for request cancellations is enhanced. Test concurrency and cleanup are now managed using wait groups and context cancellation.

Changes

Files/Groups Change Summary
core/bifrost.go, core/schemas/provider.go, ... Added context propagation to request lifecycle; refactored provider interfaces and methods for context support.
core/providers/anthropic.go, azure.go, bedrock.go, ... Updated all provider methods to accept and propagate context.Context; HTTP calls now context-aware.
core/providers/utils.go Added makeRequestWithContext for context-aware HTTP requests.
core/schemas/bifrost.go Added ToolCallID to Message struct; introduced RequestCancelled constant.
core/tests/tests.go Introduced wait groups and context cancellation for test concurrency and graceful shutdown.
core/tests/anthropic_test.go, azure_test.go, ... Removed redundant Cleanup() calls from individual tests.
core/tests/openai_test.go Updated fallback Anthropic model version; removed Cleanup() call.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Bifrost
    participant Provider
    participant HTTPAPI

    Client->>Bifrost: Send request (with context)
    Bifrost->>Provider: Call TextCompletion/ChatCompletion(ctx, ...)
    Provider->>HTTPAPI: Make HTTP request with context
    HTTPAPI-->>Provider: Response or error (respects context cancellation)
    Provider-->>Bifrost: Return result or cancellation error
    Bifrost-->>Client: Return response or error
Loading
sequenceDiagram
    participant TestRunner
    participant SetupAllRequests
    participant Goroutine
    participant WaitGroup

    TestRunner->>SetupAllRequests: Start test setup
    SetupAllRequests->>WaitGroup: Add(1) per goroutine
    SetupAllRequests->>Goroutine: Launch test goroutine (with context)
    Goroutine-->>WaitGroup: Done() on completion
    SetupAllRequests->>TestRunner: Wait for all or context cancel
    Note over SetupAllRequests,TestRunner: On interrupt, context is cancelled and waits for goroutines to finish
Loading

Poem

In the warren of code, context now flows,
Cancelling requests when the signal bell goes.
Providers all listen, with context in hand,
Awaiting a timeout, or a bunny's command.
Tests hop in sync, wait groups in tow—
Cleanup is simple, and off we all go!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Collaborator Author

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

@Pratham-Mishra04 Pratham-Mishra04 marked this pull request as ready for review June 3, 2025 07:44
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

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

206-215: 🛠️ Refactor suggestion

Pool object retains previous Context – potential memory leak

releaseChannelMessage clears Response and Err but leaves Context populated.
The next borrower may unexpectedly inherit an unrelated context and, worse, the old context (with all its values) is kept alive in the pool.

Clear it before returning to the pool.

 func (bifrost *Bifrost) releaseChannelMessage(msg *ChannelMessage) {
     // Put channels back in pools
     bifrost.responseChannelPool.Put(msg.Response)
     bifrost.errorChannelPool.Put(msg.Err)

     // Clear references and return to pool
     msg.Response = nil
     msg.Err = nil
+    msg.Context = nil
     bifrost.channelMessagePool.Put(msg)
 }
🧹 Nitpick comments (2)
core/providers/azure.go (1)

170-178: Typo in error message reduces clarity

"deployment if not found for model %s" should read "deployment not found for model %s".
Tiny issue, but logs/searches are easier when messages are consistent and grammatically correct.

-					Message: fmt.Sprintf("deployment if not found for model %s", model),
+					Message: fmt.Sprintf("deployment not found for model %s", model),
core/providers/bedrock.go (1)

208-220: json.Marshal will never return context.Canceled / DeadlineExceeded

json.Marshal is CPU-bound and has no access to the passed ctx; the extra errors.Is checks therefore cannot be hit and add noise.

Consider removing this block or moving cancel/timeout handling to the network call where it is relevant.

-	if err != nil {
-		if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
-			...
-		}
-		...
-	}
+	if err != nil {
+		return nil, &schemas.BifrostError{
+			IsBifrostError: true,
+			Error: schemas.ErrorField{
+				Message: schemas.ErrProviderJSONMarshaling,
+				Error:   err,
+			},
+		}
+	}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 083b61e and 6c65217.

📒 Files selected for processing (17)
  • core/bifrost.go (13 hunks)
  • core/providers/anthropic.go (7 hunks)
  • core/providers/azure.go (7 hunks)
  • core/providers/bedrock.go (7 hunks)
  • core/providers/cohere.go (4 hunks)
  • core/providers/openai.go (5 hunks)
  • core/providers/utils.go (2 hunks)
  • core/providers/vertex.go (5 hunks)
  • core/schemas/bifrost.go (2 hunks)
  • core/schemas/provider.go (2 hunks)
  • core/tests/anthropic_test.go (0 hunks)
  • core/tests/azure_test.go (0 hunks)
  • core/tests/bedrock_test.go (0 hunks)
  • core/tests/cohere_test.go (0 hunks)
  • core/tests/openai_test.go (1 hunks)
  • core/tests/tests.go (11 hunks)
  • core/tests/vertex_test.go (0 hunks)
💤 Files with no reviewable changes (5)
  • core/tests/anthropic_test.go
  • core/tests/azure_test.go
  • core/tests/bedrock_test.go
  • core/tests/vertex_test.go
  • core/tests/cohere_test.go
🧰 Additional context used
🧬 Code Graph Analysis (7)
core/providers/utils.go (2)
core/schemas/bifrost.go (4)
  • BifrostError (299-305)
  • ErrorField (308-315)
  • RequestCancelled (295-295)
  • Message (143-149)
core/schemas/provider.go (1)
  • ErrProviderRequest (20-20)
core/schemas/provider.go (1)
core/schemas/bifrost.go (4)
  • ModelParameters (75-89)
  • BifrostResponse (162-172)
  • BifrostError (299-305)
  • Message (143-149)
core/providers/cohere.go (1)
core/schemas/bifrost.go (4)
  • ModelParameters (75-89)
  • BifrostResponse (162-172)
  • BifrostError (299-305)
  • Message (143-149)
core/providers/vertex.go (2)
core/schemas/bifrost.go (6)
  • ModelParameters (75-89)
  • BifrostResponse (162-172)
  • BifrostError (299-305)
  • Message (143-149)
  • ErrorField (308-315)
  • RequestCancelled (295-295)
core/providers/utils.go (1)
  • StrPtr (277-279)
core/providers/openai.go (1)
core/schemas/bifrost.go (4)
  • ModelParameters (75-89)
  • BifrostResponse (162-172)
  • BifrostError (299-305)
  • Message (143-149)
core/providers/azure.go (1)
core/schemas/bifrost.go (4)
  • BifrostError (299-305)
  • ModelParameters (75-89)
  • BifrostResponse (162-172)
  • Message (143-149)
core/providers/anthropic.go (1)
core/schemas/bifrost.go (4)
  • BifrostError (299-305)
  • ModelParameters (75-89)
  • BifrostResponse (162-172)
  • Message (143-149)
🔇 Additional comments (30)
core/providers/utils.go (2)

6-6: LGTM! Context import added for new functionality.

The addition of the context package import is necessary for the new makeRequestWithContext function.


108-149: Well-implemented context-aware HTTP request handling.

The makeRequestWithContext function provides excellent context cancellation support with clear documentation about its limitations. The implementation correctly:

  1. Uses a goroutine to handle the blocking client.Do call
  2. Implements proper channel-based communication between goroutines
  3. Returns appropriate BifrostError types for different scenarios
  4. Documents that it doesn't truly cancel the underlying fasthttp request

The function follows good practices by using a buffered channel to prevent goroutine leaks and providing clear error messages.

core/tests/openai_test.go (1)

30-30:

Details

✅ Verification successful

Verify the Anthropic model version exists.

The model version "claude-3-7-sonnet-20250219" appears unusual. Anthropic typically uses "claude-3-5-sonnet" series models. Please verify this model exists and is available.


🌐 Web query:

Does Anthropic have a model called "claude-3-7-sonnet-20250219"? What are the latest Claude 3 model versions available?

💡 Result:

Yes, Anthropic has a model named "claude-3-7-sonnet-20250219." This model, released on February 24, 2025, is part of the Claude 3 family and is known for its hybrid reasoning capabilities, allowing users to choose between rapid responses and more detailed, step-by-step reasoning. (docs.anthropic.com)

As of June 2025, the latest versions in the Claude 3 series are:

  • Claude 3.7 Sonnet: Released on February 24, 2025, this model offers enhanced reasoning capabilities and is available on all Claude plans, including Free, Pro, Team, and Enterprise. (reuters.com)

  • Claude 3.5 Sonnet v2: An upgraded version of the previous Sonnet model, offering improved performance and capabilities. (docs.anthropic.com)

  • Claude 3.5 Haiku: The fastest model in the Claude 3 lineup, optimized for quick responses and cost-effectiveness. (docs.anthropic.com)

  • Claude 3 Opus: Designed for complex reasoning tasks, this model excels in deep analysis and understanding. (docs.anthropic.com)

These models are available through Anthropic's API, Amazon Bedrock, and Google Cloud's Vertex AI. (docs.anthropic.com)

Citations:


Verified Anthropic model version

The model claude-3-7-sonnet-20250219 is a valid Claude 3 release (launched Feb 24 2025) and is available on all plans. No further changes are needed.

core/schemas/bifrost.go (2)

146-146: LGTM! ToolCallID field enhances message metadata.

The addition of the optional ToolCallID field to the Message struct properly supports tool call identification with consistent pointer typing for optional fields.


294-296: LGTM! Standardized cancellation error constant.

The RequestCancelled constant provides a consistent way to identify request cancellation errors across the system, which aligns perfectly with the context propagation and cancellation features being introduced.

core/schemas/provider.go (2)

4-7: LGTM! Context import added for interface updates.

The addition of the context package import is necessary for the updated Provider interface method signatures.


146-148:

Details

✅ Verification successful

LGTM! Interface updated for context propagation.

The Provider interface method signatures are correctly updated to include context.Context as the first parameter, following Go conventions. This breaking change is necessary to enable request cancellation and timeout handling throughout the provider system.

Note that this change requires updating all provider implementations to match the new interface.


🏁 Script executed:

#!/bin/bash
# Description: Verify all provider implementations have been updated to match the new interface.

# Search for provider implementations that might need updating
ast-grep --pattern $'func ($$$) TextCompletion($$$) ($$$, $$$) {
  $$$
}'

ast-grep --pattern $'func ($$$) ChatCompletion($$$) ($$$, $$$) {
  $$$
}'

Length of output: 47895


All provider implementations now include context propagation

All TextCompletion and ChatCompletion methods across all providers have been updated to accept ctx context.Context as their first parameter, enabling request cancellation and timeout handling as intended. No further changes are required.

core/providers/cohere.go (4)

6-6: LGTM: Context import added for context propagation support.

The context package import is correctly added to support the new context-aware method signatures.


132-132: LGTM: Method signature updated to accept context parameter.

The TextCompletion method signature is correctly updated to accept context.Context as the first parameter, maintaining consistency with the updated Provider interface.


144-144: LGTM: Method signature updated to accept context parameter.

The ChatCompletion method signature is correctly updated to accept context.Context as the first parameter, enabling context-aware request handling.


226-229: LGTM: HTTP request execution updated to use context-aware helper.

The HTTP request execution is correctly updated to use makeRequestWithContext helper function, which should handle context cancellation and timeouts properly. The error handling is also updated to propagate errors from the helper function.

core/providers/vertex.go (5)

8-8: LGTM: Errors import added for context error checking.

The errors package import is correctly added to support context error detection (context.Canceled, context.DeadlineExceeded).


80-80: LGTM: Method signature updated to accept context parameter.

The TextCompletion method signature is correctly updated to accept context.Context as the first parameter, maintaining consistency with the updated Provider interface.


92-92: LGTM: Method signature updated to accept context parameter.

The ChatCompletion method signature is correctly updated to accept context.Context as the first parameter, enabling context-aware request handling.


156-156: LGTM: HTTP request creation updated to use context.

The HTTP request creation is correctly updated to use http.NewRequestWithContext, which associates the request with the provided context for cancellation and timeout handling.


171-180: LGTM: Enhanced error handling for context cancellation.

The error handling correctly detects context cancellation (context.Canceled) and timeout (context.DeadlineExceeded) scenarios, returning appropriate BifrostError with the RequestCancelled type. The error message includes the context error for debugging purposes.

core/providers/openai.go (5)

6-6: LGTM: Context import added for context propagation support.

The context package import is correctly added to support the new context-aware method signatures.


105-105: LGTM: Method signature updated to accept context parameter.

The TextCompletion method signature is correctly updated to accept context.Context as the first parameter, maintaining consistency with the updated Provider interface.


117-117: LGTM: Method signature updated to accept context parameter.

The ChatCompletion method signature is correctly updated to accept context.Context as the first parameter, enabling context-aware request handling.


149-152: LGTM: HTTP request execution updated to use context-aware helper.

The HTTP request execution is correctly updated to use makeRequestWithContext helper function, which should handle context cancellation and timeouts properly. The error handling is also updated to propagate errors from the helper function.


241-250: LGTM: Message preparation enhanced with tool_call_id support.

The message preparation logic is correctly enhanced to include the tool_call_id field when msg.ToolCallID is present. This aligns with the Message struct in core/schemas/bifrost.go (lines 143-149) that includes the ToolCallID field.

core/providers/anthropic.go (7)

6-6: LGTM: Context import added for context propagation support.

The context package import is correctly added to support the new context-aware method signatures.


172-172: LGTM: Method signature updated to accept context parameter.

The completeRequest method signature is correctly updated to accept context.Context as the first parameter, enabling context-aware HTTP request handling.


199-202: LGTM: HTTP request execution updated to use context-aware helper.

The HTTP request execution is correctly updated to use makeRequestWithContext helper function, which should handle context cancellation and timeouts properly. The error handling is also updated to propagate errors from the helper function.


226-226: LGTM: Method signature updated to accept context parameter.

The TextCompletion method signature is correctly updated to accept context.Context as the first parameter, maintaining consistency with the updated Provider interface.


235-235: LGTM: Context parameter correctly passed to completeRequest.

The context parameter is correctly passed through to the completeRequest method, enabling end-to-end context propagation for request cancellation and timeout handling.


280-280: LGTM: Method signature updated to accept context parameter.

The ChatCompletion method signature is correctly updated to accept context.Context as the first parameter, enabling context-aware request handling.


289-289: LGTM: Context parameter correctly passed to completeRequest.

The context parameter is correctly passed through to the completeRequest method, ensuring consistent context propagation for chat completion requests.

core/providers/azure.go (1)

206-211: Confirm makeRequestWithContext releases resources on cancellation

fasthttp does not natively respect Context; cancelling the context while a request is in-flight will leak the connection unless makeRequestWithContext force-closes it (e.g. by calling req.SetTimeout... or conn.Close()).

Please double-check the helper to ensure:

  1. req/resp are released even when ctx.Done() fires.
  2. the underlying TCP connection is closed to unblock client.Do.
  3. a BifrostError is returned with Type == schemas.RequestCancelled.

If any of these are missing, cancellation will not work as intended.

core/bifrost.go (1)

378-381: RequestCancelled bypass correctly implemented – kudos!

Breaking the retry loop when the provider signals RequestCancelled prevents unnecessary retries and honours client intent.

Comment thread core/tests/tests.go
Comment on lines +356 to +370
allDoneChan := make(chan struct{})
go func() {
wg.Wait()
close(allDoneChan)
}()

select {
case <-ctx.Done():
log.Println("Context cancelled, test setup winding down.")
time.Sleep(1 * time.Second)
case <-allDoneChan:
log.Println("All test goroutines completed.")
}
log.Println("Test setup finished.")
bifrostClient.Cleanup()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Race between cleanup and goroutine completion

When ctx.Done() is selected the code waits one second and proceeds to bifrostClient.Cleanup() without a wg.Wait().
Slow goroutines that have not yet noticed the cancellation may still write to closed request queues, causing panics.

Synchronise both branches:

-	case <-ctx.Done():
-		log.Println("Context cancelled, test setup winding down.")
-		time.Sleep(1 * time.Second)
-	case <-allDoneChan:
-		log.Println("All test goroutines completed.")
+	case <-ctx.Done():
+		log.Println("Context cancelled, waiting for goroutines to exit…")
+		wg.Wait()
+	case <-allDoneChan:
+		log.Println("All test goroutines completed.")
📝 Committable suggestion

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

Suggested change
allDoneChan := make(chan struct{})
go func() {
wg.Wait()
close(allDoneChan)
}()
select {
case <-ctx.Done():
log.Println("Context cancelled, test setup winding down.")
time.Sleep(1 * time.Second)
case <-allDoneChan:
log.Println("All test goroutines completed.")
}
log.Println("Test setup finished.")
bifrostClient.Cleanup()
allDoneChan := make(chan struct{})
go func() {
wg.Wait()
close(allDoneChan)
}()
select {
case <-ctx.Done():
log.Println("Context cancelled, waiting for goroutines to exit…")
wg.Wait()
case <-allDoneChan:
log.Println("All test goroutines completed.")
}
log.Println("Test setup finished.")
bifrostClient.Cleanup()
🤖 Prompt for AI Agents
In core/tests/tests.go around lines 356 to 370, the code waits one second after
ctx.Done() but does not wait for all goroutines to finish before calling
bifrostClient.Cleanup(), risking race conditions. Modify the select statement so
that in both cases, after ctx.Done() or allDoneChan, the code waits for
wg.Wait() to ensure all goroutines have completed before proceeding to cleanup.
This synchronizes cleanup with goroutine completion and prevents panics from
concurrent writes.

@akshaydeo akshaydeo merged commit e61f2b5 into main Jun 3, 2025
2 checks passed
@Pratham-Mishra04 Pratham-Mishra04 deleted the 06-03-feat_ctx_cancel_support_added branch June 3, 2025 08:48
@coderabbitai coderabbitai Bot mentioned this pull request Jun 5, 2025
akshaydeo added a commit that referenced this pull request Nov 17, 2025
# Add context propagation and request cancellation support

This PR adds support for context propagation and request cancellation throughout the Bifrost system. It allows clients to cancel in-flight requests when their context is cancelled or times out, improving resource management and responsiveness.

Key changes:
- Added context propagation from client requests to provider API calls
- Implemented request cancellation handling in all providers
- Added a new `RequestCancelled` error type to identify cancelled requests
- Modified the `ChannelMessage` struct to include the request context
- Improved the `Cleanup` method to gracefully shut down without signal handling
- Added proper context handling in test utilities to ensure clean test termination
- Refactored provider interfaces to accept context in method signatures

The implementation ensures that when a client cancels a request context, Bifrost will stop processing that request and return an appropriate cancellation error. This is particularly important for long-running requests or when clients need to implement timeouts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants