Skip to content

feat(backends): add custom compatible connectors#30

Merged
matdev83 merged 2 commits into
mainfrom
feat/custom-compatible-backends
Jun 24, 2026
Merged

feat(backends): add custom compatible connectors#30
matdev83 merged 2 commits into
mainfrom
feat/custom-compatible-backends

Conversation

@matdev83

Copy link
Copy Markdown
Owner

Summary

  • add YAML-configurable custom OpenAI Chat Completions, OpenAI Responses, and Anthropic-compatible backend factories
  • enforce custom backend prefix validation during check-config and serve paths
  • add remote model discovery, static inventory override support, docs, and sample config examples

Tests

  • go test -parallel=8 ./internal/infra/runtimebundle ./cmd/lipstd/... -count=1
  • go test -parallel=8 ./...

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@matdev83, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 48 minutes and 1 second. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 96083ae7-d5aa-4def-b6d7-fc07f5375efb

📥 Commits

Reviewing files that changed from the base of the PR and between 34840ef and 490f5ba.

📒 Files selected for processing (2)
  • config/config.yaml
  • internal/pluginreg/custom_compatible_build_test.go
📝 Walkthrough

Walkthrough

Adds three YAML-only backend factory kinds (custom-openai-legacy-compatible, custom-openai-responses-compatible, custom-anthropic-compatible) that wire API-compatible endpoints without Go plugins. Includes backend_prefix validation (reserved/duplicate/character rules), API key resolution from env vars or credentials, remote/static model inventory, runtime validation in Build/BuildBootstrap, and documentation.

Changes

Custom Compatible Backends

Layer / File(s) Summary
Configurable prefix in Anthropic plugin and model discovery
internal/plugins/backends/modeldiscover/http_providers.go, internal/plugins/backends/anthropic/plugin.go
AnthropicModelsProvider gains a CanonicalPrefix field; anthropic.Config gains BackendPrefix. New() derives a canonical id from BackendPrefix (trimmed, with fallback to the bundled ID), sets BackendPrefixes and CanonicalPrefix accordingly, and updates all error messages and newConfigErrorBackend to use the derived id.
Custom backend schema, validation, and API key resolution
internal/pluginreg/custom_backends.go
Defines ErrCustomBackendPrefix, three kind constants, YAML schema structs, collectNumberedEnvKeys, resolveCustomCompatibleAPIKeys, validateCustomBackendPrefix (empty/character/reserved-prefix checks), duplicate detection across enabled instances, IsCustomCompatibleBackendKind, ValidateCustomCompatibleBackendPrefixes, transport-cap helpers, and reservedStandardBackendPrefixes.
Custom backend builders and standard table registration
internal/pluginreg/custom_backends.go, internal/pluginreg/backends_install.go, internal/pluginreg/standard_table.go, internal/pluginreg/spec_bundle_standard_inventory_test.go
Implements the central buildCustomOpenAICompatibleBackend function and two OpenAI variant factories, adds backendCustomAnthropicCompatible in backends_install.go, and registers all three in StandardBackendBundle with CredentialStatic security profiles. The inventory test expectation is updated to include the three new IDs.
Runtime validation in Build and BuildBootstrap
internal/infra/runtimebundle/build.go, internal/infra/runtimebundle/bootstrap_plan.go
Calls pluginreg.ValidateCustomCompatibleBackendPrefixes early in both Build and BuildBootstrap, returning a wrapped runtimebundle error on failure before any further initialization.
Unit tests: prefix, env keys, and backend builds
internal/pluginreg/custom_backend_prefix_test.go, internal/pluginreg/custom_backend_env_keys_test.go, internal/pluginreg/custom_compatible_build_test.go, internal/pluginreg/backend_prefix_inventory_test.go, internal/infra/runtimebundle/bootstrap_plan_test.go, internal/infra/runtimebundle/dual_backend_test.go
Covers validateCustomBackendPrefix/ValidateCustomCompatibleBackendPrefixes (empty, invalid chars, reserved, duplicate), collectNumberedEnvKeys behavior, resolveCustomCompatibleAPIKeys precedence rules, BuildBackend for all three custom kinds (transport caps, model namespacing, static inventory, missing base_url), reserved-prefix coverage of standard backends, and integration rejection tests in runtimebundle.
Documentation and config examples
docs/custom-compatible-backends.md, docs/plugin-authoring.md, config/config.yaml
New docs/custom-compatible-backends.md describing factory kinds, backend_prefix constraints, credential rules, model discovery, and three YAML examples. plugin-authoring.md adds a reference link. config/config.yaml gains commented example backend definitions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • matdev83/go-llm-interactive-proxy#23: Added modeldiscover.AnthropicModelsProvider and Anthropic model-inventory integration, which this PR extends by adding the configurable CanonicalPrefix field to that same provider.
  • matdev83/go-llm-interactive-proxy#25: Introduced backend-prefix registry machinery, which this PR builds on to validate custom backend_prefix values during runtimebundle.Build/BuildBootstrap and extends anthropic/plugin.go to honor a configurable prefix.
