Skip to content

feat: add plugin short-circuit control with fallback management with docs enhancement#105

Merged
akshaydeo merged 1 commit intomainfrom
06-21-feat_plugin_schema_and_docs_enhancement
Jun 23, 2025
Merged

feat: add plugin short-circuit control with fallback management with docs enhancement#105
akshaydeo merged 1 commit intomainfrom
06-21-feat_plugin_schema_and_docs_enhancement

Conversation

@Pratham-Mishra04
Copy link
Copy Markdown
Collaborator

Enhanced Plugin System with Short-Circuit Control and Fallback Management

This PR introduces a significant enhancement to the Bifrost plugin system, providing more control over request flow and error handling. The key improvements include:

  1. New PluginShortCircuit Type: Replaces direct response returns with a structured approach that allows plugins to return either a response or an error when short-circuiting.

  2. Fallback Control Mechanism: Adds an AllowFallbacks field to BifrostError, giving plugins explicit control over whether fallback providers should be attempted when errors occur:

    • AllowFallbacks = &true: Try fallback providers
    • AllowFallbacks = &false: Return error immediately, no fallbacks
    • AllowFallbacks = nil: Default to allowing fallbacks for resilience
  3. Improved Error Handling: The system now properly processes short-circuit errors and respects fallback preferences in both text and chat completion flows.

  4. Comprehensive Documentation: Completely rewrites the plugin documentation with detailed explanations, diagrams, examples, and best practices for plugin development.

These changes enable more sophisticated plugin behaviors such as:

  • Authentication plugins that can block requests without trying fallbacks
  • Rate limiting plugins that allow fallbacks to other providers
  • Caching plugins that can return cached responses directly

The implementation maintains backward compatibility while providing plugin developers with greater control over the request pipeline.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 20, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced plugin system to allow plugins to short-circuit processing with either a response or an error, providing more flexible control over request handling.
    • Added the ability for plugins to control fallback behavior after errors, letting them prevent or allow fallback attempts through a new flag.
  • Documentation

    • Significantly expanded and restructured plugin documentation, including detailed guides, lifecycle diagrams, error handling strategies, best practices, and troubleshooting tips.

Summary by CodeRabbit

  • New Features

    • Enhanced plugin system to support short-circuiting with either a response or an error, allowing plugins to halt processing and control fallback behavior more precisely.
    • Introduced explicit control over fallback attempts after errors, giving plugins the ability to prevent or allow fallback providers.
  • Documentation

    • Significantly expanded and restructured plugin documentation, including detailed guides, lifecycle diagrams, error handling strategies, best practices, troubleshooting, and performance tips.
    • Added comprehensive examples for rate limiting, authentication, and caching plugins, along with plugin development and testing guidelines.

Walkthrough

This update refactors the plugin short-circuiting and error handling mechanisms in the Bifrost core. It introduces a PluginShortCircuit struct to encapsulate plugin responses or errors, updates the plugin interface and pre-hook execution flow, adds explicit fallback control via an AllowFallbacks flag, and extensively revises the plugin developer documentation.

Changes

File(s) Change Summary
core/bifrost.go Refactored pre-hook execution to use PluginShortCircuit for richer short-circuit signaling; updated fallback logic based on error metadata.
core/schemas/bifrost.go Added AllowFallbacks *bool field to BifrostError for explicit fallback control.
core/schemas/plugin.go Introduced PluginShortCircuit struct; updated Plugin interface's PreHook signature and related documentation.
docs/plugins.md Extensively expanded and restructured documentation: new plugin lifecycle, error handling, fallback control, best practices, and examples.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Bifrost
    participant PluginPipeline
    participant Plugin(s)
    participant Provider

    Client->>Bifrost: Send Request
    Bifrost->>PluginPipeline: RunPreHooks
    PluginPipeline->>Plugin(s): PreHook
    Plugin(s)-->>PluginPipeline: (req, PluginShortCircuit)
    alt PluginShortCircuit.Response
        PluginPipeline->>PluginPipeline: RunPostHooks (with response)
        PluginPipeline-->>Bifrost: Return response
    else PluginShortCircuit.Error
        PluginPipeline->>PluginPipeline: RunPostHooks (with error)
        PluginPipeline-->>Bifrost: Return error
    else No ShortCircuit
        PluginPipeline-->>Bifrost: Continue
        Bifrost->>Provider: Call Provider
        Provider-->>Bifrost: Provider Response/Error
        Bifrost->>PluginPipeline: RunPostHooks (with provider result)
        PluginPipeline-->>Bifrost: Final Response/Error
    end
    Bifrost-->>Client: Return Response/Error
Loading

Possibly related PRs

Suggested reviewers

  • danpiths
  • akshaydeo

Poem

