Skip to content

feat(plugin): filter discovered models via includeModels/excludeModels - #21

Open
zyc wants to merge 1 commit into
yuseferi:mainfrom
zyc:feat/include-exclude-models
Open

feat(plugin): filter discovered models via includeModels/excludeModels#21
zyc wants to merge 1 commit into
yuseferi:mainfrom
zyc:feat/include-exclude-models

Conversation

@zyc

@zyc zyc commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds per-provider includeModels/excludeModels options (glob patterns, * only) so a single LiteLLM proxy's catalog can be split across several OpenCode providers — e.g. one per naming prefix — without hand-maintaining a model list per provider. Also fixes a pre-existing idempotency-cache bug that already affects the litellm/litellm-responses pairing documented in the README.

Type of change

  • 🐛 Bug fix (non-breaking)
  • ✨ New feature (non-breaking)
  • 💥 Breaking change
  • 📝 Documentation only
  • 🔧 Internal / refactor

(Also includes a small non-breaking bug fix as a drive-by — see below.)

Checklist

  • npm run typecheck passes
  • No new runtime dependencies
  • README updated (new "Splitting one proxy into multiple providers" section + Features table row)
  • CHANGELOG.md updated under ## [Unreleased]
  • Commit messages follow Conventional Commits

Details

  • includeModels is evaluated first (default: everything passes, so this is fully backward-compatible for anyone not setting either option); excludeModels is evaluated after and always wins. Implemented in src/utils/model-filter.ts with a minimal *-only glob-to-regex conversion (no new dependency).
  • Applied in both the config hook (src/plugin/index.ts, the path OpenCode actually executes) and discoverBucket (src/plugin/discover.ts, the V2-schema path — it has no callers today, kept in sync for consistency with the rest of that file).
  • Drive-by fix: injectedModelIds was keyed only by baseURL, so any two providers sharing a proxy clobber each other's idempotency tracking on every config-hook invocation, defeating the "repeat invocations are a no-op" guarantee. This already affects the existing litellm/litellm-responses pairing (README "Reasoning models") — includeModels/excludeModels just adds another way to hit it. Now keyed by providerId:baseURL.
  • Warns (in the config hook only) when includeModels/excludeModels removes every discovered model for a provider, since a typo'd glob pattern is the likeliest misuse and would otherwise leave the provider silently empty.

How was this tested?

  • npm run typecheck (only check this repo's CI runs — no test suite exists yet).
  • Manually traced the glob-matching logic against edge cases: empty patterns, patterns containing regex metacharacters, and real model ids with literal dots (gpt-4.1, claude-3.5-sonnet) to confirm they're matched literally, not misinterpreted as regex.
  • Running against my own LiteLLM proxy in daily use since before this PR, across two provider configs at once (one excludeModels-only, one combining includeModels+excludeModels) splitting the same proxy's catalog into two OpenCode providers — confirmed via the plugin's own discovery log line and opencode models --verbose.

Summary by CodeRabbit

  • New Features

    • Added model filtering for LiteLLM providers using includeModels and excludeModels glob patterns.
    • Supports separate provider configurations for production, staging, canary, and other model sets.
    • Inclusion filters are applied first, with exclusions taking precedence.
    • Added clearer discovery reporting when models are filtered or no eligible models remain.
  • Documentation

    • Documented model filtering options, behavior, and configuration examples.

Adds per-provider includeModels/excludeModels options (glob patterns,
* only) so a single LiteLLM proxy can be split across several OpenCode
providers -- e.g. one per upstream naming prefix -- without hand-
maintaining a model list per provider.

includeModels is evaluated first (default: everything passes),
excludeModels afterwards and always wins. Applied in both the config
hook (src/plugin/index.ts, the path OpenCode actually executes) and
discoverBucket (src/plugin/discover.ts, the V2-schema path kept for
consistency -- it has no callers today, so this is unreachable code,
same as the rest of that file).

Also fixes an idempotency-cache bug: injectedModelIds was keyed only
by baseURL, so any two providers sharing a baseURL clobber each
other's injected-model tracking on every config-hook invocation,
defeating the "repeat invocations are a no-op" guarantee. This
already affects the existing litellm/litellm-responses pairing
(README "Reasoning models") -- includeModels/excludeModels just adds
another way to hit it, by design. Now keyed by providerId:baseURL.

In the config hook only (discoverBucket has no equivalent logging to
begin with), also warns when includeModels/excludeModels removes
every non-wildcard discovered model for a provider, since a typo'd
glob pattern is the likeliest way to misuse this feature and it would
otherwise just leave the provider silently empty.
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b6896f22-a3aa-47b7-b9ae-029edee69308

📥 Commits

Reviewing files that changed from the base of the PR and between f7a20e0 and 246f09a.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • README.md
  • src/plugin/discover.ts
  • src/plugin/index.ts
  • src/types/index.ts
  • src/utils/index.ts
  • src/utils/model-filter.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The plugin adds includeModels and excludeModels provider options. It filters discovered model IDs with anchored * patterns, applies exclusions after inclusions, and scopes discovery caching by provider ID and base URL.

Changes

Model discovery filtering

Layer / File(s) Summary
Filter contract and matcher
src/types/index.ts, src/utils/model-filter.ts, src/utils/index.ts
Adds includeModels and excludeModels options and exports matching logic for literal characters and * wildcards.
Discovery integration and caching
src/plugin/discover.ts, src/plugin/index.ts
Filters models before transport selection, tracks filtered counts, warns when all non-wildcard models are removed, and keys discovery state by provider ID and base URL.
Configuration documentation
README.md, CHANGELOG.md
Documents multi-provider filtering, filter precedence, wildcard behavior, and the unreleased feature.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 246f0

This change adds configurable model filtering and an idempotency-key fix without any identified current-head merge-blocking risk; it is merge-ready after normal checks and review.

Possibly related PRs

Suggested reviewers: yuseferi

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: filtering discovered plugin models with includeModels and excludeModels.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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