refactor(agents): privatize models config test seams (#108275)

* refactor(agents): privatize models config test seams

* chore(deadcode): shrink models config export baseline
This commit is contained in:
Peter Steinberger
2026-07-15 04:27:39 -07:00
committed by GitHub
parent d223409c88
commit 20d6ddc4c7
19 changed files with 170 additions and 43 deletions
-8
View File
@@ -48,14 +48,6 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/agents/mcp-ui-resource.ts: testing",
"src/agents/media-generation-task-status-shared.ts: resetRecentMediaGenerationDuplicateGuardsForTests",
"src/agents/model-fallback.ts: testing",
"src/agents/models-config-state.ts: resetModelsJsonReadyCacheForTest",
"src/agents/models-config.plan.ts: planOpenClawModelsJsonWithDeps",
"src/agents/models-config.plan.ts: resolveProvidersForModelsJsonWithDeps",
"src/agents/models-config.providers.implicit.ts: resolvePluginMetadataProviderOwnersForTest",
"src/agents/models-config.providers.implicit.ts: resolveProviderDiscoveryFilterForTest",
"src/agents/models-config.ts: ensureModelsFileModeForModelsJson",
"src/agents/models-config.ts: resetModelsJsonReadyCacheForTest",
"src/agents/models-config.ts: writeModelsFileAtomicForModelsJson",
"src/agents/modes/interactive/theme/theme.ts: setTheme",
"src/agents/openai-completions-compat.ts: resolveOpenAICompletionsCompatDefaults",
"src/agents/openai-transport-stream.ts: testing",
+2 -4
View File
@@ -5,10 +5,8 @@ import { tmpdir } from "node:os";
import path from "node:path";
import { monitorEventLoopDelay, performance } from "node:perf_hooks";
import { resolveModelAsync } from "../../src/agents/embedded-agent-runner/model.js";
import {
ensureOpenClawModelsJson,
resetModelsJsonReadyCacheForTest,
} from "../../src/agents/models-config.js";
import { resetModelsJsonReadyCacheForTest } from "../../src/agents/models-config-state.test-support.js";
import { ensureOpenClawModelsJson } from "../../src/agents/models-config.js";
import type { OpenClawConfig } from "../../src/config/types.openclaw.js";
import {
Issue78851CliArgumentError,
@@ -0,0 +1,7 @@
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
import { MODELS_JSON_STATE } from "./models-config-state.js";
export function resetModelsJsonReadyCacheForTest(): void {
MODELS_JSON_STATE.writeQueue = new KeyedAsyncQueue();
MODELS_JSON_STATE.readyCache.clear();
}
-6
View File
@@ -31,9 +31,3 @@ export const MODELS_JSON_STATE = (() => {
}
return globalState[MODELS_JSON_STATE_KEY];
})();
/** Clear models.json write/ready caches for tests. */
export function resetModelsJsonReadyCacheForTest(): void {
MODELS_JSON_STATE.writeQueue = new KeyedAsyncQueue();
MODELS_JSON_STATE.readyCache.clear();
}
@@ -13,7 +13,7 @@ import { unsetEnv, withTempEnv } from "./models-config.e2e-harness.js";
import {
planOpenClawModelsJsonWithDeps,
resolveProvidersForModelsJsonWithDeps,
} from "./models-config.plan.js";
} from "./models-config.plan.test-support.js";
import type { ProviderConfig } from "./models-config.providers.secrets.js";
import { encodePluginModelCatalogRelativePath } from "./plugin-model-catalog.js";
+1 -1
View File
@@ -7,7 +7,7 @@ import { clearConfigCache, clearRuntimeConfigSnapshot } from "../config/config.j
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { withTempHome as withTempHomeBase } from "../plugin-sdk/test-helpers/temp-home.js";
import { resetPluginLoaderTestStateForTest } from "../plugins/loader.test-fixtures.js";
import { resetModelsJsonReadyCacheForTest } from "./models-config-state.js";
import { resetModelsJsonReadyCacheForTest } from "./models-config-state.test-support.js";
/** Runs a models-config test with an isolated temp HOME and no session cleanup. */
export function withModelsTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
+1 -1
View File
@@ -6,7 +6,7 @@ import { cleanupTempDirs, makeTempDir } from "../../test/helpers/temp-dir.js";
import {
ensureModelsFileModeForModelsJson,
writeModelsFileAtomicForModelsJson,
} from "./models-config.js";
} from "./models-config.test-support.js";
const tempDirs = new Set<string>();
@@ -0,0 +1,57 @@
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import "./models-config.plan.js";
import type { ProviderConfig } from "./models-config.providers.secrets.js";
type ResolveImplicitProvidersForModelsJson = (params: {
agentDir: string;
config: OpenClawConfig;
env: NodeJS.ProcessEnv;
workspaceDir?: string;
explicitProviders: Record<string, ProviderConfig>;
pluginMetadataSnapshot?: Pick<PluginMetadataSnapshot, "index" | "manifestRegistry" | "owners">;
providerDiscoveryProviderIds?: readonly string[];
providerDiscoveryTimeoutMs?: number;
providerDiscoveryEntriesOnly?: boolean;
}) => Promise<Record<string, ProviderConfig>>;
type PlanParams = Parameters<typeof import("./models-config.plan.js").planOpenClawModelsJson>[0];
type PlanResult = Awaited<
ReturnType<typeof import("./models-config.plan.js").planOpenClawModelsJson>
>;
type ResolveProvidersParams = {
cfg: OpenClawConfig;
agentDir: string;
env: NodeJS.ProcessEnv;
workspaceDir?: string;
pluginMetadataSnapshot?: Pick<PluginMetadataSnapshot, "index" | "manifestRegistry" | "owners">;
providerDiscoveryProviderIds?: readonly string[];
providerDiscoveryTimeoutMs?: number;
providerDiscoveryEntriesOnly?: boolean;
};
type PlanDeps = { resolveImplicitProviders?: ResolveImplicitProvidersForModelsJson };
type ModelsConfigPlanTestApi = {
planOpenClawModelsJsonWithDeps(params: PlanParams, deps?: PlanDeps): Promise<PlanResult>;
resolveProvidersForModelsJsonWithDeps(
params: ResolveProvidersParams,
deps?: PlanDeps,
): Promise<Record<string, ProviderConfig>>;
};
function getTestApi(): ModelsConfigPlanTestApi {
return (globalThis as Record<PropertyKey, unknown>)[
Symbol.for("openclaw.modelsConfigPlanTestApi")
] as ModelsConfigPlanTestApi;
}
export const planOpenClawModelsJsonWithDeps = async (
params: PlanParams,
deps?: PlanDeps,
): Promise<PlanResult> => await getTestApi().planOpenClawModelsJsonWithDeps(params, deps);
export const resolveProvidersForModelsJsonWithDeps = async (
params: ResolveProvidersParams,
deps?: PlanDeps,
): Promise<Record<string, ProviderConfig>> =>
await getTestApi().resolveProvidersForModelsJsonWithDeps(params, deps);
+9 -2
View File
@@ -92,7 +92,7 @@ function buildPluginCatalogWrites(
}
/** Resolves providers for models.json with injectable implicit-provider discovery. */
export async function resolveProvidersForModelsJsonWithDeps(
async function resolveProvidersForModelsJsonWithDeps(
params: {
cfg: OpenClawConfig;
agentDir: string;
@@ -200,7 +200,7 @@ function filterWritableProviders(
}
/** Plans root and plugin-owned model catalog writes with injectable provider discovery. */
export async function planOpenClawModelsJsonWithDeps(
async function planOpenClawModelsJsonWithDeps(
params: {
cfg: OpenClawConfig;
sourceConfigForSecrets?: OpenClawConfig;
@@ -316,3 +316,10 @@ export async function planOpenClawModelsJson(
): Promise<ModelsJsonPlan> {
return planOpenClawModelsJsonWithDeps(params);
}
if (process.env.VITEST || process.env.NODE_ENV === "test") {
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.modelsConfigPlanTestApi")] = {
planOpenClawModelsJsonWithDeps,
resolveProvidersForModelsJsonWithDeps,
};
}
@@ -0,0 +1,37 @@
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import "./models-config.providers.implicit.js";
type ResolveProviderDiscoveryFilterParams = {
config?: OpenClawConfig;
workspaceDir?: string;
env: NodeJS.ProcessEnv;
resolveOwners?: (provider: string) => readonly string[] | undefined;
providerIds?: readonly string[];
};
type ModelsConfigImplicitProvidersTestApi = {
resolveProviderDiscoveryFilterForTest(
params: ResolveProviderDiscoveryFilterParams,
): string[] | undefined;
resolvePluginMetadataProviderOwnersForTest(
pluginMetadataSnapshot: Pick<PluginMetadataSnapshot, "owners"> | undefined,
provider: string,
): readonly string[] | undefined;
};
function getTestApi(): ModelsConfigImplicitProvidersTestApi {
return (globalThis as Record<PropertyKey, unknown>)[
Symbol.for("openclaw.modelsConfigImplicitProvidersTestApi")
] as ModelsConfigImplicitProvidersTestApi;
}
export const resolveProviderDiscoveryFilterForTest = (
params: ResolveProviderDiscoveryFilterParams,
): string[] | undefined => getTestApi().resolveProviderDiscoveryFilterForTest(params);
export const resolvePluginMetadataProviderOwnersForTest = (
pluginMetadataSnapshot: Pick<PluginMetadataSnapshot, "owners"> | undefined,
provider: string,
): readonly string[] | undefined =>
getTestApi().resolvePluginMetadataProviderOwnersForTest(pluginMetadataSnapshot, provider);
+11 -2
View File
@@ -235,7 +235,7 @@ function appendNormalizedPluginMetadataOwners(
}
/** Resolve the plugin discovery filter used by implicit provider discovery tests. */
export function resolveProviderDiscoveryFilterForTest(params: {
function resolveProviderDiscoveryFilterForTest(params: {
config?: OpenClawConfig;
workspaceDir?: string;
env: NodeJS.ProcessEnv;
@@ -246,13 +246,22 @@ export function resolveProviderDiscoveryFilterForTest(params: {
}
/** Resolve provider owner plugin IDs from a preloaded metadata snapshot for tests. */
export function resolvePluginMetadataProviderOwnersForTest(
function resolvePluginMetadataProviderOwnersForTest(
pluginMetadataSnapshot: Pick<PluginMetadataSnapshot, "owners"> | undefined,
provider: string,
): readonly string[] | undefined {
return resolvePluginMetadataProviderOwners(pluginMetadataSnapshot, provider);
}
if (process.env.VITEST || process.env.NODE_ENV === "test") {
(globalThis as Record<PropertyKey, unknown>)[
Symbol.for("openclaw.modelsConfigImplicitProvidersTestApi")
] = {
resolvePluginMetadataProviderOwnersForTest,
resolveProviderDiscoveryFilterForTest,
};
}
function mergeImplicitProviderSet(
target: Record<string, ProviderConfig>,
additions: Record<string, ProviderConfig> | undefined,
@@ -4,7 +4,7 @@ import type { PluginMetadataSnapshotOwnerMaps } from "../plugins/plugin-metadata
import {
resolvePluginMetadataProviderOwnersForTest,
resolveProviderDiscoveryFilterForTest,
} from "./models-config.providers.implicit.js";
} from "./models-config.providers.implicit.test-support.js";
function liveFilterEnv(overrides: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
// VITEST enables the live-filter parsing path without requiring real live creds.
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.js";
import { resolveProvidersForModelsJsonWithDeps } from "./models-config.plan.js";
import { resolveProvidersForModelsJsonWithDeps } from "./models-config.plan.test-support.js";
import type { ProviderConfig } from "./models-config.providers.secrets.js";
function createExplicitProvider(): ProviderConfig {
@@ -49,8 +49,8 @@ let clearConfigCache: typeof import("../config/io.js").clearConfigCache;
let clearRuntimeConfigSnapshot: typeof import("../config/io.js").clearRuntimeConfigSnapshot;
let setRuntimeConfigSnapshot: typeof import("../config/io.js").setRuntimeConfigSnapshot;
let ensureOpenClawModelsJson: typeof import("./models-config.js").ensureOpenClawModelsJson;
let resetModelsJsonReadyCacheForTest: typeof import("./models-config.js").resetModelsJsonReadyCacheForTest;
let planOpenClawModelsJsonWithDeps: typeof import("./models-config.plan.js").planOpenClawModelsJsonWithDeps;
let resetModelsJsonReadyCacheForTest: typeof import("./models-config-state.test-support.js").resetModelsJsonReadyCacheForTest;
let planOpenClawModelsJsonWithDeps: typeof import("./models-config.plan.test-support.js").planOpenClawModelsJsonWithDeps;
let readGeneratedModelsJson: typeof import("./models-config.test-utils.js").readGeneratedModelsJson;
const fixtureSuite = createFixtureSuite("openclaw-models-runtime-source-");
@@ -58,9 +58,9 @@ beforeAll(async () => {
await fixtureSuite.setup();
({ clearConfigCache, clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot } =
await import("../config/io.js"));
({ ensureOpenClawModelsJson, resetModelsJsonReadyCacheForTest } =
await import("./models-config.js"));
({ planOpenClawModelsJsonWithDeps } = await import("./models-config.plan.js"));
({ ensureOpenClawModelsJson } = await import("./models-config.js"));
({ resetModelsJsonReadyCacheForTest } = await import("./models-config-state.test-support.js"));
({ planOpenClawModelsJsonWithDeps } = await import("./models-config.plan.test-support.js"));
({ readGeneratedModelsJson } = await import("./models-config.test-utils.js"));
});
@@ -97,7 +97,7 @@ let clearConfigCache: typeof import("../config/config.js").clearConfigCache;
let clearRuntimeConfigSnapshot: typeof import("../config/config.js").clearRuntimeConfigSnapshot;
let clearRuntimeAuthProfileStoreSnapshots: typeof import("./auth-profiles/store.js").clearRuntimeAuthProfileStoreSnapshots;
let ensureOpenClawModelsJson: typeof import("./models-config.js").ensureOpenClawModelsJson;
let resetModelsJsonReadyCacheForTest: typeof import("./models-config.js").resetModelsJsonReadyCacheForTest;
let resetModelsJsonReadyCacheForTest: typeof import("./models-config-state.test-support.js").resetModelsJsonReadyCacheForTest;
type ParsedProviderConfig = {
baseUrl?: string;
@@ -163,8 +163,8 @@ describe("models-config", () => {
vi.resetModules();
({ clearConfigCache, clearRuntimeConfigSnapshot } = await import("../config/config.js"));
({ clearRuntimeAuthProfileStoreSnapshots } = await import("./auth-profiles/store.js"));
({ ensureOpenClawModelsJson, resetModelsJsonReadyCacheForTest } =
await import("./models-config.js"));
({ ensureOpenClawModelsJson } = await import("./models-config.js"));
({ resetModelsJsonReadyCacheForTest } = await import("./models-config-state.test-support.js"));
});
beforeEach(() => {
+20
View File
@@ -0,0 +1,20 @@
import "./models-config.js";
type ModelsConfigTestApi = {
ensureModelsFileModeForModelsJson(pathname: string): Promise<void>;
writeModelsFileAtomicForModelsJson(targetPath: string, contents: string): Promise<void>;
};
function getTestApi(): ModelsConfigTestApi {
return (globalThis as Record<PropertyKey, unknown>)[
Symbol.for("openclaw.modelsConfigTestApi")
] as ModelsConfigTestApi;
}
export const ensureModelsFileModeForModelsJson = async (pathname: string): Promise<void> =>
await getTestApi().ensureModelsFileModeForModelsJson(pathname);
export const writeModelsFileAtomicForModelsJson = async (
targetPath: string,
contents: string,
): Promise<void> => await getTestApi().writeModelsFileAtomicForModelsJson(targetPath, contents);
+9 -4
View File
@@ -39,8 +39,6 @@ import {
} from "./plugin-model-catalog.js";
import { stableStringify } from "./stable-stringify.js";
export { resetModelsJsonReadyCacheForTest } from "./models-config-state.js";
type PreparedOpenClawModelsJsonSource = ModelsJsonReadyResult & {
fingerprint: string;
workspaceDir?: string;
@@ -141,20 +139,27 @@ async function readExistingModelsFile(pathname: string): Promise<{
}
/** Best-effort chmod for generated models.json and plugin catalog files. */
export async function ensureModelsFileModeForModelsJson(pathname: string): Promise<void> {
async function ensureModelsFileModeForModelsJson(pathname: string): Promise<void> {
await fs.chmod(pathname, 0o600).catch(() => {
// best-effort
});
}
/** Atomic private-file-store write used by models.json generation. */
export async function writeModelsFileAtomicForModelsJson(
async function writeModelsFileAtomicForModelsJson(
targetPath: string,
contents: string,
): Promise<void> {
await privateFileStore(path.dirname(targetPath)).writeText(path.basename(targetPath), contents);
}
if (process.env.VITEST || process.env.NODE_ENV === "test") {
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.modelsConfigTestApi")] = {
ensureModelsFileModeForModelsJson,
writeModelsFileAtomicForModelsJson,
};
}
async function isGeneratedPluginCatalogFile(targetPath: string): Promise<boolean> {
return (await readGeneratedPluginCatalog(targetPath)) !== undefined;
}
@@ -1,6 +1,7 @@
// Verifies GitHub Copilot profile token fallback and implicit provider planning.
import { describe, expect, it, vi } from "vitest";
import { planOpenClawModelsJson, planOpenClawModelsJsonWithDeps } from "./models-config.plan.js";
import { planOpenClawModelsJson } from "./models-config.plan.js";
import { planOpenClawModelsJsonWithDeps } from "./models-config.plan.test-support.js";
import type { ProviderConfig } from "./models-config.providers.secrets.js";
import { createProviderAuthResolver } from "./models-config.providers.secrets.js";
+3 -3
View File
@@ -31,7 +31,7 @@ type WorkerCleanupHelpers = {
drainSessionWriteLockStateForTest: typeof import("../src/agents/session-write-lock.js").drainSessionWriteLockStateForTest;
resetContextWindowCacheForTest: typeof import("../src/agents/context-runtime-state.js").resetContextWindowCacheForTest;
resetFileLockStateForTest: typeof import("../src/infra/file-lock.js").resetFileLockStateForTest;
resetModelsJsonReadyCacheForTest: typeof import("../src/agents/models-config-state.js").resetModelsJsonReadyCacheForTest;
resetModelsJsonReadyCacheForTest: typeof import("../src/agents/models-config-state.test-support.js").resetModelsJsonReadyCacheForTest;
resetSessionWriteLockStateForTest: typeof import("../src/agents/session-write-lock.js").resetSessionWriteLockStateForTest;
};
@@ -73,8 +73,8 @@ function loadWorkerCleanupHelpers(): Promise<WorkerCleanupHelpers> {
vi.importActual<typeof import("../src/agents/context-runtime-state.js")>(
"../src/agents/context-runtime-state.js",
),
vi.importActual<typeof import("../src/agents/models-config-state.js")>(
"../src/agents/models-config-state.js",
vi.importActual<typeof import("../src/agents/models-config-state.test-support.js")>(
"../src/agents/models-config-state.test-support.js",
),
vi.importActual<typeof import("../src/agents/session-write-lock.js")>(
"../src/agents/session-write-lock.js",