🚥 Pre-merge checks | ✅ 7 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the PR’s main change: adding custom compatible backend connectors.
Description check ✅ Passed The description directly covers the YAML-configurable backends, validation, docs, and tests in the change set.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Secrets ✅ Passed Only placeholder keys, example.com/localhost URLs, and dummy test secrets appear; no hardcoded production credentials, tokens, private keys, or sensitive internal URLs found.
Context Propagation ✅ Passed New backend/model-discovery paths pass ctx into HTTP requests and stream opens; model-registry refresh loops cancel via context.WithCancel/WaitGroup, so no leak found.
No Accidental Public Api Break ✅ Passed PASS: the PR only adds new config kinds/fields/functions and documents the new prefix validation and backend-prefix behavior, so no accidental API break is apparent.

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


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@config/config.yaml`:
- Around line 330-331: The sample block for backend_prefix is missing an
enforced validator constraint: it must not contain “/” or “:”. Update the
documentation near the existing backend_prefix and api_key_env_var_root comments
to list this rule alongside the uniqueness and reserved-prefix restrictions so
users can avoid check-config failures.

In `@internal/pluginreg/custom_compatible_build_test.go`:
- Around line 44-52: Replace the use of t.Fatalf inside the httptest handler in
custom_compatible_build_test.go with non-fatal test reporting, because the
handler runs in a separate goroutine. In the server setup for the models
endpoint, and similarly in the other handler blocks in this test file, use
t.Errorf to record the mismatch, then return immediately and optionally send an
appropriate non-200 response so the request fails cleanly. Keep the same checks
around r.URL.Path, the Authorization header, and the handler response body, but
avoid terminating the parent test from inside the HTTP callback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0394a60c-2f0f-48fe-b029-a921a5a688b4

📥 Commits

Reviewing files that changed from the base of the PR and between b5b0983 and 34840ef.

📒 Files selected for processing (17)
  • config/config.yaml
  • docs/custom-compatible-backends.md
  • docs/plugin-authoring.md
  • internal/infra/runtimebundle/bootstrap_plan.go
  • internal/infra/runtimebundle/bootstrap_plan_test.go
  • internal/infra/runtimebundle/build.go
  • internal/infra/runtimebundle/dual_backend_test.go
  • internal/pluginreg/backend_prefix_inventory_test.go
  • internal/pluginreg/backends_install.go
  • internal/pluginreg/custom_backend_env_keys_test.go
  • internal/pluginreg/custom_backend_prefix_test.go
  • internal/pluginreg/custom_backends.go
  • internal/pluginreg/custom_compatible_build_test.go
  • internal/pluginreg/spec_bundle_standard_inventory_test.go
  • internal/pluginreg/standard_table.go
  • internal/plugins/backends/anthropic/plugin.go
  • internal/plugins/backends/modeldiscover/http_providers.go
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: qa
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (Custom checks)

For server, CLI, worker, or network code, check that context.Context is propagated correctly, cancellation is respected, and new goroutines cannot leak indefinitely

**/*.go: Avoid any unless unavoidable at a protocol boundary
Use small interfaces defined where they are consumed
Do not use Java-style interface prefixes. Use idiomatic Go names such as Store, Router, Clock
Every I/O boundary takes context.Context
Establish explicit ownership for goroutines, channels, buffers, and cancellation
Prefer simple push/pull stream abstractions over ad hoc channel webs
Return errors, do not panic in request paths
Wrap errors with %w and preserve classification metadata
Keep config structs typed and explicit
Avoid circular imports by design
Do not mix frontend codec logic, routing policy, and backend invocation in one package
Add package docs where the boundary is non-obvious
Line length ~120+: break at semantic boundaries where practical. When splitting embedded JSON/SSE in tests or emulators, re-check brace matching
Slices in JSON and returned values: prefer explicit empty initialization (s := []T{} or make) so null never appears in JSON for 'empty list'
Short-lived append-only local buffers may use var s []T and append when the value never escapes
JSON presence vs null: when a wire shape must preserve 'field absent' vs explicit null vs empty containers, reuse internal/core/jsonpresence patterns

Files:

  • internal/pluginreg/spec_bundle_standard_inventory_test.go
  • internal/infra/runtimebundle/bootstrap_plan.go
  • internal/infra/runtimebundle/bootstrap_plan_test.go
  • internal/pluginreg/standard_table.go
  • internal/pluginreg/backends_install.go
  • internal/plugins/backends/modeldiscover/http_providers.go
  • internal/infra/runtimebundle/dual_backend_test.go
  • internal/pluginreg/custom_backend_prefix_test.go
  • internal/infra/runtimebundle/build.go
  • internal/pluginreg/custom_backend_env_keys_test.go
  • internal/pluginreg/custom_compatible_build_test.go
  • internal/pluginreg/backend_prefix_inventory_test.go
  • internal/plugins/backends/anthropic/plugin.go
  • internal/pluginreg/custom_backends.go

⚙️ CodeRabbit configuration file

**/*.go: Review as production Go code. Prioritize correctness, race conditions, goroutine leaks, context cancellation, timeout handling, error wrapping, nil-pointer risks, resource cleanup, defer placement, API compatibility, interface design, dependency boundaries, and testability. Avoid generic style comments when gofmt/golangci-lint already covers the issue.

Files:

  • internal/pluginreg/spec_bundle_standard_inventory_test.go
  • internal/infra/runtimebundle/bootstrap_plan.go
  • internal/infra/runtimebundle/bootstrap_plan_test.go
  • internal/pluginreg/standard_table.go
  • internal/pluginreg/backends_install.go
  • internal/plugins/backends/modeldiscover/http_providers.go
  • internal/infra/runtimebundle/dual_backend_test.go
  • internal/pluginreg/custom_backend_prefix_test.go
  • internal/infra/runtimebundle/build.go
  • internal/pluginreg/custom_backend_env_keys_test.go
  • internal/pluginreg/custom_compatible_build_test.go
  • internal/pluginreg/backend_prefix_inventory_test.go
  • internal/plugins/backends/anthropic/plugin.go
  • internal/pluginreg/custom_backends.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Prefer locking invariants (routing, streaming, B2BUA, capability mismatch, no-retry-after-output) through tests
Tests are behavior contracts, not implementation snapshots
Decoder and selector parsers should gain fuzz tests when practical
Keep tests near the package they validate unless a cross-package integration test is required

Files:

  • internal/pluginreg/spec_bundle_standard_inventory_test.go
  • internal/infra/runtimebundle/bootstrap_plan_test.go
  • internal/infra/runtimebundle/dual_backend_test.go
  • internal/pluginreg/custom_backend_prefix_test.go
  • internal/pluginreg/custom_backend_env_keys_test.go
  • internal/pluginreg/custom_compatible_build_test.go
  • internal/pluginreg/backend_prefix_inventory_test.go

⚙️ CodeRabbit configuration file

**/*_test.go: Review tests for meaningful assertions, table-driven coverage, race-prone tests, t.Parallel misuse, nondeterminism, leaked goroutines, real network or filesystem dependencies, fragile sleeps, and missing edge cases. Prefer testing observable behavior over implementation details.

Files:

  • internal/pluginreg/spec_bundle_standard_inventory_test.go
  • internal/infra/runtimebundle/bootstrap_plan_test.go
  • internal/infra/runtimebundle/dual_backend_test.go
  • internal/pluginreg/custom_backend_prefix_test.go
  • internal/pluginreg/custom_backend_env_keys_test.go
  • internal/pluginreg/custom_compatible_build_test.go
  • internal/pluginreg/backend_prefix_inventory_test.go
internal/**

⚙️ CodeRabbit configuration file

internal/**: Focus on package boundaries, hidden coupling, unexported API design, concurrency safety, deterministic behavior, and whether logic belongs in this internal package.

Files:

  • internal/pluginreg/spec_bundle_standard_inventory_test.go
  • internal/infra/runtimebundle/bootstrap_plan.go
  • internal/infra/runtimebundle/bootstrap_plan_test.go
  • internal/pluginreg/standard_table.go
  • internal/pluginreg/backends_install.go
  • internal/plugins/backends/modeldiscover/http_providers.go
  • internal/infra/runtimebundle/dual_backend_test.go
  • internal/pluginreg/custom_backend_prefix_test.go
  • internal/infra/runtimebundle/build.go
  • internal/pluginreg/custom_backend_env_keys_test.go
  • internal/pluginreg/custom_compatible_build_test.go
  • internal/pluginreg/backend_prefix_inventory_test.go
  • internal/plugins/backends/anthropic/plugin.go
  • internal/pluginreg/custom_backends.go
internal/plugins/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Keep provider-specific payload types inside adapters/plugins

Files:

  • internal/plugins/backends/modeldiscover/http_providers.go
  • internal/plugins/backends/anthropic/plugin.go
internal/plugins/backends/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use official vendor Go SDKs only inside backend plugins (OpenAI: openai-go); do not import provider SDKs from internal/core, pkg/lipapi, or pkg/lipsdk

Files:

  • internal/plugins/backends/modeldiscover/http_providers.go
  • internal/plugins/backends/anthropic/plugin.go
🪛 LanguageTool
docs/plugin-authoring.md

[style] ~3-~3: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...e README.md and config/config.yaml. For YAML-only OpenAI/Anthropic-compatible p...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~3-~3: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ds.md`](custom-compatible-backends.md). For the no-key local stub maintainer wo...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (17)
docs/custom-compatible-backends.md (1)

