refactor: move plugin contracts onto SDK testing seams

This commit is contained in:
Peter Steinberger
2026-04-28 00:14:52 +01:00
parent d3e4640bed
commit d462d1faf2
28 changed files with 326 additions and 167 deletions

View File

@@ -1,13 +1,15 @@
import type { OpenClawConfig } from "../../../src/config/config.js";
import { createPluginRegistry, type PluginRecord } from "../../../src/plugins/registry.js";
import type { PluginRuntime } from "../../../src/plugins/runtime/types.js";
import { createPluginRecord } from "../../../src/plugins/status.test-helpers.js";
import type { OpenClawPluginApi } from "../../../src/plugins/types.js";
export {
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
import {
createPluginRecord,
createPluginRegistry,
registerProviderPlugins as registerProviders,
requireRegisteredProvider as requireProvider,
} from "../../../src/test-utils/plugin-registration.js";
type OpenClawConfig,
type PluginRecord,
type PluginRuntime,
} from "openclaw/plugin-sdk/testing";
export { registerProviders, requireProvider };
export function uniqueSortedStrings(values: readonly string[]) {
return [...new Set(values)].toSorted((left, right) => left.localeCompare(right));

View File

@@ -1,5 +1,5 @@
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { ModelApi } from "../../../src/config/types.models.js";
import type { ModelApi } from "openclaw/plugin-sdk/provider-model-shared";
import type { OpenClawConfig } from "openclaw/plugin-sdk/testing";
export const EXPECTED_FALLBACKS = ["anthropic/claude-opus-4-5"] as const;

View File

@@ -1,16 +1,12 @@
export { deliverOutboundPayloads } from "../../../src/infra/outbound/deliver.js";
export {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../../../src/plugins/hook-runner-global.js";
export { addTestHook } from "../../../src/plugins/hooks.test-helpers.js";
export { createEmptyPluginRegistry } from "../../../src/plugins/registry.js";
export {
releasePinnedPluginChannelRegistry,
setActivePluginRegistry,
} from "../../../src/plugins/runtime.js";
export type { PluginHookRegistration } from "../../../src/plugins/types.js";
export {
addTestHook,
createEmptyPluginRegistry,
createOutboundTestPlugin,
createTestRegistry,
} from "../../../src/test-utils/channel-plugins.js";
deliverOutboundPayloads,
initializeGlobalHookRunner,
releasePinnedPluginChannelRegistry,
resetGlobalHookRunner,
setActivePluginRegistry,
type PluginHookRegistration,
} from "openclaw/plugin-sdk/testing";

View File

@@ -1,8 +1,11 @@
import fs from "node:fs";
import path from "node:path";
import {
isAtLeast,
parseMinHostVersionRequirement,
parseSemver,
} from "openclaw/plugin-sdk/testing";
import { describe, expect, it } from "vitest";
import { isAtLeast, parseSemver } from "../../../src/infra/runtime-guard.js";
import { parseMinHostVersionRequirement } from "../../../src/plugins/min-host-version.js";
import { bundledPluginFile } from "../bundled-plugin-paths.js";
type PackageManifest = {

View File

@@ -1,6 +1,8 @@
import {
loadPluginManifestRegistry,
pluginRegistrationContractRegistry,
} from "openclaw/plugin-sdk/testing";
import { describe, expect, it } from "vitest";
import { pluginRegistrationContractRegistry } from "../../../src/plugins/contracts/registry.js";
import { loadPluginManifestRegistry } from "../../../src/plugins/manifest-registry.js";
type PluginRegistrationContractParams = {
pluginId: string;

View File

@@ -1,15 +1,15 @@
import { vi } from "vitest";
import {
implicitMentionKindWhen,
resolveInboundMentionDecision,
} from "openclaw/plugin-sdk/channel-mention-gating";
import {
createAckReactionHandle,
removeAckReactionAfterReply,
removeAckReactionHandleAfterReply,
shouldAckReaction,
} from "../../../src/channels/ack-reactions.js";
import {
implicitMentionKindWhen,
resolveInboundMentionDecision,
} from "../../../src/channels/mention-gating.js";
import type { PluginRuntime } from "../../../src/plugins/runtime/types.js";
} from "openclaw/plugin-sdk/testing";
import type { PluginRuntime } from "openclaw/plugin-sdk/testing";
import { vi } from "vitest";
const DEFAULT_PROVIDER = "openai";
const DEFAULT_MODEL = "gpt-5.5";

View File

@@ -1,21 +1,21 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { clearRuntimeAuthProfileStoreSnapshots } from "../../../src/agents/auth-profiles/store.js";
import type { AuthProfileStore } from "../../../src/agents/auth-profiles/types.js";
import { createNonExitingRuntime } from "../../../src/runtime.js";
import {
clearRuntimeAuthProfileStoreSnapshots,
type AuthProfileStore,
} from "openclaw/plugin-sdk/agent-runtime";
import { createNonExitingRuntime } from "openclaw/plugin-sdk/runtime";
import type {
WizardMultiSelectParams,
WizardPrompter,
WizardProgress,
WizardSelectParams,
} from "../../../src/wizard/prompts.js";
} from "openclaw/plugin-sdk/setup";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { registerProviders, requireProvider } from "./contracts-testkit.js";
type LoginOpenAICodexOAuth =
(typeof import("openclaw/plugin-sdk/provider-auth-login"))["loginOpenAICodexOAuth"];
type GithubCopilotLoginCommand =
(typeof import("openclaw/plugin-sdk/provider-auth-login"))["githubCopilotLoginCommand"];
type CreateVpsAwareHandlers =
(typeof import("../../../src/plugins/provider-oauth-flow.js"))["createVpsAwareOAuthHandlers"];
type EnsureAuthProfileStore =
typeof import("openclaw/plugin-sdk/provider-auth").ensureAuthProfileStore;
type ListProfilesForProvider =
@@ -83,7 +83,7 @@ function buildAuthContext() {
isRemote: false,
openUrl: async () => {},
oauth: {
createVpsAwareHandlers: vi.fn<CreateVpsAwareHandlers>(),
createVpsAwareHandlers: vi.fn(),
},
};
}

