fix(models): default non-finite catalog browse timeout

This commit is contained in:
Peter Steinberger
2026-05-28 23:01:41 -04:00
parent c237de552a
commit 01d9963e4e
2 changed files with 37 additions and 2 deletions

View File

@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { loadModelCatalogForBrowse } from "./model-catalog-browse.js";
import type { ModelCatalogEntry } from "./model-catalog.types.js";
@@ -23,6 +23,10 @@ function config(params: { providerWildcard?: boolean } = {}): OpenClawConfig {
}
describe("loadModelCatalogForBrowse", () => {
afterEach(() => {
vi.useRealTimers();
});
it("uses the read-only catalog for default browse views", async () => {
const loadCatalog = vi.fn(async ({ readOnly }: { readOnly: boolean }) =>
readOnly ? readOnlyCatalog : fullCatalog,
@@ -79,4 +83,27 @@ describe("loadModelCatalogForBrowse", () => {
expect(onTimeout).toHaveBeenCalledExactlyOnceWith(5);
await new Promise((resolve) => setTimeout(resolve, 15));
});
it("uses the default timeout when timeoutMs is non-finite", async () => {
vi.useFakeTimers();
const onTimeout = vi.fn();
const loadCatalog = vi.fn(
() =>
new Promise<ModelCatalogEntry[]>((resolve) => {
setTimeout(() => resolve(readOnlyCatalog), 5);
}),
);
const resultPromise = loadModelCatalogForBrowse({
cfg: config(),
loadCatalog,
timeoutMs: Number.NaN,
onTimeout,
});
await vi.advanceTimersByTimeAsync(5);
await expect(resultPromise).resolves.toBe(readOnlyCatalog);
expect(onTimeout).not.toHaveBeenCalled();
});
});

View File

@@ -1,4 +1,5 @@
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { parseFiniteNumber } from "../shared/number-coercion.js";
import type { ModelCatalogEntry } from "./model-catalog.types.js";
import { parseConfiguredModelVisibilityEntries } from "./model-selection-shared.js";
@@ -6,6 +7,13 @@ export const DEFAULT_MODEL_CATALOG_BROWSE_TIMEOUT_MS = 750;
export type ModelCatalogBrowseView = "default" | "configured" | "all";
function resolveModelCatalogBrowseTimeoutMs(value: number | undefined): number {
return Math.max(
1,
Math.floor(parseFiniteNumber(value) ?? DEFAULT_MODEL_CATALOG_BROWSE_TIMEOUT_MS),
);
}
export async function loadModelCatalogForBrowse(params: {
cfg: OpenClawConfig;
view?: ModelCatalogBrowseView;
@@ -22,7 +30,7 @@ export async function loadModelCatalogForBrowse(params: {
}
let timeout: NodeJS.Timeout | undefined;
const timeoutMs = params.timeoutMs ?? DEFAULT_MODEL_CATALOG_BROWSE_TIMEOUT_MS;
const timeoutMs = resolveModelCatalogBrowseTimeoutMs(params.timeoutMs);
const timedOut = Symbol("model-catalog-browse-timeout");
const catalogPromise = params.loadCatalog({ readOnly: true });
const timeoutPromise = new Promise<typeof timedOut>((resolve) => {