1-85: LGTM!

docs/plugin-authoring.md (1)

3-3: LGTM!

internal/plugins/backends/modeldiscover/http_providers.go (1)

54-58: LGTM!

Also applies to: 81-95

internal/plugins/backends/anthropic/plugin.go (1)

56-83: LGTM!

Also applies to: 99-99, 128-131

internal/pluginreg/custom_backends.go (2)

39-81: LGTM!

Also applies to: 115-218


83-95: 🎯 Functional Correctness

No issue: prefix matching is case-sensitive end-to-end, so mixed-case custom prefixes cannot shadow a standard connector.

			> Likely an incorrect or invalid review comment.
internal/pluginreg/backends_install.go (1)

260-282: LGTM!

internal/pluginreg/standard_table.go (1)

199-207: LGTM!

internal/pluginreg/spec_bundle_standard_inventory_test.go (1)

34-36: LGTM!

internal/infra/runtimebundle/build.go (1)

75-77: LGTM!

internal/infra/runtimebundle/bootstrap_plan.go (1)

93-95: LGTM!

internal/pluginreg/custom_backend_prefix_test.go (1)

8-80: LGTM!

internal/pluginreg/custom_backend_env_keys_test.go (1)

11-177: LGTM!

internal/pluginreg/backend_prefix_inventory_test.go (1)

34-122: LGTM!

internal/pluginreg/custom_compatible_build_test.go (1)

155-283: LGTM!

internal/infra/runtimebundle/bootstrap_plan_test.go (1)

93-124: LGTM!

internal/infra/runtimebundle/dual_backend_test.go (1)

55-112: LGTM!

Comment thread config/config.yaml Outdated
Comment thread internal/pluginreg/custom_compatible_build_test.go
@matdev83 matdev83 merged commit 47f8832 into main Jun 24, 2026
2 checks passed
@matdev83 matdev83 deleted the feat/custom-compatible-backends branch June 24, 2026 18:21
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