Skip to content

Commit 353a444

Browse files
committed
test(gateway): honor provider filters in small live profile
1 parent fa44554 commit 353a444

1 file changed

Lines changed: 92 additions & 14 deletions

File tree

src/gateway/gateway-models.profiles.live.test.ts

Lines changed: 92 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import { STREAM_ERROR_FALLBACK_TEXT } from "../agents/stream-message-shared.js";
5252
import { clearRuntimeConfigSnapshot, getRuntimeConfig } from "../config/io.js";
5353
import type { ModelsConfig, ModelProviderConfig, OpenClawConfig } from "../config/types.js";
5454
import { isTruthyEnvValue } from "../infra/env.js";
55+
import type { ModelRegistry } from "../llm/model-registry.js";
5556
import { normalizeGoogleModelId } from "../plugin-sdk/google-model-id.js";
5657
import { resolveProviderThinkingProfile } from "../plugins/provider-runtime.js";
5758
import type { ProviderThinkingModelCompat } from "../plugins/provider-thinking.types.js";
@@ -197,6 +198,29 @@ function providerScopedModelRegistryProviders(params: {
197198
});
198199
}
199200

201+
function filterGatewayLiveModelRefsByProvider(
202+
refs: readonly { provider: string; id: string }[],
203+
providerFilter: ReadonlySet<string> | null,
204+
): Array<{ provider: string; id: string }> {
205+
if (!providerFilter) {
206+
return [...refs];
207+
}
208+
const providers = new Set(
209+
[...providerFilter].map((provider) => normalizeProviderId(provider)).filter(Boolean),
210+
);
211+
return refs.filter((ref) => providers.has(normalizeProviderId(ref.provider)));
212+
}
213+
214+
function isWantedSmallGatewayLiveModel(params: {
215+
model: Pick<Model, "provider" | "id">;
216+
targetMatcher: ReturnType<typeof createLiveTargetMatcher>;
217+
}): boolean {
218+
return (
219+
params.targetMatcher.matchesProvider(params.model.provider) &&
220+
isSmallLiveModelRef({ provider: params.model.provider, id: params.model.id })
221+
);
222+
}
223+
200224
function shouldSuppressGatewayLiveOllamaWarnings(): boolean {
201225
return PROVIDERS !== null && !PROVIDERS.has("ollama");
202226
}
@@ -998,6 +1022,24 @@ function createExplicitLiveFallbackModel(provider: string, id: string): Model {
9981022
};
9991023
}
10001024

