Skip to content

[fix]: classify dynamic plugins by the hooks they actually export - #5702

Open
eyeveil wants to merge 1 commit into
maximhq:devfrom
eyeveil:fix/dynamic-plugin-hook-classification
Open

[fix]: classify dynamic plugins by the hooks they actually export#5702
eyeveil wants to merge 1 commit into
maximhq:devfrom
eyeveil:fix/dynamic-plugin-hook-classification

Conversation

@eyeveil

@eyeveil eyeveil commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Fixes #5700

Summary

DynamicPlugin satisfies all three hook interfaces regardless of which symbols the .so exports, and both classification sites use plain type assertions. So every dynamic plugin lands in all three interface caches, runs no-op hooks per request, reports types it does not implement, and gets Cleanup() called once per list on removal, which is a double close for anything that frees resources there.

Switched both sites to the As* helpers in framework/plugins, which also check the hook pointers. That is what they are there for. Builtins are concrete types, so nothing changes for them.

Type of change

  • Bug fix

Affected areas

  • Transports (HTTP)
  • Plugins

How to test

Install a .so exporting GetName, Cleanup and PreLLMHook but no MCP hooks, then disable it. Before: Cleanup runs twice and the API lists mcp in its types. After: once, and the types match the exported symbols.

Breaking changes

  • No

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate - DynamicPlugin hook fields are unexported, so a test would need to live in framework/plugins next to the As* helpers. Happy to add one there if you would like.
  • I verified builds succeed (Go and UI)

A .so plugin is wrapped in a DynamicPlugin, which structurally satisfies
LLMPlugin, MCPPlugin and HTTPTransportPlugin regardless of which symbols the .so
exports. Bare type assertions therefore classified every dynamic plugin as all
three, so it landed in all three interface caches and ran no-op hooks on every
request, reported misleading types through the API, and had Cleanup() called once
per list on removal - a double close for plugins that release resources there.

Both call sites now use the framework's As* helpers, which additionally check the
hook function pointers. Built-in plugins are unaffected; they are concrete types
whose classification is unchanged.

Changes:
- transports/bifrost-http/lib/config.go - rebuildInterfaceCaches
- transports/bifrost-http/server/plugins.go - InferPluginTypes
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved plugin classification during loading and registration.
    • Prevented dynamically loaded plugins from being incorrectly assigned to multiple plugin types.
    • Ensured plugin capabilities are identified based on their actual supported hooks.

Walkthrough

Changes

Dynamic plugin classification

Layer / File(s) Summary
Use dynamic plugin interface adapters
transports/bifrost-http/lib/config.go, transports/bifrost-http/server/plugins.go
Plugin caches and inferred plugin types now depend on AsLLMPlugin, AsMCPPlugin, and AsHTTPTransportPlugin hook resolution instead of direct interface assertions. Documentation describes dynamic plugin wrapper behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: akshaydeo, danpiths, pratham-mishra04, roroghost17

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main fix: classifying dynamic plugins by the hooks they actually export.
Description check ✅ Passed The PR description covers the summary, change type, affected areas, testing, breaking changes, and checklist, with only minor template gaps.
Linked Issues check ✅ Passed The code changes match #5700 by switching both classification sites to the As* helpers, aligning plugin types with exported hooks.
Out of Scope Changes check ✅ Passed The added documentation in server/plugins.go is directly related to the classification fix, with no unrelated changes evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

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

🔧 golangci-lint (2.12.2)

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


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

❤️ Share

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

@eyeveil
eyeveil force-pushed the fix/dynamic-plugin-hook-classification branch from d6855d3 to 9c5fb61 Compare July 30, 2026 18:36
@CLAassistant

CLAassistant commented Jul 30, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
transports/bifrost-http/lib/config.go (1)

5134-5144: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add table-driven coverage for hook-based plugin classification.

rebuildInterfaceCaches() and InferPluginTypes() now depend on the framework’s As* helpers. Add deterministic coverage for dynamic plugins with LLM-only, MCP-only, HTTP-only, multiple hooks, and no hooks, asserting both cache contents and InferPluginTypes results.

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

In `@transports/bifrost-http/lib/config.go` around lines 5134 - 5144, Add
table-driven tests covering dynamic plugins with LLM-only, MCP-only, HTTP-only,
multiple-hook, and no-hook configurations. For each case, invoke
rebuildInterfaceCaches() and InferPluginTypes(), then assert the expected cache
membership and inferred plugin types, ensuring classification uses the framework
As* helpers rather than bare interface assertions.

Source: Coding guidelines

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

Nitpick comments:
In `@transports/bifrost-http/lib/config.go`:
- Around line 5134-5144: Add table-driven tests covering dynamic plugins with
LLM-only, MCP-only, HTTP-only, multiple-hook, and no-hook configurations. For
each case, invoke rebuildInterfaceCaches() and InferPluginTypes(), then assert
the expected cache membership and inferred plugin types, ensuring classification
uses the framework As* helpers rather than bare interface assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 55f3fab1-351d-4c14-a2a4-1d9049aeff56

📥 Commits

Reviewing files that changed from the base of the PR and between 02ceef3 and d6855d3.

📒 Files selected for processing (3)
  • framework/logstore/asyncjob_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/server/plugins.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
transports/bifrost-http/server/plugins.go (1)

24-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add table-driven regression coverage for adapter-based classification.

Cover dynamic plugins with no hooks, each individual hook family, multiple hook families, and built-in plugins. Verify both InferPluginTypes and rebuildInterfaceCaches report the same classifications.

As per coding guidelines, Go behavior changes should have deterministic, table-driven coverage.

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

In `@transports/bifrost-http/server/plugins.go` around lines 24 - 42, Add
deterministic table-driven tests covering dynamic plugins with no hooks, each
individual hook family, combinations of multiple hook families, and built-in
plugins. For every case, assert that both InferPluginTypes and
rebuildInterfaceCaches produce the same expected classifications, using the
existing plugin adapters and test helpers rather than duplicating classification
logic.

Source: Coding guidelines

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

Nitpick comments:
In `@transports/bifrost-http/server/plugins.go`:
- Around line 24-42: Add deterministic table-driven tests covering dynamic
plugins with no hooks, each individual hook family, combinations of multiple
hook families, and built-in plugins. For every case, assert that both
InferPluginTypes and rebuildInterfaceCaches produce the same expected
classifications, using the existing plugin adapters and test helpers rather than
duplicating classification logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 38faa928-5b2b-4cec-b3f2-ab8494312ce1

📥 Commits

Reviewing files that changed from the base of the PR and between d6855d3 and 9c5fb61.

📒 Files selected for processing (2)
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/server/plugins.go

@eyeveil

eyeveil commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

recheck

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: dynamic .so plugins are classified as every plugin type

2 participants