View File

@@ -3,12 +3,12 @@ export {
expectedAugmentedOpenaiCodexCatalogEntriesWithGpt55,
expectCodexBuiltInSuppression,
expectCodexMissingAuthHint,
} from "../../../src/plugins/provider-runtime.test-support.js";
export type { ProviderPlugin } from "../../../src/plugins/types.js";
} from "openclaw/plugin-sdk/testing";
export type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
export {
loadBundledPluginPublicSurface,
loadBundledPluginPublicSurfaceSync,
} from "../../../src/test-utils/bundled-plugin-public-surface.js";
} from "./public-surface-loader.js";
type ProviderRuntimeCatalogModule = Pick<
typeof import("openclaw/plugin-sdk/provider-catalog-runtime"),

View File

@@ -1,10 +1,8 @@
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
import type { WebFetchProviderPlugin } from "openclaw/plugin-sdk/provider-web-fetch-contract";
import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/provider-web-search-contract";
import type { OpenClawConfig } from "openclaw/plugin-sdk/testing";
import { expect, it } from "vitest";
import type { OpenClawConfig } from "../../../src/config/config.js";
import type {
ProviderPlugin,
WebFetchProviderPlugin,
WebSearchProviderPlugin,
} from "../../../src/plugins/types.js";
type Lazy<T> = T | (() => T);

View File

