test: cap docker live model sweeps and harden timeouts

This commit is contained in:
Peter Steinberger
2026-02-25 02:48:25 +00:00
parent df9a474891
commit 7c59b78aee
4 changed files with 159 additions and 15 deletions

View File

@@ -55,6 +55,58 @@ function parseFilter(raw?: string): Set<string> | null {
return ids.length ? new Set(ids) : null;
}
function toInt(value: string | undefined, fallback: number): number {
const trimmed = value?.trim();
if (!trimmed) {
return fallback;
}
const parsed = Number.parseInt(trimmed, 10);
return Number.isFinite(parsed) ? parsed : fallback;
}
function capByProviderSpread<T>(
items: T[],
maxItems: number,
providerOf: (item: T) => string,
): T[] {
if (maxItems <= 0 || items.length <= maxItems) {
return items;
}
const providerOrder: string[] = [];
const grouped = new Map<string, T[]>();
for (const item of items) {
const provider = providerOf(item);
const bucket = grouped.get(provider);
if (bucket) {
bucket.push(item);
continue;
}
providerOrder.push(provider);
grouped.set(provider, [item]);
}
const selected: T[] = [];
while (selected.length < maxItems && grouped.size > 0) {
for (const provider of providerOrder) {
const bucket = grouped.get(provider);
if (!bucket || bucket.length === 0) {
continue;
}
const item = bucket.shift();
if (item) {
selected.push(item);
}
if (bucket.length === 0) {
grouped.delete(provider);
}
if (selected.length >= maxItems) {
break;
}
}
}
return selected;
}
function logProgress(message: string): void {
console.log(`[live] ${message}`);
}
@@ -1061,6 +1113,7 @@ describeLive("gateway live (dev agent, profile keys)", () => {
const useModern = !rawModels || rawModels === "modern" || rawModels === "all";
const useExplicit = Boolean(rawModels) && !useModern;
const filter = useExplicit ? parseFilter(rawModels) : null;
const maxModels = toInt(process.env.OPENCLAW_LIVE_GATEWAY_MAX_MODELS, 0);
const wanted = filter
? all.filter((m) => filter.has(`${m.provider}/${m.id}`))
: all.filter((m) => isModernModelRef({ provider: m.provider, id: m.id }));
@@ -1091,21 +1144,31 @@ describeLive("gateway live (dev agent, profile keys)", () => {
logProgress("[all-models] no API keys found; skipping");
return;
}
const selectedCandidates = capByProviderSpread(
candidates,
maxModels > 0 ? maxModels : candidates.length,
(model) => model.provider,
);
logProgress(`[all-models] selection=${useExplicit ? "explicit" : "modern"}`);
const imageCandidates = candidates.filter((m) => m.input?.includes("image"));
if (selectedCandidates.length < candidates.length) {
logProgress(
`[all-models] capped to ${selectedCandidates.length}/${candidates.length} via OPENCLAW_LIVE_GATEWAY_MAX_MODELS=${maxModels}`,
);
}
const imageCandidates = selectedCandidates.filter((m) => m.input?.includes("image"));
if (imageCandidates.length === 0) {
logProgress("[all-models] no image-capable models selected; image probe will be skipped");
}
await runGatewayModelSuite({
label: "all-models",
cfg,
candidates,
candidates: selectedCandidates,
extraToolProbes: true,
extraImageProbes: true,
thinkingLevel: THINKING_LEVEL,
});
const minimaxCandidates = candidates.filter((model) => model.provider === "minimax");
const minimaxCandidates = selectedCandidates.filter((model) => model.provider === "minimax");
if (minimaxCandidates.length === 0) {
logProgress("[minimax] no candidates with keys; skipping dual endpoint probes");
return;