Skip to content

feat: add modelBlacklistRegex system setting to filter channel-derive…#1673

Merged
looplj merged 2 commits into
looplj:unstablefrom
nb5p:feature/model-blacklist-regex
May 16, 2026
Merged

feat: add modelBlacklistRegex system setting to filter channel-derive…#1673
looplj merged 2 commits into
looplj:unstablefrom
nb5p:feature/model-blacklist-regex

Conversation

@nb5p

@nb5p nb5p commented May 15, 2026

Copy link
Copy Markdown
Contributor

…d models

Add a regex-based blacklist on system model settings. When QueryAllChannelModels is enabled, channel-derived model IDs matching the pattern are excluded from /v1/models output. Configured Model entities are never filtered, and the setting is grayed out / ineffective when QueryAllChannelModels is off.

Server-side validation rejects invalid regex on save via xregexp.ValidateRegex (regexp2 / .NET-style engine). The frontend defers all syntax validation to the server to avoid divergence with the ECMAScript engine.

…d models

Add a regex-based blacklist on system model settings. When QueryAllChannelModels
is enabled, channel-derived model IDs matching the pattern are excluded from
/v1/models output. Configured Model entities are never filtered, and the setting
is grayed out / ineffective when QueryAllChannelModels is off.

Server-side validation rejects invalid regex on save via xregexp.ValidateRegex
(regexp2 / .NET-style engine). The frontend defers all syntax validation to the
server to avoid divergence with the ECMAScript engine.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a modelBlacklistRegex system setting that lets administrators exclude channel-derived model IDs from /v1/models output using a regexp2/.NET-style regex pattern. The filter is a no-op when QueryAllChannelModels is disabled, and explicitly configured Model entities are never affected.

  • Backend: SystemModelSettings gains a ModelBlacklistRegex field; SetModelSettings validates the pattern via xregexp.ValidateRegex before persisting; ListEnabledModels applies the filter inside the channel-model merge loop, caching the blacklist decision in modelSet to avoid redundant regex evaluations per model ID.
  • GraphQL layer: Schema and generated resolver updated symmetrically — non-null String! output field, optional String input field (consistent with existing settings fields).
  • Frontend: A new card in the model-settings dialog renders a text input that is visually grayed-out and functionally disabled when QueryAllChannelModels is off; six integration tests cover filtering, empty-pattern passthrough, invalid-pattern rejection, bypass when the feature flag is off, and configured-entity protection.

Confidence Score: 5/5

Safe to merge — blacklist filtering is additive, opt-in, and defaults to an empty string (disabled).

The change is isolated to the channel-model merge loop; configured Model entities are pre-populated in modelSet before the blacklist runs, so they are structurally protected. Server-side validation at SetModelSettings prevents invalid patterns from being persisted. The exactMatch fast-path and the ensureAnchored full-string semantics are both exercised by the new integration tests. No existing code paths are modified in a breaking way.

No files require special attention. The generated GQL resolver (generated.go) is the largest change by line count but is mechanical and consistent with existing field patterns.

Important Files Changed

Filename Overview
internal/server/biz/model.go Integrates blacklist filtering in the channel-model merge loop; logic correctly skips configured models and caches the blacklist decision in modelSet.
internal/server/biz/system.go Adds ModelBlacklistRegex to SystemModelSettings struct and gates SetModelSettings with xregexp.ValidateRegex; error message quality is discussed in existing review threads.
internal/server/biz/model_test.go Adds six integration test cases covering: basic filtering, empty pattern passthrough, invalid-pattern rejection, QueryAllChannelModels=false bypass, configured-entity protection, and exactMatch fast-path.
internal/server/biz/system_default.go Adds explicit zero-value defaults for AutoReasoningEffort and ModelBlacklistRegex; no behavioral change since Go initialises these to false/"".
internal/server/gql/system.graphql Adds modelBlacklistRegex: String! to SystemModelSettings output and optional String to UpdateSystemModelSettingsInput; follows the same pattern as other settings fields.
internal/server/gql/generated.go Auto-generated resolver code for modelBlacklistRegex field; correctly uses unmarshalOString2string for the optional input field and marshalNString2string for the non-null output type.
frontend/src/features/models/components/models-settings-dialog.tsx Adds regex input field to the settings dialog; correctly grays out the card and disables the input when QueryAllChannelModels is off or a mutation is in flight.
frontend/src/features/system/data/system.ts Extends GraphQL query, ModelSettings interface, and UpdateModelSettingsInput with modelBlacklistRegex; consistent with existing field additions.
frontend/src/locales/en/models.json Adds English i18n keys for label, description, and placeholder; copy is accurate and consistent with the PR description.
frontend/src/locales/zh-CN/models.json Adds Chinese i18n keys for the new setting; translations are consistent with the English copy.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ListEnabledModels] --> B[queryConfiguredModelFacades]
    B --> C[ModelSettingsOrDefault]
    C --> D{QueryAllChannelModels?}
    D -- false --> E[Return configuredModels only]
    D -- true --> F[Init modelSet from configuredModels]
    F --> G[Iterate channel entries]
    G --> H{modelSet contains ID?}
    H -- yes --> G
    H -- no --> I{blacklist != '' AND MatchString?}
    I -- yes --> J[modelSet ID = true — skip]
    J --> G
    I -- no --> K[Add to models + modelSet]
    K --> G
    G -- done --> L{allowedModelIDs filter?}
    L -- yes --> M[Filter by key profile]
    L -- no --> N[Return merged models]
    M --> N
Loading

Reviews (2): Last reviewed commit: "perf: cache blacklist-matched model IDs ..." | Re-trigger Greptile

Comment on lines +1039 to +1041
if err := xregexp.ValidateRegex(settings.ModelBlacklistRegex); err != nil {
return fmt.Errorf("invalid model blacklist regex: %w", err)
}

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.

P2 Validation error discards root cause

xregexp.getOrCreatePattern calls regexp2.Compile and, on failure, sets only compileErr = true — the original error value is never stored. As a result, ValidateRegex can only produce "invalid regex pattern: <pattern>", and the caller sees "invalid model blacklist regex: invalid regex pattern: [unclosed" with no indication of what is syntactically wrong. Since the PR description explicitly positions server-side validation as the user-facing feedback mechanism, this means a user submitting a bad pattern has no actionable error message to guide correction.

Comment thread internal/server/biz/model.go

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a 'Model Blacklist Regex' feature, allowing administrators to exclude specific channel-derived models from the /v1/models API output using regular expressions. The changes include UI updates to the settings dialog, new translation strings, and backend logic to validate and apply the regex filter during model listing. A performance improvement was suggested to cache blacklisted model IDs in the modelSet to avoid redundant regex evaluations when the same model ID is encountered across multiple channels.

Comment on lines +632 to +634
if blacklist != "" && xregexp.MatchString(blacklist, requestModel) {
continue
}

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.

medium

To improve performance when multiple channels provide the same model IDs, you should add the blacklisted model to modelSet. This ensures that the regex match is only performed once per unique model ID across all channels, avoiding redundant computations in the nested loop.

Suggested change
if blacklist != "" && xregexp.MatchString(blacklist, requestModel) {
continue
}
if blacklist != "" && xregexp.MatchString(blacklist, requestModel) {
modelSet[requestModel] = true
continue
}

When a channel model matches the blacklist regex, mark its ID in modelSet so
the same model ID coming from a subsequent channel is short-circuited by the
existing modelSet check instead of re-running the regex match.

Addresses Gemini review feedback on PR looplj#1673.
@looplj looplj merged commit 587b01a into looplj:unstable May 16, 2026
4 checks passed
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