Skip to content

Commit fcb4512

Browse files
committed
fix: drop existing overrides for filtered-out models
mergeModels previously re-merged every entry from existing provider model config, so a user override for a model the filter excludes (e.g. includeModels: ["claude-*"] with an existing gpt-5.6-terra override) was still exposed. Pass an allowlist of surviving model IDs (only when a filter is active) so overrides are preserved only for models that survive filtering. No behavior change when no filter is configured.
1 parent be84aaa commit fcb4512

3 files changed

Lines changed: 48 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ and this project follows [Semantic Versioning](https://semver.org/).
1212
- `includeModels` and `excludeModels` plugin options to filter the discovered
1313
CLIProxyAPI catalog so only a subset of models is exposed to OpenCode.
1414
Entries are glob patterns; `excludeModels` takes precedence over
15-
`includeModels`. Filtering to zero models fails loudly at startup.
15+
`includeModels`. Existing model overrides are only preserved for models that
16+
survive filtering. Filtering to zero models fails loudly at startup.
1617

1718
## [0.1.2] - 2026-07-28
1819

src/index.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,45 @@ describe("CLIProxyAPIPlugin", () => {
261261
}
262262
})
263263

264+
test("filtering drops existing overrides for excluded models but keeps included ones", async () => {
265+
const originalFetch = globalThis.fetch
266+
globalThis.fetch = async () =>
267+
Response.json({
268+
data: [{ id: "claude-sonnet-4-6" }, { id: "gpt-5.6-terra" }],
269+
})
270+
271+
try {
272+
const plugin = await CLIProxyAPIPlugin(
273+
{
274+
client: { app: { log: async () => ({}) } },
275+
} as PluginInput,
276+
{
277+
baseURL: "http://cliproxy.test:8317",
278+
apiKey: "secret",
279+
includeModels: ["claude-*"],
280+
},
281+
)
282+
const config: Config = {
283+
provider: {
284+
cliproxyapi: {
285+
models: {
286+
"gpt-5.6-terra": { name: "My Terra" },
287+
"claude-sonnet-4-6": { name: "My Claude" },
288+
},
289+
},
290+
},
291+
}
292+
293+
await plugin.config?.(config)
294+
295+
const models = config.provider?.cliproxyapi?.models ?? {}
296+
expect(Object.keys(models).sort()).toEqual(["claude-sonnet-4-6"])
297+
expect(models["claude-sonnet-4-6"]?.name).toBe("My Claude")
298+
} finally {
299+
globalThis.fetch = originalFetch
300+
}
301+
})
302+
264303
test("fails loudly when the filter matches no discovered models", async () => {
265304
const originalFetch = globalThis.fetch
266305
globalThis.fetch = async () =>

src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ export const CLIProxyAPIPlugin: Plugin = async ({ client }, rawOptions) => {
9090
protocol: options.protocol ?? "chat",
9191
catalog: filteredCatalog,
9292
protocolCatalog: protocolDiscovery.catalog,
93+
allowedModelIDs: filtering
94+
? new Set(filteredCatalog.map((model) => model.id))
95+
: undefined,
9396
})
9497

9598
await client.app.log({
@@ -140,6 +143,7 @@ function addProvider(
140143
protocol: "chat" | "responses"
141144
catalog: CatalogModel[]
142145
protocolCatalog: ModelProtocolCatalog
146+
allowedModelIDs?: Set<string>
143147
},
144148
) {
145149
const existing = config.provider?.[input.providerID]
@@ -186,7 +190,7 @@ function addProvider(
186190
baseURL: input.baseURL,
187191
...(input.apiKey ? { apiKey: input.apiKey } : {}),
188192
},
189-
models: mergeModels(discovered, existing?.models),
193+
models: mergeModels(discovered, existing?.models, input.allowedModelIDs),
190194
},
191195
}
192196
}
@@ -203,10 +207,12 @@ function resolveModelNpm(
203207
function mergeModels(
204208
discovered: Record<string, ModelConfig>,
205209
existing: ProviderConfig["models"],
210+
allowedModelIDs?: Set<string>,
206211
): Record<string, ModelConfig> {
207212
const merged = { ...discovered }
208213

209214
for (const [modelID, model] of Object.entries(existing ?? {})) {
215+
if (allowedModelIDs && !allowedModelIDs.has(modelID)) continue
210216
const discoveredModel = merged[modelID]
211217
const providerNpm = model.provider?.npm ?? discoveredModel?.provider?.npm
212218
merged[modelID] = {

0 commit comments

Comments
 (0)