1025+
function createGatewayLiveTestRegistry(overrides: Partial<ModelRegistry>): ModelRegistry {
1026+
return {
1027+
find() {
1028+
return undefined;
1029+
},
1030+
getAll() {
1031+
return [];
1032+
},
1033+
getAvailable() {
1034+
return [];
1035+
},
1036+
hasConfiguredAuth() {
1037+
return true;
1038+
},
1039+
...overrides,
1040+
};
1041+
}
1042+
10011043
describe("resolveExplicitLiveModelCandidates", () => {
10021044
it("uses targeted registry lookup for explicit provider/model filters", () => {
10031045
const model = createGatewayLiveTestModel("xai", "grok-4.3");
@@ -1007,7 +1049,7 @@ describe("resolveExplicitLiveModelCandidates", () => {
10071049
env: {},
10081050
});
10091051
const candidates = resolveExplicitLiveModelCandidates({
1010-
modelRegistry: {
1052+
modelRegistry: createGatewayLiveTestRegistry({
10111053
find(provider, modelId) {
10121054
expect(provider).toBe("xai");
10131055
expect(modelId).toBe("grok-4.3");
@@ -1016,7 +1058,7 @@ describe("resolveExplicitLiveModelCandidates", () => {
10161058
getAll() {
10171059
throw new Error("explicit model lookup should not enumerate registry");
10181060
},
1019-
},
1061+
}),
10201062
modelFilter: new Set(["xai/grok-4.3"]),
10211063
providerFilter: new Set(["xai"]),
10221064
targetMatcher: matcher,
@@ -1033,7 +1075,7 @@ describe("resolveExplicitLiveModelCandidates", () => {
10331075
env: {},
10341076
});
10351077
const candidates = resolveExplicitLiveModelCandidates({
1036-
modelRegistry: {
1078+
modelRegistry: createGatewayLiveTestRegistry({
10371079
find(provider, modelId) {
10381080
expect(provider).toBe("google");
10391081
expect(modelId).toBe("gemini-3.1-pro-preview");
@@ -1042,7 +1084,7 @@ describe("resolveExplicitLiveModelCandidates", () => {
10421084
getAll() {
10431085
throw new Error("explicit model lookup should not enumerate registry");
10441086
},
1045-
},
1087+
}),
10461088
modelFilter: new Set(["google/gemini-3-pro-preview"]),
10471089
providerFilter: new Set(["google"]),
10481090
targetMatcher: matcher,
@@ -1058,7 +1100,7 @@ describe("resolveExplicitLiveModelCandidates", () => {
10581100
env: {},
10591101
});
10601102
const candidates = resolveExplicitLiveModelCandidates({
1061-
modelRegistry: {
1103+
modelRegistry: createGatewayLiveTestRegistry({
10621104
find(provider, modelId) {
10631105
expect(provider).toBe("openai");
10641106
expect(modelId).toBe("gpt-5.5");
@@ -1067,7 +1109,7 @@ describe("resolveExplicitLiveModelCandidates", () => {
10671109
getAll() {
10681110
throw new Error("explicit model lookup should not enumerate registry");
10691111
},
1070-
},
1112+
}),
10711113
modelFilter: new Set(["openai/gpt-5.5"]),
10721114
providerFilter: new Set(["openai"]),
10731115
targetMatcher: matcher,
@@ -1089,14 +1131,14 @@ describe("resolveExplicitLiveModelCandidates", () => {
10891131

10901132
expect(
10911133
resolveExplicitLiveModelCandidates({
1092-
modelRegistry: {
1134+
modelRegistry: createGatewayLiveTestRegistry({
10931135
find() {
10941136
throw new Error("ambiguous model-only lookup should not use direct find");
10951137
},
10961138
getAll() {
10971139
return [];
10981140
},
1099-
},
1141+
}),
11001142
modelFilter: new Set(["grok-4.3"]),
11011143
providerFilter: null,
11021144
targetMatcher: matcher,
@@ -1154,6 +1196,36 @@ describe("providerScopedModelRegistryProviders", () => {
11541196
).toEqual(["ollama"]);
11551197
});
11561198

1199+
it("filters prioritized small refs before dynamic lookup", () => {
1200+
expect(
1201+
filterGatewayLiveModelRefsByProvider(
1202+
listPrioritizedSmallLiveModelRefs(),
1203+
new Set(["ollama"]),
1204+
),
1205+
).toEqual([{ provider: "ollama", id: "gemma3:4b" }]);
1206+
});
1207+
1208+
it("does not count small models outside a provider-scoped gateway sweep", () => {
1209+
const matcher = createLiveTargetMatcher({
1210+
providerFilter: new Set(["ollama"]),
1211+
modelFilter: null,
1212+
env: {},
1213+
});
1214+
1215+
expect(
1216+
isWantedSmallGatewayLiveModel({
1217+
model: createGatewayLiveTestModel("openrouter", "qwen/qwen3.5-9b"),
1218+
targetMatcher: matcher,
1219+
}),
1220+
).toBe(false);
1221+
expect(
1222+
isWantedSmallGatewayLiveModel({
1223+
model: createGatewayLiveTestModel("ollama", "gemma3:4b"),
1224+
targetMatcher: matcher,
1225+
}),
1226+
).toBe(true);
1227+
});
1228+
11571229
it("uses explicit provider-qualified model refs without enumerating the full registry", () => {
11581230
expect(
11591231
providerScopedModelRegistryProviders({
@@ -2157,10 +2229,7 @@ type GatewayModelSuiteParams = {
21572229
providerOverrides?: Record<string, ModelProviderConfig>;
21582230
};
21592231

2160-
type LiveModelRegistry = {
2161-
find(provider: string, modelId: string): Model | null | undefined;
2162-
getAll(): Array<Model>;
2163-
};
2232+
type LiveModelRegistry = ModelRegistry;
21642233

21652234
function toGatewayLiveModel(params: {
21662235
provider: string;
@@ -2259,6 +2328,12 @@ function createStaticLiveModelRegistry(models: Array<Model>): LiveModelRegistry
22592328
getAll() {
22602329
return models;
22612330
},
2331+
getAvailable() {
2332+
return models;
2333+
},
2334+
hasConfiguredAuth() {
2335+
return true;
2336+
},
22622337
};
22632338
}
22642339

@@ -3512,7 +3587,10 @@ describeLive("gateway live (dev agent, profile keys)", () => {
35123587
workspaceDir,
35133588
env: process.env,
35143589
modelRegistry,
3515-
refs: listPrioritizedSmallLiveModelRefs(),
3590+
refs: filterGatewayLiveModelRefsByProvider(
3591+
listPrioritizedSmallLiveModelRefs(),
3592+
PROVIDERS,
3593+
),
35163594
}),
35173595
"[all-models] load dynamic small model refs",
35183596
);
@@ -3543,7 +3621,7 @@ describeLive("gateway live (dev agent, profile keys)", () => {
35433621
wanted = filter
35443622
? all.filter((m) => targetMatcher.matchesModel(m.provider, m.id))
35453623
: useSmall
3546-
? all.filter((m) => isSmallLiveModelRef({ provider: m.provider, id: m.id }))
3624+
? all.filter((m) => isWantedSmallGatewayLiveModel({ model: m, targetMatcher }))
35473625
: all.filter(
35483626
(m) =>
35493627
!shouldExcludeProviderFromDefaultHighSignalLiveSweep({

0 commit comments

Comments
 (0)