@@ -1,10 +1,10 @@
import { describe, expect, it } from "vitest";
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
import {
providerContractLoadError,
resolveBundledExplicitProviderContractsFromPublicArtifacts,
resolveProviderContractProvidersForPluginIds,
} from "../../../src/plugins/contracts/registry.js";
import { resolveBundledExplicitProviderContractsFromPublicArtifacts } from "../../../src/plugins/provider-contract-public-artifacts.js";
import type { ProviderPlugin } from "../../../src/plugins/types.js";
} from "openclaw/plugin-sdk/testing";
import { describe, expect, it } from "vitest";
import { installProviderPluginContractSuite } from "./provider-contract-suites.js";
type ProviderContractEntry = {

View File

@@ -1,10 +1,10 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { AuthProfileStore } from "../../../src/agents/auth-profiles/types.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { AuthProfileStore, OpenClawConfig } from "openclaw/plugin-sdk/provider-auth";
import {
registerProviderPlugins as registerProviders,
requireRegisteredProvider as requireProvider,
} from "../../../src/test-utils/plugin-registration.js";
runProviderCatalog,
} from "openclaw/plugin-sdk/testing";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const resolveCopilotApiTokenMock = vi.hoisted(() => vi.fn());
const buildVllmProviderMock = vi.hoisted(() => vi.fn());
@@ -19,7 +19,7 @@ export type ProviderDiscoveryContractPluginLoader = () => Promise<{
type ProviderHandle = Awaited<ReturnType<typeof registerProviders>>[number];
type DiscoveryState = {
runProviderCatalog: typeof import("../../../src/plugins/provider-discovery.js").runProviderCatalog;
runProviderCatalog: typeof runProviderCatalog;
githubCopilotProvider?: ProviderHandle;
vllmProvider?: ProviderHandle;
sglangProvider?: ProviderHandle;
@@ -183,8 +183,7 @@ function installDiscoveryHooks(state: DiscoveryState, options: DiscoveryContract
};
});
}
({ runProviderCatalog: state.runProviderCatalog } =
await import("../../../src/plugins/provider-discovery.js"));
state.runProviderCatalog = runProviderCatalog;
if (options.providerIds.includes("github-copilot")) {
const { default: githubCopilotPlugin } = await options.loadGithubCopilot!();

View File

@@ -3,8 +3,8 @@ import {
resolveAgentModelPrimaryValue,
} from "openclaw/plugin-sdk/provider-onboard";
import type { ModelApi } from "openclaw/plugin-sdk/provider-onboard";
import type { OpenClawConfig } from "openclaw/plugin-sdk/testing";
import { expect } from "vitest";
import type { OpenClawConfig } from "../../../src/config/config.js";
import {
createConfigWithFallbacks,
createLegacyProviderConfig,

View File

@@ -1,6 +1,8 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import type { ProviderRuntimeModel } from "openclaw/plugin-sdk/plugin-entry";
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
import {
createProviderUsageFetch,
makeResponse,
@@ -8,7 +10,6 @@ import {
requireRegisteredProvider,
} from "openclaw/plugin-sdk/testing";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ProviderPlugin, ProviderRuntimeModel } from "../../../src/plugins/types.js";
const CONTRACT_SETUP_TIMEOUT_MS = 300_000;

View File

@@ -1,18 +1,16 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ProviderAuthMethod } from "openclaw/plugin-sdk/plugin-entry";
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
import {
buildProviderPluginMethodChoice,
resolveProviderModelPickerEntries,
resolveProviderPluginChoice,
resolveProviderWizardOptions,
} from "../../../src/plugins/provider-wizard.js";
import type { ProviderAuthMethod, ProviderPlugin } from "../../../src/plugins/types.js";
setProviderWizardProvidersResolverForTest,
} from "openclaw/plugin-sdk/testing";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const resolvePluginProvidersMock = vi.fn();
vi.mock("../../../src/plugins/providers.runtime.js", () => ({
isPluginProvidersLoadInFlight: () => false,
resolvePluginProviders: (...args: unknown[]) => resolvePluginProvidersMock(...args),
}));
let restoreProviderResolver: (() => void) | undefined;
function createAuthMethod(
params: Pick<ProviderAuthMethod, "id" | "label"> &
@@ -175,6 +173,15 @@ function expectAllChoicesResolve(
beforeEach(() => {
resolvePluginProvidersMock.mockReset();
resolvePluginProvidersMock.mockReturnValue(TEST_PROVIDERS);
restoreProviderResolver?.();
restoreProviderResolver = setProviderWizardProvidersResolverForTest((params) =>
resolvePluginProvidersMock(params),
);
});
afterEach(() => {
restoreProviderResolver?.();
restoreProviderResolver = undefined;
});
export function describeProviderWizardSetupOptionsContract() {

View File

@@ -1,7 +1,4 @@
import {
assertUniqueValues,
BUNDLED_RUNTIME_SIDECAR_PATHS,
} from "../../../src/plugins/runtime-sidecar-paths.js";
import { assertUniqueValues, BUNDLED_RUNTIME_SIDECAR_PATHS } from "openclaw/plugin-sdk/testing";
export function getPublicArtifactBasename(relativePath: string): string {
return relativePath.split("/").at(-1) ?? relativePath;

View File

@@ -0,0 +1,81 @@
import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
const repoRoot = process.cwd();
function readJson<T>(filePath: string): T | undefined {
try {
return JSON.parse(fs.readFileSync(filePath, "utf8")) as T;
} catch {
return undefined;
}
}
function normalizeArtifactBasename(artifactBasename: string): string {
return artifactBasename.replace(/^\.\/+/u, "").replace(/^\/+/u, "");
}
function resolveSourceArtifactPath(packageDir: string, artifactBasename: string): string {
const artifactPath = path.resolve(packageDir, normalizeArtifactBasename(artifactBasename));
if (artifactPath.endsWith(".js")) {
const sourcePath = `${artifactPath.slice(0, -".js".length)}.ts`;
if (fs.existsSync(sourcePath)) {
return sourcePath;
}
}
return artifactPath;
}
function resolveExtensionDirByManifestId(pluginId: string): string {
const pluginDir = path.resolve(repoRoot, "extensions", pluginId);
const manifest = readJson<{ id?: unknown }>(path.join(pluginDir, "openclaw.plugin.json"));
if (manifest?.id === pluginId) {
return pluginDir;
}
throw new Error(`Unknown bundled plugin id: ${pluginId}`);
}
function resolveWorkspacePackageDir(packageName: string): string {
const extensionsDir = path.resolve(repoRoot, "extensions");
for (const entry of fs.readdirSync(extensionsDir, { withFileTypes: true })) {
if (!entry.isDirectory()) {
continue;
}
const packageDir = path.join(extensionsDir, entry.name);
const manifest = readJson<{ name?: unknown }>(path.join(packageDir, "package.json"));
if (manifest?.name === packageName) {
return packageDir;
}
}
throw new Error(`Unknown workspace package: ${packageName}`);
}
export async function loadBundledPluginPublicSurface<T extends object>(params: {
pluginId: string;
artifactBasename: string;
}): Promise<T> {
const artifactPath = resolveSourceArtifactPath(
resolveExtensionDirByManifestId(params.pluginId),
params.artifactBasename,
);
return (await import(pathToFileURL(artifactPath).href)) as T;
}
export function loadBundledPluginPublicSurfaceSync<T extends object>(_params: {
pluginId: string;
artifactBasename: string;
}): T {
throw new Error("Synchronous bundled plugin public-surface loading is not available here");
}
export function resolveWorkspacePackagePublicModuleUrl(params: {
packageName: string;
artifactBasename: string;
}): string {
const artifactPath = resolveSourceArtifactPath(
resolveWorkspacePackageDir(params.packageName),
params.artifactBasename,
);
return pathToFileURL(artifactPath).href;
}

View File

@@ -1,11 +1,11 @@
import { createRuntimeEnv } from "openclaw/plugin-sdk/testing";
import { vi } from "vitest";
import type {
ChannelAccountSnapshot,
ChannelGatewayContext,
} from "../../../src/channels/plugins/types.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { RuntimeEnv } from "../../../src/runtime.js";
OpenClawConfig,
RuntimeEnv,
} from "openclaw/plugin-sdk/testing";
import { vi } from "vitest";
export function createStartAccountContext<TAccount extends { accountId: string }>(params: {
account: TAccount;

View File

@@ -1,8 +1,5 @@
import type { ChannelAccountSnapshot, ChannelGatewayContext } from "openclaw/plugin-sdk/testing";
import { expect, vi } from "vitest";
import type {
ChannelAccountSnapshot,
ChannelGatewayContext,
} from "../../../src/channels/plugins/types.js";
import { createStartAccountContext } from "./start-account-context.js";
export function startAccountAndTrackLifecycle<TAccount extends { accountId: string }>(params: {

View File

@@ -1,16 +1,19 @@
import type { AssistantMessage } from "@mariozechner/pi-ai";
import type { ResolvedTtsConfig, SpeechProviderPlugin } from "openclaw/plugin-sdk/speech-core";
import type { OpenClawConfig } from "openclaw/plugin-sdk/testing";
import {
BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS,
createEmptyPluginRegistry,
setActivePluginRegistry,
withEnv,
withEnvAsync,
} from "openclaw/plugin-sdk/testing";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../../src/config/config.js";
import { BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS } from "../../../src/plugins/contracts/inventory/bundled-capability-metadata.js";
import { createEmptyPluginRegistry } from "../../../src/plugins/registry-empty.js";
import { setActivePluginRegistry } from "../../../src/plugins/runtime.js";
import type { SpeechProviderPlugin } from "../../../src/plugins/types.js";
import { resolveWorkspacePackagePublicModuleUrl } from "../../../src/test-utils/bundled-plugin-public-surface.js";
import { withEnv, withEnvAsync } from "../../../src/test-utils/env.js";
import type { ResolvedTtsConfig } from "../../../src/tts/tts-types.js";
import { resolveWorkspacePackagePublicModuleUrl } from "./public-surface-loader.js";
type TtsRuntimeModule = typeof import("../../../src/tts/tts.js");
type TtsCoreModule = typeof import("../../../src/tts/tts-core.js");
type TtsRuntimeModule = typeof import("openclaw/plugin-sdk/tts-runtime");
type TtsCoreModule = typeof import("openclaw/plugin-sdk/speech-core");
type SummarizeTextDeps = NonNullable<Parameters<TtsCoreModule["summarizeText"]>[1]>;
const speechCoreRuntimeApiModuleId = resolveWorkspacePackagePublicModuleUrl({
packageName: "@openclaw/speech-core",
@@ -22,11 +25,11 @@ let ttsRuntimePromise: Promise<TtsRuntimeModule> | null = null;
let ttsRuntimeInitialized = false;
let ttsCorePromise: Promise<TtsCoreModule> | null = null;
let completeSimple: typeof import("@mariozechner/pi-ai").completeSimple;
let getApiKeyForModelMock: typeof import("../../../src/agents/model-auth.js").getApiKeyForModel;
let requireApiKeyMock: typeof import("../../../src/agents/model-auth.js").requireApiKey;
let resolveModelAsyncMock: typeof import("../../../src/agents/pi-embedded-runner/model.js").resolveModelAsync;
let ensureCustomApiRegisteredMock: typeof import("../../../src/agents/custom-api-registry.js").ensureCustomApiRegistered;
let prepareModelForSimpleCompletionMock: typeof import("../../../src/agents/simple-completion-transport.js").prepareModelForSimpleCompletion;
let getApiKeyForModelMock: SummarizeTextDeps["getApiKeyForModel"];
let requireApiKeyMock: SummarizeTextDeps["requireApiKey"];
let resolveModelAsyncMock: SummarizeTextDeps["resolveModelAsync"];
let ensureCustomApiRegisteredMock: ReturnType<typeof vi.fn>;
let prepareModelForSimpleCompletionMock: SummarizeTextDeps["prepareModelForSimpleCompletion"];
let summarizeTextCore: TtsCoreModule["summarizeText"];
let resolveTtsConfig: TtsRuntimeModule["resolveTtsConfig"];
let maybeApplyTtsToPayload: TtsRuntimeModule["maybeApplyTtsToPayload"];
@@ -108,28 +111,6 @@ function createResolvedModel(provider: string, modelId: string, api = "openai-co
};
}
vi.mock("../../../src/agents/pi-embedded-runner/model.js", () => ({
resolveModel: vi.fn((provider: string, modelId: string) =>
createResolvedModel(provider, modelId),
),
resolveModelAsync: vi.fn(async (provider: string, modelId: string) =>
createResolvedModel(provider, modelId),
),
}));
vi.mock("../../../src/agents/model-auth.js", () => ({
getApiKeyForModel: vi.fn(async () => ({
apiKey: "test-api-key",
source: "test",
mode: "api-key",
})),
requireApiKey: vi.fn((auth: { apiKey?: string }) => auth.apiKey ?? ""),
}));
vi.mock("../../../src/agents/custom-api-registry.js", () => ({
ensureCustomApiRegistered: vi.fn(),
}));
function asLegacyTtsConfig(value: unknown): OpenClawConfig {
return value as OpenClawConfig;
}
@@ -444,10 +425,16 @@ async function loadTtsRuntime(): Promise<TtsRuntimeModule> {
}
async function loadTtsCore(): Promise<TtsCoreModule> {
ttsCorePromise ??= import("../../../src/tts/tts-core.js");
ttsCorePromise ??= import("openclaw/plugin-sdk/speech-core");
return await ttsCorePromise;
}
function createPrepareModelForSimpleCompletionMock(): SummarizeTextDeps["prepareModelForSimpleCompletion"] {
return vi.fn(
({ model }: Parameters<SummarizeTextDeps["prepareModelForSimpleCompletion"]>[0]) => model,
) as SummarizeTextDeps["prepareModelForSimpleCompletion"];
}
async function setupTtsRuntime() {
if (ttsRuntimeInitialized) {
return;
@@ -467,7 +454,7 @@ async function setupTtsRuntime() {
}
function setupTestSpeechProviderRegistry() {
prepareModelForSimpleCompletionMock = vi.fn(({ model }) => model);
prepareModelForSimpleCompletionMock = createPrepareModelForSimpleCompletionMock();
const registry = createEmptyPluginRegistry();
registry.speechProviders = [
{ pluginId: "openai", provider: buildTestOpenAISpeechProvider(), source: "test" },
@@ -510,14 +497,12 @@ function createResolvedSummarizationConfig(cfg: OpenClawConfig): ResolvedTtsConf
async function setupSummarizationMocks() {
({ summarizeText: summarizeTextCore } = await loadTtsCore());
prepareModelForSimpleCompletionMock = vi.fn(({ model }) => model);
({ completeSimple } = await import("@mariozechner/pi-ai"));
({ getApiKeyForModel: getApiKeyForModelMock, requireApiKey: requireApiKeyMock } =
await import("../../../src/agents/model-auth.js"));
({ resolveModelAsync: resolveModelAsyncMock } =
await import("../../../src/agents/pi-embedded-runner/model.js"));
({ ensureCustomApiRegistered: ensureCustomApiRegisteredMock } =
await import("../../../src/agents/custom-api-registry.js"));
getApiKeyForModelMock = vi.fn() as SummarizeTextDeps["getApiKeyForModel"];
requireApiKeyMock = vi.fn() as SummarizeTextDeps["requireApiKey"];
resolveModelAsyncMock = vi.fn() as SummarizeTextDeps["resolveModelAsync"];
ensureCustomApiRegisteredMock = vi.fn();
prepareModelForSimpleCompletionMock = createPrepareModelForSimpleCompletionMock();
vi.mocked(completeSimple).mockResolvedValue(
mockAssistantMessage([{ type: "text", text: "Summary" }]),
);
@@ -534,7 +519,7 @@ async function setupSummarizationMocks() {
>,
);
vi.mocked(ensureCustomApiRegisteredMock).mockReset();
prepareModelForSimpleCompletionMock = vi.fn(({ model }) => model);
prepareModelForSimpleCompletionMock = createPrepareModelForSimpleCompletionMock();
}
async function setupTtsContractTest() {

View File

@@ -1,10 +1,10 @@
import { describe, expect, it } from "vitest";
import type { WebFetchProviderPlugin } from "openclaw/plugin-sdk/provider-web-fetch-contract";
import {
pluginRegistrationContractRegistry,
resolveBundledExplicitWebFetchProvidersFromPublicArtifacts,
resolveWebFetchProviderContractEntriesForPluginId,
} from "../../../src/plugins/contracts/registry.js";
import type { WebFetchProviderPlugin } from "../../../src/plugins/types.js";
import { resolveBundledExplicitWebFetchProvidersFromPublicArtifacts } from "../../../src/plugins/web-provider-public-artifacts.explicit.js";
} from "openclaw/plugin-sdk/testing";
import { describe, expect, it } from "vitest";
import { installWebFetchProviderContractSuite } from "./provider-contract-suites.js";
function resolveWebFetchCredentialValue(provider: WebFetchProviderPlugin): unknown {

View File

@@ -1,9 +1,9 @@
import { describe, expect, it } from "vitest";
import {
pluginRegistrationContractRegistry,
resolveBundledExplicitWebSearchProvidersFromPublicArtifacts,
resolveWebSearchProviderContractEntriesForPluginId,
} from "../../../src/plugins/contracts/registry.js";
import { resolveBundledExplicitWebSearchProvidersFromPublicArtifacts } from "../../../src/plugins/web-provider-public-artifacts.explicit.js";
} from "openclaw/plugin-sdk/testing";
import { describe, expect, it } from "vitest";
import { installWebSearchProviderContractSuite } from "./provider-contract-suites.js";
type WebSearchContractEntry = ReturnType<