In the land of Bifrost, plugins hop anew,
With short-circuits richer, and fallbacks in view.
Errors now whisper, "Fallbacks? Yes or no?"
Documentation blossoms, so all devs may know.
With every new struct, the code grows more bright—
A rabbit’s delight in the refactored light! 🐇✨


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1a9edd9 and 3ed1607.

📒 Files selected for processing (4)
  • core/bifrost.go (5 hunks)
  • core/schemas/bifrost.go (1 hunks)
  • core/schemas/plugin.go (3 hunks)
  • docs/plugins.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
core/schemas/bifrost.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#80
File: plugins/maxim/main.go:249-264
Timestamp: 2025-06-14T06:17:54.426Z
Learning: In the BifrostError struct, the Error field is a struct (not a pointer), so accessing bifrostErr.Error.Message, bifrostErr.Error.Code, and bifrostErr.Error.Type is safe without nil checks on the Error field itself. The Code and Type fields are of type *string.
core/bifrost.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#79
File: core/bifrost.go:94-103
Timestamp: 2025-06-14T04:06:58.240Z
Learning: In core/bifrost.go, the count parameter in RunPostHooks method is intentionally kept separate from p.executedPreHooks to support circuit breaker plugins that may need to trigger PostHooks for only a subset of executed plugins when detecting failure conditions mid-execution.
🪛 LanguageTool
docs/plugins.md

[uncategorized] ~322-~322: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...nfiguration ## 8. Plugin Examples ### Rate Limiting Plugin ```go type RateLimitPlugin stru...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[grammar] ~533-~533: Did you mean “to Add”?
Context: ... Ensure thread safety where needed - Add extensive test coverage (>80%) 3. **Te...

(MISSING_TO_BEFORE_A_VERB)

🪛 markdownlint-cli2 (0.17.2)
docs/plugins.md

479-479: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

🔇 Additional comments (6)
core/schemas/bifrost.go (1)

418-430: Well-documented fallback control field!

The addition of the AllowFallbacks field with comprehensive documentation provides clear guidance for plugin developers. The three-state design (true/false/nil) with nil defaulting to true is a good choice for maintaining resilience by default.

core/schemas/plugin.go (2)

6-11: Clean plugin short-circuit abstraction!

The PluginShortCircuit struct provides a clear and type-safe way to handle both success and error short-circuits. The documentation effectively communicates the mutual exclusivity of the fields.


34-39: Excellent documentation for plugin developers!

The detailed explanation of the AllowFallbacks behavior with all three states (true/false/nil) will help plugin developers make informed decisions about fallback control.

core/bifrost.go (2)

74-90: Correct implementation of short-circuit returns!

The updated RunPreHooks method properly returns the PluginShortCircuit and maintains the count of executed pre-hooks for pipeline symmetry.


574-578: Proper implementation of fallback control!

The AllowFallbacks check correctly treats nil as true (default allow) and explicitly checks for false to prevent fallbacks. This maintains backward compatibility while providing explicit control.

Also applies to: 722-726

docs/plugins.md (1)

1-730: Exceptional plugin system documentation!

This comprehensive rewrite transforms the plugin documentation into a complete manual with:

  • Clear architecture diagrams and execution flows
  • Practical examples for common use cases
  • Detailed troubleshooting guide
  • Performance optimization tips

The documentation effectively explains the new PluginShortCircuit behavior and AllowFallbacks control, making it easy for developers to understand and implement plugins correctly.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch 06-21-feat_plugin_schema_and_docs_enhancement

🪧 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 auto-generate unit tests to generate unit tests for 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

Pratham-Mishra04 commented Jun 20, 2025

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: 3

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between bea5781 and 4b60f04.

📒 Files selected for processing (4)
  • core/bifrost.go (5 hunks)
  • core/schemas/bifrost.go (1 hunks)
  • core/schemas/plugin.go (3 hunks)
  • docs/plugins.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
core/schemas/bifrost.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#80
File: plugins/maxim/main.go:249-264
Timestamp: 2025-06-14T06:17:54.426Z
Learning: In the BifrostError struct, the Error field is a struct (not a pointer), so accessing bifrostErr.Error.Message, bifrostErr.Error.Code, and bifrostErr.Error.Type is safe without nil checks on the Error field itself. The Code and Type fields are of type *string.
core/bifrost.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#79
File: core/bifrost.go:94-103
Timestamp: 2025-06-14T04:06:58.240Z
Learning: In core/bifrost.go, the count parameter in RunPostHooks method is intentionally kept separate from p.executedPreHooks to support circuit breaker plugins that may need to trigger PostHooks for only a subset of executed plugins when detecting failure conditions mid-execution.
🪛 LanguageTool
docs/plugins.md

