refactor: remove core test extension leaks

This commit is contained in:
Peter Steinberger
2026-04-05 19:54:43 +01:00
parent 8cd9007ec1
commit bcc0e3de2e
20 changed files with 149 additions and 41 deletions

View File

@@ -9,6 +9,7 @@ export {
export * from "./src/account-selection.js";
export * from "./src/env-vars.js";
export * from "./src/storage-paths.js";
export { ensureMatrixSdkInstalled, isMatrixSdkAvailable } from "./src/matrix/deps.js";
export {
assertHttpUrlTargetsPrivateNetwork,
closeDispatcher,

View File

@@ -1,8 +1,8 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { parseTelegramTopicConversation } from "../../extensions/telegram/api.js";
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
import type { ChannelConfiguredBindingProvider, ChannelPlugin } from "../channels/plugins/types.js";
import type { OpenClawConfig } from "../config/config.js";
import { parseTelegramTopicConversation } from "../plugin-sdk/telegram.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { createChannelTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js";
import { buildConfiguredAcpSessionKey } from "./persistent-bindings.types.js";

View File

@@ -5,7 +5,7 @@ import {
MINIMAX_DEFAULT_MODEL_ID,
MINIMAX_DEFAULT_MODEL_REF,
MINIMAX_TEXT_MODEL_REFS,
} from "../../extensions/minimax/api.js";
} from "../plugin-sdk/minimax.js";
const repoRoot = path.resolve(import.meta.dirname, "../..");
const testingDoc = fs.readFileSync(path.join(repoRoot, "docs/help/testing.md"), "utf8");

View File

@@ -8,7 +8,7 @@ import {
buildAssistantMessage,
parseNdjsonStream,
resolveOllamaBaseUrlForRun,
} from "../../extensions/ollama/runtime-api.js";
} from "../plugin-sdk/ollama-runtime.js";
import {
__testing as extraParamsTesting,
applyExtraParamsToAgent,

View File

@@ -1,7 +1,6 @@
import type { StreamFn } from "@mariozechner/pi-agent-core";
import type { Context, Model, SimpleStreamOptions } from "@mariozechner/pi-ai";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createConfiguredOllamaCompatNumCtxWrapper } from "../../extensions/ollama/runtime-api.js";
import {
createAnthropicBetaHeadersWrapper,
createAnthropicFastModeWrapper,
@@ -10,6 +9,7 @@ import {
resolveAnthropicFastMode,
resolveAnthropicServiceTier,
} from "../../test/helpers/providers/anthropic-contract.js";
import { createConfiguredOllamaCompatNumCtxWrapper } from "../plugin-sdk/ollama-runtime.js";
import { __testing as extraParamsTesting } from "./pi-embedded-runner/extra-params.js";
import {
createOpenRouterSystemCacheWrapper,

View File

@@ -1,12 +1,12 @@
import { streamSimple } from "@mariozechner/pi-ai";
import { describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../../config/config.js";
import {
isOllamaCompatProvider,
resolveOllamaCompatNumCtxEnabled,
shouldInjectOllamaCompatNumCtx,
wrapOllamaCompatNumCtx,
} from "../../../../extensions/ollama/runtime-api.js";
import type { OpenClawConfig } from "../../../config/config.js";
} from "../../../plugin-sdk/ollama-runtime.js";
import { appendBootstrapPromptWarning } from "../../bootstrap-budget.js";
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../system-prompt-cache-boundary.js";
import { buildAgentSystemPrompt } from "../../system-prompt.js";

View File

@@ -2,8 +2,8 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { applyXaiModelCompat } from "../../extensions/xai/api.js";
import {
applyXaiModelCompat,
findUnsupportedSchemaKeywords,
GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS,
XAI_UNSUPPORTED_SCHEMA_KEYWORDS,

View File

@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import {
HTML_ENTITY_TOOL_CALL_ARGUMENTS_ENCODING,
XAI_TOOL_SCHEMA_PROFILE,
} from "../../extensions/xai/api.js";
} from "../plugin-sdk/provider-tools.js";
import { __testing } from "./pi-tools.js";
import type { AnyAgentTool } from "./pi-tools.types.js";

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { evaluateZaloGroupAccess } from "../../../../extensions/zalo/test-api.js";
import { evaluateZaloGroupAccess } from "../../../plugin-sdk/zalo-setup.js";
function expectAllowedZaloGroupAccess(params: Parameters<typeof evaluateZaloGroupAccess>[0]) {
expect(evaluateZaloGroupAccess(params)).toMatchObject({

View File

@@ -1,6 +1,9 @@
import type { OpenClawConfig } from "../../../config/config.js";
import { mergeMissing } from "../../../config/legacy.shared.js";
import { BUNDLED_WEB_SEARCH_PROVIDER_PLUGIN_IDS } from "../../../plugins/bundled-capability-metadata.js";
import {
loadPluginManifestRegistry,
resolveManifestContractOwnerPluginId,
} from "../../../plugins/manifest-registry.js";
type JsonRecord = Record<string, unknown>;
@@ -9,12 +12,11 @@ const MODERN_SCOPED_WEB_SEARCH_KEYS = new Set(["openaiCodex"]);
// Tavily only ever used the plugin-owned config path, so there is no legacy
// `tools.web.search.tavily.*` shape to migrate.
const NON_MIGRATED_LEGACY_WEB_SEARCH_PROVIDER_IDS = new Set(["tavily"]);
const LEGACY_WEB_SEARCH_PROVIDER_PLUGIN_IDS = Object.fromEntries(
Object.entries(BUNDLED_WEB_SEARCH_PROVIDER_PLUGIN_IDS).filter(
([providerId]) => !NON_MIGRATED_LEGACY_WEB_SEARCH_PROVIDER_IDS.has(providerId),
),
);
const LEGACY_WEB_SEARCH_PROVIDER_IDS = Object.keys(LEGACY_WEB_SEARCH_PROVIDER_PLUGIN_IDS);
const LEGACY_WEB_SEARCH_PROVIDER_IDS = loadPluginManifestRegistry({ cache: true })
.plugins.filter((plugin) => plugin.origin === "bundled")
.flatMap((plugin) => plugin.contracts?.webSearchProviders ?? [])
.filter((providerId) => !NON_MIGRATED_LEGACY_WEB_SEARCH_PROVIDER_IDS.has(providerId))
.toSorted((left, right) => left.localeCompare(right));
const LEGACY_WEB_SEARCH_PROVIDER_ID_SET = new Set(LEGACY_WEB_SEARCH_PROVIDER_IDS);
const LEGACY_GLOBAL_WEB_SEARCH_PROVIDER_ID = "brave";
@@ -84,8 +86,11 @@ function resolveLegacyGlobalWebSearchMigration(search: JsonRecord): {
return null;
}
const pluginId =
LEGACY_WEB_SEARCH_PROVIDER_PLUGIN_IDS[LEGACY_GLOBAL_WEB_SEARCH_PROVIDER_ID] ??
LEGACY_GLOBAL_WEB_SEARCH_PROVIDER_ID;
resolveManifestContractOwnerPluginId({
contract: "webSearchProviders",
value: LEGACY_GLOBAL_WEB_SEARCH_PROVIDER_ID,
origin: "bundled",
}) ?? LEGACY_GLOBAL_WEB_SEARCH_PROVIDER_ID;
return {
pluginId,
payload,
@@ -233,7 +238,11 @@ function normalizeLegacyWebSearchConfigRecord<T extends JsonRecord>(
if (!scoped || Object.keys(scoped).length === 0) {
continue;
}
const pluginId = LEGACY_WEB_SEARCH_PROVIDER_PLUGIN_IDS[providerId];
const pluginId = resolveManifestContractOwnerPluginId({
contract: "webSearchProviders",
value: providerId,
origin: "bundled",
});
if (!pluginId) {
continue;
}

View File

@@ -604,7 +604,7 @@ vi.mock("../plugins/manifest-registry.js", async () => {
};
});
vi.mock("../../extensions/matrix/src/matrix/deps.js", () => ({
vi.mock("../plugin-sdk/matrix-deps.js", () => ({
ensureMatrixSdkInstalled: vi.fn(async () => {}),
isMatrixSdkAvailable: vi.fn(() => true),
}));

View File

@@ -5,7 +5,6 @@ import os from "node:os";
import path from "node:path";
import type { Api, Model } from "@mariozechner/pi-ai";
import { describe, expect, it } from "vitest";
import { normalizeGoogleModelId } from "../../extensions/google/api.js";
import { resolveOpenClawAgentDir } from "../agents/agent-paths.js";
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
import {
@@ -29,6 +28,7 @@ import { discoverAuthStorage, discoverModels } from "../agents/pi-model-discover
import { clearRuntimeConfigSnapshot, loadConfig } from "../config/config.js";
import type { ModelsConfig, OpenClawConfig, ModelProviderConfig } from "../config/types.js";
import { isTruthyEnvValue } from "../infra/env.js";
import { normalizeGoogleModelId } from "../plugin-sdk/google-model-id.js";
import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
import { stripAssistantInternalScaffolding } from "../shared/text/assistant-visible-text.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";

View File

@@ -76,7 +76,7 @@ vi.mock("../../config/sessions/paths.js", () => ({
resolveSessionTranscriptsDirForAgent: mocks.resolveSessionTranscriptsDirForAgent,
}));
vi.mock("../../../extensions/browser/runtime-api.js", () => ({
vi.mock("../../plugin-sdk/browser-maintenance.js", () => ({
movePathToTrash: mocks.movePathToTrash,
}));

View File

@@ -182,16 +182,6 @@ vi.mock("../acp/control-plane/manager.js", () => ({
}),
}));
vi.mock("../../extensions/browser/runtime-api.js", async () => {
const actual = await vi.importActual<typeof import("../../extensions/browser/runtime-api.js")>(
"../../extensions/browser/runtime-api.js",
);
return {
...actual,
closeTrackedBrowserTabsForSessions: browserSessionTabMocks.closeTrackedBrowserTabsForSessions,
};
});
vi.mock("../plugin-sdk/browser-maintenance.js", () => ({
closeTrackedBrowserTabsForSessions: browserSessionTabMocks.closeTrackedBrowserTabsForSessions,
movePathToTrash: vi.fn(async () => {}),

View File

@@ -0,0 +1,15 @@
// Manual facade. Keep loader boundary explicit.
type FacadeModule = typeof import("@openclaw/matrix/runtime-api.js");
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
function loadFacadeModule(): FacadeModule {
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
dirName: "matrix",
artifactBasename: "runtime-api.js",
});
}
export const ensureMatrixSdkInstalled: FacadeModule["ensureMatrixSdkInstalled"] = ((...args) =>
loadFacadeModule().ensureMatrixSdkInstalled(...args)) as FacadeModule["ensureMatrixSdkInstalled"];
export const isMatrixSdkAvailable: FacadeModule["isMatrixSdkAvailable"] = ((...args) =>
loadFacadeModule().isMatrixSdkAvailable(...args)) as FacadeModule["isMatrixSdkAvailable"];

26
src/plugin-sdk/minimax.ts Normal file
View File

@@ -0,0 +1,26 @@
// Manual facade. Keep loader boundary explicit.
type FacadeModule = {
MINIMAX_DEFAULT_MODEL_ID: string;
MINIMAX_DEFAULT_MODEL_REF: string;
MINIMAX_TEXT_MODEL_REFS: readonly string[];
};
import {
createLazyFacadeArrayValue,
loadBundledPluginPublicSurfaceModuleSync,
} from "./facade-runtime.js";
function loadFacadeModule(): FacadeModule {
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
dirName: "minimax",
artifactBasename: "api.js",
});
}
export const MINIMAX_DEFAULT_MODEL_ID: FacadeModule["MINIMAX_DEFAULT_MODEL_ID"] =
loadFacadeModule().MINIMAX_DEFAULT_MODEL_ID;
export const MINIMAX_DEFAULT_MODEL_REF: FacadeModule["MINIMAX_DEFAULT_MODEL_REF"] =
loadFacadeModule().MINIMAX_DEFAULT_MODEL_REF;
export const MINIMAX_TEXT_MODEL_REFS: FacadeModule["MINIMAX_TEXT_MODEL_REFS"] =
createLazyFacadeArrayValue(
() => loadFacadeModule().MINIMAX_TEXT_MODEL_REFS as unknown as readonly unknown[],
) as FacadeModule["MINIMAX_TEXT_MODEL_REFS"];

View File

@@ -11,6 +11,30 @@ function loadFacadeModule(): FacadeModule {
export type OllamaEmbeddingClient = import("@openclaw/ollama/runtime-api.js").OllamaEmbeddingClient;
export const DEFAULT_OLLAMA_EMBEDDING_MODEL: FacadeModule["DEFAULT_OLLAMA_EMBEDDING_MODEL"] =
loadFacadeModule().DEFAULT_OLLAMA_EMBEDDING_MODEL;
export const buildAssistantMessage: FacadeModule["buildAssistantMessage"] = ((...args) =>
loadFacadeModule().buildAssistantMessage(...args)) as FacadeModule["buildAssistantMessage"];
export const buildOllamaChatRequest: FacadeModule["buildOllamaChatRequest"] = ((...args) =>
loadFacadeModule().buildOllamaChatRequest(...args)) as FacadeModule["buildOllamaChatRequest"];
export const convertToOllamaMessages: FacadeModule["convertToOllamaMessages"] = ((...args) =>
loadFacadeModule().convertToOllamaMessages(...args)) as FacadeModule["convertToOllamaMessages"];
export const createConfiguredOllamaCompatNumCtxWrapper: FacadeModule["createConfiguredOllamaCompatNumCtxWrapper"] =
((...args) =>
loadFacadeModule().createConfiguredOllamaCompatNumCtxWrapper(
...args,
)) as FacadeModule["createConfiguredOllamaCompatNumCtxWrapper"];
export const createConfiguredOllamaCompatStreamWrapper: FacadeModule["createConfiguredOllamaCompatStreamWrapper"] =
((...args) =>
loadFacadeModule().createConfiguredOllamaCompatStreamWrapper(
...args,
)) as FacadeModule["createConfiguredOllamaCompatStreamWrapper"];
export const createConfiguredOllamaStreamFn: FacadeModule["createConfiguredOllamaStreamFn"] = ((
...args
) =>
loadFacadeModule().createConfiguredOllamaStreamFn(
...args,
)) as FacadeModule["createConfiguredOllamaStreamFn"];
export const createOllamaStreamFn: FacadeModule["createOllamaStreamFn"] = ((...args) =>
loadFacadeModule().createOllamaStreamFn(...args)) as FacadeModule["createOllamaStreamFn"];
export const createOllamaEmbeddingProvider: FacadeModule["createOllamaEmbeddingProvider"] = ((
...args
@@ -32,5 +56,11 @@ export const shouldInjectOllamaCompatNumCtx: FacadeModule["shouldInjectOllamaCom
loadFacadeModule().shouldInjectOllamaCompatNumCtx(
...args,
)) as FacadeModule["shouldInjectOllamaCompatNumCtx"];
export const parseNdjsonStream: FacadeModule["parseNdjsonStream"] = ((...args) =>
loadFacadeModule().parseNdjsonStream(...args)) as FacadeModule["parseNdjsonStream"];
export const resolveOllamaBaseUrlForRun: FacadeModule["resolveOllamaBaseUrlForRun"] = ((...args) =>
loadFacadeModule().resolveOllamaBaseUrlForRun(
...args,
)) as FacadeModule["resolveOllamaBaseUrlForRun"];
export const wrapOllamaCompatNumCtx: FacadeModule["wrapOllamaCompatNumCtx"] = ((...args) =>
loadFacadeModule().wrapOllamaCompatNumCtx(...args)) as FacadeModule["wrapOllamaCompatNumCtx"];

View File

@@ -0,0 +1,17 @@
// Manual facade. Keep loader boundary explicit.
type FacadeModule = typeof import("@openclaw/telegram/contract-api.js");
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
function loadFacadeModule(): FacadeModule {
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
dirName: "telegram",
artifactBasename: "contract-api.js",
});
}
export const parseTelegramTopicConversation: FacadeModule["parseTelegramTopicConversation"] = ((
...args
) =>
loadFacadeModule().parseTelegramTopicConversation(
...args,
)) as FacadeModule["parseTelegramTopicConversation"];

View File

@@ -1,5 +1,8 @@
import { listBundledPluginMetadata } from "./bundled-plugin-metadata.js";
// Build/test inventory only.
// Runtime code should prefer manifest/runtime registry queries instead of these snapshots.
export type BundledPluginContractSnapshot = {
pluginId: string;
providerIds: string[];

View File

@@ -1,9 +1,6 @@
import { normalizeChatChannelId } from "../channels/registry.js";
import type { OpenClawConfig } from "../config/config.js";
import {
BUNDLED_LEGACY_PLUGIN_ID_ALIASES,
BUNDLED_PROVIDER_PLUGIN_ID_ALIASES,
} from "./bundled-capability-metadata.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
import { defaultSlotIdForKey, hasKind } from "./slots.js";
import type { PluginKind, PluginOrigin } from "./types.js";
@@ -74,13 +71,33 @@ export type NormalizedPluginsConfig = {
>;
};
let bundledPluginAliasLookupCache: ReadonlyMap<string, string> | undefined;
function getBundledPluginAliasLookup(): ReadonlyMap<string, string> {
if (bundledPluginAliasLookupCache) {
return bundledPluginAliasLookupCache;
}
const lookup = new Map<string, string>();
for (const plugin of loadPluginManifestRegistry({ cache: true }).plugins) {
if (plugin.origin !== "bundled") {
continue;
}
lookup.set(plugin.id.toLowerCase(), plugin.id);
for (const providerId of plugin.providers) {
lookup.set(providerId.toLowerCase(), plugin.id);
}
for (const legacyPluginId of plugin.legacyPluginIds ?? []) {
lookup.set(legacyPluginId.toLowerCase(), plugin.id);
}
}
bundledPluginAliasLookupCache = lookup;
return lookup;
}
export function normalizePluginId(id: string): string {
const trimmed = id.trim();
return (
BUNDLED_LEGACY_PLUGIN_ID_ALIASES[trimmed] ??
BUNDLED_PROVIDER_PLUGIN_ID_ALIASES[trimmed] ??
trimmed
);
return getBundledPluginAliasLookup().get(trimmed.toLowerCase()) ?? trimmed;
}
const normalizeList = (value: unknown): string[] => {