[uncategorized] ~322-~322: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...nfiguration ## 8. Plugin Examples ### Rate Limiting Plugin ```go type RateLimitPlugin stru...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[grammar] ~533-~533: Did you mean “to Add”?
Context: ... Ensure thread safety where needed - Add extensive test coverage (>80%) 3. **Te...

(MISSING_TO_BEFORE_A_VERB)

🪛 markdownlint-cli2 (0.17.2)
docs/plugins.md

479-479: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

🔇 Additional comments (5)
core/schemas/bifrost.go (1)

418-430: Well-designed fallback control mechanism!

The AllowFallbacks field is properly implemented as a pointer to distinguish between three states (nil/true/false), and the documentation clearly explains the behavior for plugin developers. The default behavior (nil = true) maintains resilience while giving plugins explicit control when needed.

core/bifrost.go (1)

574-579: Consistent fallback control implementation!

The AllowFallbacks check is correctly implemented in both TextCompletionRequest and ChatCompletionRequest. The logic properly treats nil as true (default behavior) and only skips fallbacks when explicitly set to false.

Also applies to: 723-727

docs/plugins.md (3)

51-55: Excellent documentation of the PluginShortCircuit type!

The struct definition clearly shows the mutual exclusivity between Response and Error fields. This matches the actual implementation and helps plugin developers understand the concept.


253-260: Excellent fallback decision matrix!

This table clearly communicates when to use different AllowFallbacks values based on the error type. It provides practical guidance that will help plugin developers make the right decisions.


551-603: Comprehensive plugin testing example!

The test structure demonstrates best practices with table-driven tests covering all scenarios including short-circuit behavior and fallback control. This will help plugin developers write thorough tests.

Comment thread core/schemas/plugin.go
Comment thread core/schemas/plugin.go
Comment thread core/bifrost.go
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

♻️ Duplicate comments (3)
core/schemas/plugin.go (2)

49-50: Breaking change requires migration guide for plugin developers.

The PreHook signature change from *BifrostResponse to *PluginShortCircuit will break all existing plugin implementations.


6-11: Document mutual exclusivity of Response and Error fields.

Add a comment clarifying that only one of Response or Error should be set at a time to prevent ambiguity.

 // PluginShortCircuit represents a plugin's decision to short-circuit the normal flow.
 // It can contain either a response (success short-circuit) or an error (error short-circuit).
+// Only one of Response or Error should be set at a time.
 type PluginShortCircuit struct {
core/bifrost.go (1)

628-646: Refactor duplicated short-circuit handling logic.

The short-circuit handling code is identical in both tryTextCompletion and tryChatCompletion. Extract this into a helper method to avoid maintenance issues.

+func (bifrost *Bifrost) handleShortCircuit(ctx *context.Context, shortCircuit *schemas.PluginShortCircuit, pipeline *PluginPipeline, preCount int) (*schemas.BifrostResponse, *schemas.BifrostError) {
+    if shortCircuit == nil {
+        return nil, nil
+    }
+    
+    // Handle short-circuit with response (success case)
+    if shortCircuit.Response != nil {
+        resp, bifrostErr := pipeline.RunPostHooks(ctx, shortCircuit.Response, nil, preCount)
+        if bifrostErr != nil {
+            return nil, bifrostErr
+        }
+        return resp, nil
+    }
+    
+    // Handle short-circuit with error
+    if shortCircuit.Error != nil {
+        resp, bifrostErr := pipeline.RunPostHooks(ctx, nil, shortCircuit.Error, preCount)
+        if bifrostErr != nil {
+            return nil, bifrostErr
+        }
+        return resp, nil
+    }
+    
+    return nil, nil
+}

Then replace the duplicated code in both methods:

-    if shortCircuit != nil {
-        // Handle short-circuit with response (success case)
-        if shortCircuit.Response != nil {
-            resp, bifrostErr := pipeline.RunPostHooks(&ctx, shortCircuit.Response, nil, preCount)
-            if bifrostErr != nil {
-                return nil, bifrostErr
-            }
-            return resp, nil
-        }
-        // Handle short-circuit with error
-        if shortCircuit.Error != nil {
-            resp, bifrostErr := pipeline.RunPostHooks(&ctx, nil, shortCircuit.Error, preCount)
-            if bifrostErr != nil {
-                return nil, bifrostErr
-            }
-            return resp, nil
-        }
-    }
+    if resp, err := bifrost.handleShortCircuit(&ctx, shortCircuit, pipeline, preCount); resp != nil || err != nil {
+        return resp, err
+    }

Also applies to: 776-794

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4b60f04 and 57ebad0.

📒 Files selected for processing (4)
  • core/bifrost.go (5 hunks)
  • core/schemas/bifrost.go (1 hunks)
  • core/schemas/plugin.go (3 hunks)
  • docs/plugins.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
core/schemas/bifrost.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#80
File: plugins/maxim/main.go:249-264
Timestamp: 2025-06-14T06:17:54.426Z
Learning: In the BifrostError struct, the Error field is a struct (not a pointer), so accessing bifrostErr.Error.Message, bifrostErr.Error.Code, and bifrostErr.Error.Type is safe without nil checks on the Error field itself. The Code and Type fields are of type *string.
core/bifrost.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#79
File: core/bifrost.go:94-103
Timestamp: 2025-06-14T04:06:58.240Z
Learning: In core/bifrost.go, the count parameter in RunPostHooks method is intentionally kept separate from p.executedPreHooks to support circuit breaker plugins that may need to trigger PostHooks for only a subset of executed plugins when detecting failure conditions mid-execution.
🪛 LanguageTool
docs/plugins.md

[uncategorized] ~322-~322: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...nfiguration ## 8. Plugin Examples ### Rate Limiting Plugin ```go type RateLimitPlugin stru...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[grammar] ~533-~533: Did you mean “to Add”?
Context: ... Ensure thread safety where needed - Add extensive test coverage (>80%) 3. **Te...

(MISSING_TO_BEFORE_A_VERB)

🪛 markdownlint-cli2 (0.17.2)
docs/plugins.md

479-479: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

🔇 Additional comments (5)
core/schemas/bifrost.go (1)

418-430: Well-designed fallback control mechanism!

The AllowFallbacks field provides plugin developers with explicit control over fallback behavior while maintaining backward compatibility. The three-state design (true/false/nil) with nil defaulting to true is a good pattern for optional fields.

core/bifrost.go (2)

74-90: Clean implementation of short-circuit mechanism in PreHooks!

The updated RunPreHooks correctly handles the new PluginShortCircuit return type and maintains proper tracking of executed plugins for pipeline symmetry.


574-579: Correct implementation of fallback control!

The AllowFallbacks check properly handles all three states (true/false/nil) with clear comments explaining the default behavior. This gives plugins fine-grained control over fallback attempts.

Also applies to: 722-727

docs/plugins.md (2)

1-730: Excellent comprehensive plugin documentation!

The documentation provides thorough coverage of the plugin system with:

  • Clear architectural overview and lifecycle diagrams
  • Practical examples demonstrating short-circuit and fallback control
  • Comprehensive testing guidelines and best practices
  • Helpful troubleshooting guide

This will be invaluable for plugin developers.


322-323: Use hyphen for compound adjective.

"Rate limiting" should be hyphenated when used as a compound adjective.

-### Rate Limiting Plugin
+### Rate-Limiting Plugin

Likely an incorrect or invalid review comment.

Comment thread docs/plugins.md
@Pratham-Mishra04 Pratham-Mishra04 marked this pull request as ready for review June 21, 2025 11:24
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-21-feat_plugin_schema_and_docs_enhancement branch from 57ebad0 to 1a9edd9 Compare June 22, 2025 18:53
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-21-feat_plugin_schema_and_docs_enhancement branch from 1a9edd9 to 3ed1607 Compare June 23, 2025 18:26
@akshaydeo akshaydeo merged commit 329c457 into main Jun 23, 2025
2 checks passed
@akshaydeo akshaydeo deleted the 06-21-feat_plugin_schema_and_docs_enhancement branch August 31, 2025 17:30
akshaydeo added a commit that referenced this pull request Nov 17, 2025
…docs enhancement (#105)

# Enhanced Plugin System with Short-Circuit Control and Fallback Management

This PR introduces a significant enhancement to the Bifrost plugin system, providing more control over request flow and error handling. The key improvements include:

1. **New PluginShortCircuit Type**: Replaces direct response returns with a structured approach that allows plugins to return either a response or an error when short-circuiting.

2. **Fallback Control Mechanism**: Adds an `AllowFallbacks` field to `BifrostError`, giving plugins explicit control over whether fallback providers should be attempted when errors occur:
   - `AllowFallbacks = &true`: Try fallback providers
   - `AllowFallbacks = &false`: Return error immediately, no fallbacks
   - `AllowFallbacks = nil`: Default to allowing fallbacks for resilience

3. **Improved Error Handling**: The system now properly processes short-circuit errors and respects fallback preferences in both text and chat completion flows.

4. **Comprehensive Documentation**: Completely rewrites the plugin documentation with detailed explanations, diagrams, examples, and best practices for plugin development.

These changes enable more sophisticated plugin behaviors such as:
- Authentication plugins that can block requests without trying fallbacks
- Rate limiting plugins that allow fallbacks to other providers
- Caching plugins that can return cached responses directly

The implementation maintains backward compatibility while providing plugin developers with greater control over the request pipeline.
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