mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:10:44 +00:00
test: keep extension mocks on sdk seams
This commit is contained in:
@@ -99,6 +99,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
|
||||
| `plugin-sdk/provider-env-vars` | Provider auth env-var lookup helpers |
|
||||
| `plugin-sdk/provider-auth` | `createProviderApiKeyAuthMethod`, `ensureApiKeyFromOptionEnvOrPrompt`, `upsertAuthProfile`, `upsertApiKeyProfile`, `writeOAuthCredentials` |
|
||||
| `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`, `buildProviderReplayFamilyHooks`, `normalizeModelCompat`, shared replay-policy builders, provider-endpoint helpers, and model-id normalization helpers such as `normalizeNativeXaiModelId` |
|
||||
| `plugin-sdk/provider-catalog-runtime` | Provider catalog runtime hook and plugin-provider registry seams for contract tests |
|
||||
| `plugin-sdk/provider-catalog-shared` | `findCatalogTemplate`, `buildSingleProviderApiKeyCatalog`, `supportsNativeStreamingUsageCompat`, `applyProviderNativeStreamingUsageCompat` |
|
||||
| `plugin-sdk/provider-http` | Generic provider HTTP/endpoint capability helpers, provider HTTP errors, and audio transcription multipart form helpers |
|
||||
| `plugin-sdk/provider-web-fetch-contract` | Narrow web-fetch config/selection contract helpers such as `enablePluginInConfig` and `WebFetchProviderPlugin` |
|
||||
|
||||
@@ -10,11 +10,6 @@ vi.mock("./channel.runtime.js", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
let bluebubblesPlugin: typeof import("./channel.js").bluebubblesPlugin;
|
||||
|
||||
describe("bluebubblesPlugin.status.probeAccount", () => {
|
||||
|
||||
@@ -16,9 +16,15 @@ const gatewayMocks = vi.hoisted(() => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/cli/gateway-rpc.js", () => ({
|
||||
callGatewayFromCli: gatewayMocks.callGatewayFromCli,
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/browser-node-runtime", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/browser-node-runtime")>(
|
||||
"openclaw/plugin-sdk/browser-node-runtime",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
callGatewayFromCli: gatewayMocks.callGatewayFromCli,
|
||||
};
|
||||
});
|
||||
|
||||
const configMocks = vi.hoisted(() => {
|
||||
const loadConfig = vi.fn(() => ({ browser: {} }));
|
||||
|
||||
@@ -18,10 +18,16 @@ vi.mock("openclaw/plugin-sdk/runtime-config-snapshot", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../../../src/gateway/node-command-policy.js", () => ({
|
||||
isNodeCommandAllowed: isNodeCommandAllowedMock,
|
||||
resolveNodeCommandAllowlist: resolveNodeCommandAllowlistMock,
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/browser-node-runtime", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/browser-node-runtime")>(
|
||||
"openclaw/plugin-sdk/browser-node-runtime",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
isNodeCommandAllowed: isNodeCommandAllowedMock,
|
||||
resolveNodeCommandAllowlist: resolveNodeCommandAllowlistMock,
|
||||
};
|
||||
});
|
||||
|
||||
import { browserHandlers } from "./browser-request.js";
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const oauthMocks = vi.hoisted(() => ({
|
||||
const providerRuntimeMocks = vi.hoisted(() => ({
|
||||
formatProviderAuthProfileApiKeyWithPlugin: vi.fn(),
|
||||
refreshProviderOAuthCredentialWithPlugin: vi.fn(
|
||||
async (params: { context: { refresh: string } }) => {
|
||||
async (params: { provider?: string; context: { refresh: string } }) => {
|
||||
const refreshed = await oauthMocks.refreshOpenAICodexToken(params.context.refresh);
|
||||
return refreshed
|
||||
? {
|
||||
@@ -37,12 +37,57 @@ vi.mock("@mariozechner/pi-ai/oauth", () => ({
|
||||
refreshOpenAICodexToken: oauthMocks.refreshOpenAICodexToken,
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/plugins/provider-runtime.runtime.js", () => ({
|
||||
formatProviderAuthProfileApiKeyWithPlugin:
|
||||
providerRuntimeMocks.formatProviderAuthProfileApiKeyWithPlugin,
|
||||
refreshProviderOAuthCredentialWithPlugin:
|
||||
providerRuntimeMocks.refreshProviderOAuthCredentialWithPlugin,
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/agent-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/agent-runtime")>();
|
||||
return {
|
||||
...actual,
|
||||
resolveApiKeyForProfile: async (
|
||||
params: Parameters<typeof actual.resolveApiKeyForProfile>[0],
|
||||
) => {
|
||||
const credential = params.store.profiles[params.profileId];
|
||||
if (!credential) {
|
||||
return null;
|
||||
}
|
||||
if (credential.type === "api_key") {
|
||||
const apiKey =
|
||||
credential.key?.trim() ||
|
||||
(credential.keyRef?.source === "env" ? process.env[credential.keyRef.id]?.trim() : "");
|
||||
return apiKey ? { apiKey, provider: credential.provider } : null;
|
||||
}
|
||||
if (credential.type === "token") {
|
||||
const apiKey =
|
||||
credential.token?.trim() ||
|
||||
(credential.tokenRef?.source === "env"
|
||||
? process.env[credential.tokenRef.id]?.trim()
|
||||
: "");
|
||||
return apiKey ? { apiKey, provider: credential.provider, email: credential.email } : null;
|
||||
}
|
||||
let oauthCredential = credential;
|
||||
if ((oauthCredential.expires ?? 0) <= Date.now()) {
|
||||
const refreshed = await providerRuntimeMocks.refreshProviderOAuthCredentialWithPlugin({
|
||||
provider: oauthCredential.provider,
|
||||
context: oauthCredential,
|
||||
});
|
||||
if (refreshed?.access) {
|
||||
oauthCredential = refreshed as typeof oauthCredential;
|
||||
params.store.profiles[params.profileId] = oauthCredential;
|
||||
if (params.agentDir) {
|
||||
actual.saveAuthProfileStore(params.store, params.agentDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
const formatted = await providerRuntimeMocks.formatProviderAuthProfileApiKeyWithPlugin({
|
||||
provider: oauthCredential.provider,
|
||||
context: oauthCredential,
|
||||
});
|
||||
const apiKey =
|
||||
typeof formatted === "string" && formatted ? formatted : oauthCredential.access;
|
||||
return apiKey
|
||||
? { apiKey, provider: oauthCredential.provider, email: oauthCredential.email }
|
||||
: null;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
|
||||
@@ -25,9 +25,15 @@ type DiscordReactionClient = Parameters<
|
||||
|
||||
const readAllowFromStoreMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../../../src/pairing/pairing-store.js", () => ({
|
||||
readChannelAllowFromStore: (...args: unknown[]) => readAllowFromStoreMock(...args),
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/conversation-runtime", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/conversation-runtime")>(
|
||||
"openclaw/plugin-sdk/conversation-runtime",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
readChannelAllowFromStore: (...args: unknown[]) => readAllowFromStoreMock(...args),
|
||||
};
|
||||
});
|
||||
|
||||
const fakeGuild = (id: string, name: string) => ({ id, name }) as Guild;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import path from "node:path";
|
||||
import { ChannelType, type AutocompleteInteraction } from "@buape/carbon";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
|
||||
import { clearSessionStoreCacheForTest } from "openclaw/plugin-sdk/session-store-runtime";
|
||||
import { createEmptyPluginRegistry, setActivePluginRegistry } from "openclaw/plugin-sdk/testing";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createNoopThreadBindingManager } from "./thread-bindings.js";
|
||||
|
||||
@@ -125,14 +126,44 @@ let findCommandByNativeName: typeof import("openclaw/plugin-sdk/command-auth").f
|
||||
let resolveCommandArgChoices: typeof import("openclaw/plugin-sdk/command-auth").resolveCommandArgChoices;
|
||||
let resolveDiscordNativeChoiceContext: typeof import("./native-command-ui.js").resolveDiscordNativeChoiceContext;
|
||||
|
||||
function installProviderThinkingRegistryForTest(): void {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
registry.providers.push({
|
||||
pluginId: "discord-test",
|
||||
source: "test",
|
||||
provider: {
|
||||
id: "discord-test-thinking",
|
||||
label: "Discord Test Thinking",
|
||||
aliases: ["anthropic", "openai-codex"],
|
||||
auth: [],
|
||||
isBinaryThinking: (context) =>
|
||||
providerThinkingMocks.resolveProviderBinaryThinking({
|
||||
provider: context.provider,
|
||||
context,
|
||||
}),
|
||||
supportsXHighThinking: (context) =>
|
||||
providerThinkingMocks.resolveProviderXHighThinking({
|
||||
provider: context.provider,
|
||||
context,
|
||||
}),
|
||||
resolveThinkingProfile: (context) =>
|
||||
providerThinkingMocks.resolveProviderThinkingProfile({
|
||||
provider: context.provider,
|
||||
context,
|
||||
}),
|
||||
resolveDefaultThinkingLevel: (context) =>
|
||||
providerThinkingMocks.resolveProviderDefaultThinkingLevel({
|
||||
provider: context.provider,
|
||||
context,
|
||||
}),
|
||||
},
|
||||
});
|
||||
setActivePluginRegistry(registry);
|
||||
}
|
||||
|
||||
async function loadDiscordThinkAutocompleteModulesForTest() {
|
||||
vi.resetModules();
|
||||
vi.doMock("../../../../src/plugins/provider-thinking.js", () => ({
|
||||
resolveProviderBinaryThinking: providerThinkingMocks.resolveProviderBinaryThinking,
|
||||
resolveProviderDefaultThinkingLevel: providerThinkingMocks.resolveProviderDefaultThinkingLevel,
|
||||
resolveProviderThinkingProfile: providerThinkingMocks.resolveProviderThinkingProfile,
|
||||
resolveProviderXHighThinking: providerThinkingMocks.resolveProviderXHighThinking,
|
||||
}));
|
||||
installProviderThinkingRegistryForTest();
|
||||
const commandAuth = await import("openclaw/plugin-sdk/command-auth");
|
||||
const nativeCommandUi = await import("./native-command-ui.js");
|
||||
return {
|
||||
@@ -183,6 +214,7 @@ describe("discord native /think autocomplete", () => {
|
||||
? true
|
||||
: undefined,
|
||||
);
|
||||
installProviderThinkingRegistryForTest();
|
||||
fs.mkdirSync(path.dirname(STORE_PATH), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
STORE_PATH,
|
||||
|
||||
@@ -55,11 +55,6 @@ vi.mock("./channel.runtime.js", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
function getDescribedActions(cfg: OpenClawConfig, accountId?: string): string[] {
|
||||
return [...(feishuPlugin.actions?.describeMessageTool?.({ cfg, accountId })?.actions ?? [])];
|
||||
}
|
||||
|
||||
@@ -91,11 +91,6 @@ vi.mock("./subagent-hooks.js", () => ({
|
||||
registerFeishuSubagentHooks: registerFeishuSubagentHooksMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
const baseAccount: ResolvedFeishuAccount = {
|
||||
accountId: "main",
|
||||
selectionSource: "explicit",
|
||||
|
||||
@@ -218,10 +218,3 @@ vi.mock("openclaw/plugin-sdk/conversation-runtime", async () => {
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../../src/infra/outbound/session-binding-service.js", () => ({
|
||||
getSessionBindingService: () => ({
|
||||
resolveByConversation: resolveBoundConversationMock,
|
||||
touch: touchBindingMock,
|
||||
}),
|
||||
}));
|
||||
|
||||
@@ -51,11 +51,6 @@ vi.mock("openclaw/plugin-sdk/media-runtime", async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
let downloadImageFeishu: typeof import("./media.js").downloadImageFeishu;
|
||||
let downloadMessageResourceFeishu: typeof import("./media.js").downloadMessageResourceFeishu;
|
||||
let sanitizeFileNameForUpload: typeof import("./media.js").sanitizeFileNameForUpload;
|
||||
|
||||
@@ -20,11 +20,6 @@ vi.mock("./runtime.js", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
let sendCardFeishu: typeof import("./send.js").sendCardFeishu;
|
||||
let sendMessageFeishu: typeof import("./send.js").sendMessageFeishu;
|
||||
|
||||
|
||||
@@ -1,25 +1,37 @@
|
||||
import { join, parse } from "node:path";
|
||||
import { describe, expect, it, vi, beforeAll, beforeEach, afterEach } from "vitest";
|
||||
|
||||
vi.mock("../../src/infra/wsl.js", () => ({
|
||||
isWSL2Sync: () => false,
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/runtime-env", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/runtime-env")>(
|
||||
"openclaw/plugin-sdk/runtime-env",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
isWSL2Sync: () => false,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../src/infra/net/fetch-guard.js", () => ({
|
||||
fetchWithSsrFGuard: async (params: {
|
||||
url: string;
|
||||
init?: RequestInit;
|
||||
fetchImpl?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
||||
}) => {
|
||||
const fetchImpl = params.fetchImpl ?? globalThis.fetch;
|
||||
const response = await fetchImpl(params.url, params.init);
|
||||
return {
|
||||
response,
|
||||
finalUrl: params.url,
|
||||
release: async () => {},
|
||||
};
|
||||
},
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/ssrf-runtime", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/ssrf-runtime")>(
|
||||
"openclaw/plugin-sdk/ssrf-runtime",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
fetchWithSsrFGuard: async (params: {
|
||||
url: string;
|
||||
init?: RequestInit;
|
||||
fetchImpl?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
||||
}) => {
|
||||
const fetchImpl = params.fetchImpl ?? globalThis.fetch;
|
||||
const response = await fetchImpl(params.url, params.init);
|
||||
return {
|
||||
response,
|
||||
finalUrl: params.url,
|
||||
release: async () => {},
|
||||
};
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const mockExistsSync = vi.fn();
|
||||
const mockReadFileSync = vi.fn();
|
||||
|
||||
@@ -12,11 +12,6 @@ vi.mock("../../../test/helpers/config/bundled-channel-config-runtime.js", () =>
|
||||
getBundledChannelConfigSchemaMap: () => new Map(),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
describe("nextcloud talk channel core", () => {
|
||||
it("accepts SecretRef botSecret and apiPassword at top-level", () => {
|
||||
const result = NextcloudTalkConfigSchema.safeParse({
|
||||
|
||||
@@ -27,17 +27,47 @@ const resolveCatalogHookProviderPluginIdsMock = vi.hoisted(() =>
|
||||
vi.fn<ResolveCatalogHookProviderPluginIds>((_) => [] as string[]),
|
||||
);
|
||||
|
||||
vi.mock("../../../src/plugins/providers.js", () => ({
|
||||
resolveOwningPluginIdsForProvider: (params: unknown) =>
|
||||
resolveOwningPluginIdsForProviderMock(params as never),
|
||||
resolveCatalogHookProviderPluginIds: (params: unknown) =>
|
||||
resolveCatalogHookProviderPluginIdsMock(params as never),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/plugins/providers.runtime.js", () => ({
|
||||
isPluginProvidersLoadInFlight: () => false,
|
||||
resolvePluginProviders: (params: unknown) => resolvePluginProvidersMock(params as never),
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/provider-catalog-runtime", async () => {
|
||||
const actual = await vi.importActual<
|
||||
typeof import("openclaw/plugin-sdk/provider-catalog-runtime")
|
||||
>("openclaw/plugin-sdk/provider-catalog-runtime");
|
||||
const resolveCatalogHookProviders = (params: unknown) =>
|
||||
resolvePluginProvidersMock({
|
||||
onlyPluginIds: resolveCatalogHookProviderPluginIdsMock(params),
|
||||
});
|
||||
return {
|
||||
...actual,
|
||||
augmentModelCatalogWithProviderPlugins: async (params: {
|
||||
context: Parameters<NonNullable<ProviderPlugin["augmentModelCatalog"]>>[0];
|
||||
}) => {
|
||||
const supplemental = [];
|
||||
for (const provider of resolveCatalogHookProviders(params)) {
|
||||
const entries = await provider.augmentModelCatalog?.(params.context);
|
||||
if (entries?.length) {
|
||||
supplemental.push(...entries);
|
||||
}
|
||||
}
|
||||
return supplemental;
|
||||
},
|
||||
resolveProviderBuiltInModelSuppression: (params: {
|
||||
context: Parameters<NonNullable<ProviderPlugin["suppressBuiltInModel"]>>[0];
|
||||
}) => {
|
||||
for (const provider of resolveCatalogHookProviders(params)) {
|
||||
const result = provider.suppressBuiltInModel?.(params.context);
|
||||
if (result?.suppress) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
resolveOwningPluginIdsForProvider: (params: unknown) =>
|
||||
resolveOwningPluginIdsForProviderMock(params as never),
|
||||
resolveCatalogHookProviderPluginIds: (params: unknown) =>
|
||||
resolveCatalogHookProviderPluginIdsMock(params as never),
|
||||
isPluginProvidersLoadInFlight: () => false,
|
||||
resolvePluginProviders: (params: unknown) => resolvePluginProvidersMock(params as never),
|
||||
};
|
||||
});
|
||||
|
||||
export function describeOpenAIProviderCatalogContract() {
|
||||
const contractDepsPromise = (async () => {
|
||||
|
||||
@@ -46,10 +46,16 @@ vi.mock("openclaw/plugin-sdk/reply-runtime", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../../../src/pairing/pairing-store.js", () => ({
|
||||
readChannelAllowFromStore: vi.fn().mockResolvedValue([]),
|
||||
upsertChannelPairingRequest: vi.fn(),
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/conversation-runtime", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/conversation-runtime")>(
|
||||
"openclaw/plugin-sdk/conversation-runtime",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
readChannelAllowFromStore: vi.fn().mockResolvedValue([]),
|
||||
upsertChannelPairingRequest: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe("signal createSignalEventHandler inbound context", () => {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -8,28 +8,34 @@ const prepareSlackMessageMock =
|
||||
>();
|
||||
const dispatchPreparedSlackMessageMock = vi.fn<(prepared: unknown) => Promise<void>>();
|
||||
|
||||
vi.mock("../../../../src/channels/inbound-debounce-policy.js", () => ({
|
||||
shouldDebounceTextInbound: () => false,
|
||||
createChannelInboundDebouncer: (params: {
|
||||
onFlush: (
|
||||
entries: Array<{
|
||||
message: Record<string, unknown>;
|
||||
opts: { source: "message" | "app_mention"; wasMentioned?: boolean };
|
||||
}>,
|
||||
) => Promise<void>;
|
||||
}) => ({
|
||||
debounceMs: 0,
|
||||
debouncer: {
|
||||
enqueue: async (entry: {
|
||||
message: Record<string, unknown>;
|
||||
opts: { source: "message" | "app_mention"; wasMentioned?: boolean };
|
||||
}) => {
|
||||
await params.onFlush([entry]);
|
||||
vi.mock("openclaw/plugin-sdk/channel-inbound", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/channel-inbound")>(
|
||||
"openclaw/plugin-sdk/channel-inbound",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
shouldDebounceTextInbound: () => false,
|
||||
createChannelInboundDebouncer: (params: {
|
||||
onFlush: (
|
||||
entries: Array<{
|
||||
message: Record<string, unknown>;
|
||||
opts: { source: "message" | "app_mention"; wasMentioned?: boolean };
|
||||
}>,
|
||||
) => Promise<void>;
|
||||
}) => ({
|
||||
debounceMs: 0,
|
||||
debouncer: {
|
||||
enqueue: async (entry: {
|
||||
message: Record<string, unknown>;
|
||||
opts: { source: "message" | "app_mention"; wasMentioned?: boolean };
|
||||
}) => {
|
||||
await params.onFlush([entry]);
|
||||
},
|
||||
flushKey: async (_key: string) => {},
|
||||
},
|
||||
flushKey: async (_key: string) => {},
|
||||
},
|
||||
}),
|
||||
}));
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./thread-resolution.js", () => ({
|
||||
createSlackThreadTsResolver: () => ({
|
||||
|
||||
@@ -21,15 +21,24 @@ const fetchWithSsrFGuard = vi.fn(
|
||||
}) as const,
|
||||
);
|
||||
|
||||
vi.mock("../../../src/infra/net/fetch-guard.js", () => ({
|
||||
vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({
|
||||
fetchWithSsrFGuard: (...args: unknown[]) =>
|
||||
fetchWithSsrFGuard(...(args as [params: { url: string; init?: RequestInit }])),
|
||||
withTrustedEnvProxyGuardedFetchMode: (params: Record<string, unknown>) => ({
|
||||
...params,
|
||||
mode: "trusted_env_proxy",
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/fetch-runtime", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/fetch-runtime")>(
|
||||
"openclaw/plugin-sdk/fetch-runtime",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
withTrustedEnvProxyGuardedFetchMode: (params: Record<string, unknown>) => ({
|
||||
...params,
|
||||
mode: "trusted_env_proxy",
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./runtime-api.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("./runtime-api.js")>("./runtime-api.js");
|
||||
const mockedLoadOutboundMediaFromUrl =
|
||||
|
||||
@@ -7,32 +7,12 @@ import type { OpenClawConfig } from "../runtime-api.js";
|
||||
import { createTaskFlowWebhookRequestHandler, type TaskFlowWebhookTarget } from "./http.js";
|
||||
|
||||
const hoisted = vi.hoisted(() => {
|
||||
const sendMessageMock = vi.fn();
|
||||
const cancelSessionMock = vi.fn();
|
||||
const killSubagentRunAdminMock = vi.fn();
|
||||
const resolveConfiguredSecretInputStringMock = vi.fn();
|
||||
return {
|
||||
sendMessageMock,
|
||||
cancelSessionMock,
|
||||
killSubagentRunAdminMock,
|
||||
resolveConfiguredSecretInputStringMock,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../../src/tasks/task-registry-delivery-runtime.js", () => ({
|
||||
sendMessage: hoisted.sendMessageMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/acp/control-plane/manager.js", () => ({
|
||||
getAcpSessionManager: () => ({
|
||||
cancelSession: hoisted.cancelSessionMock,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/agents/subagent-control.js", () => ({
|
||||
killSubagentRunAdmin: (params: unknown) => hoisted.killSubagentRunAdminMock(params),
|
||||
}));
|
||||
|
||||
vi.mock("../runtime-api.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../runtime-api.js")>();
|
||||
hoisted.resolveConfiguredSecretInputStringMock.mockImplementation(
|
||||
|
||||
@@ -49,8 +49,12 @@ vi.mock("openclaw/plugin-sdk/runtime-config-snapshot", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../../src/pairing/pairing-store.js", () => {
|
||||
vi.mock("openclaw/plugin-sdk/conversation-runtime", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/conversation-runtime")>(
|
||||
"openclaw/plugin-sdk/conversation-runtime",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
readChannelAllowFromStore(...args: unknown[]) {
|
||||
return readAllowFromStoreMock(...args);
|
||||
},
|
||||
@@ -60,6 +64,18 @@ vi.mock("../../../src/pairing/pairing-store.js", () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/channel-pairing", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/channel-pairing")>(
|
||||
"openclaw/plugin-sdk/channel-pairing",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
readChannelAllowFromStore(...args: unknown[]) {
|
||||
return readAllowFromStoreMock(...args);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/media-store", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/media-store")>(
|
||||
"openclaw/plugin-sdk/media-store",
|
||||
|
||||
@@ -6,9 +6,15 @@ const hoisted = vi.hoisted(() => ({
|
||||
sendReactionWhatsApp: vi.fn(async () => undefined),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/globals.js", () => ({
|
||||
shouldLogVerbose: () => false,
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/runtime-env", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/runtime-env")>(
|
||||
"openclaw/plugin-sdk/runtime-env",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
shouldLogVerbose: () => false,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./send.js", () => ({
|
||||
sendPollWhatsApp: hoisted.sendPollWhatsApp,
|
||||
|
||||
@@ -1162,6 +1162,10 @@
|
||||
"types": "./dist/plugin-sdk/plugin-entry.d.ts",
|
||||
"default": "./dist/plugin-sdk/plugin-entry.js"
|
||||
},
|
||||
"./plugin-sdk/provider-catalog-runtime": {
|
||||
"types": "./dist/plugin-sdk/provider-catalog-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/provider-catalog-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/provider-catalog-shared": {
|
||||
"types": "./dist/plugin-sdk/provider-catalog-shared.d.ts",
|
||||
"default": "./dist/plugin-sdk/provider-catalog-shared.js"
|
||||
|
||||
@@ -37,6 +37,8 @@ const FORBIDDEN_PATTERNS: Array<{ pattern: RegExp; hint: string }> = [
|
||||
|
||||
const STATIC_RELATIVE_MODULE_PATTERN = /\b(?:import|export)\b[\s\S]*?\bfrom\s*["']([^"']+)["']/g;
|
||||
const DYNAMIC_RELATIVE_MODULE_PATTERN = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
|
||||
const MOCK_RELATIVE_MODULE_PATTERN =
|
||||
/\bvi\.(?:mock|doMock|unmock|doUnmock)\s*\(\s*["']([^"']+)["']/g;
|
||||
|
||||
const RELATIVE_CORE_HINT =
|
||||
"Use openclaw/plugin-sdk/testing or a focused plugin-sdk test/runtime subpath instead of core internals.";
|
||||
@@ -88,6 +90,7 @@ function collectRelativeCoreImportOffenders(
|
||||
const matches = [
|
||||
...content.matchAll(STATIC_RELATIVE_MODULE_PATTERN),
|
||||
...(opts.includeDynamic ? [...content.matchAll(DYNAMIC_RELATIVE_MODULE_PATTERN)] : []),
|
||||
...content.matchAll(MOCK_RELATIVE_MODULE_PATTERN),
|
||||
];
|
||||
for (const match of matches) {
|
||||
const specifier = match[1];
|
||||
|
||||
@@ -274,6 +274,7 @@
|
||||
"provider-auth-login",
|
||||
"provider-selection-runtime",
|
||||
"plugin-entry",
|
||||
"provider-catalog-runtime",
|
||||
"provider-catalog-shared",
|
||||
"provider-entry",
|
||||
"provider-env-vars",
|
||||
|
||||
15
src/plugin-sdk/provider-catalog-runtime.ts
Normal file
15
src/plugin-sdk/provider-catalog-runtime.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
// Public provider-catalog runtime seams for provider plugin contract tests.
|
||||
|
||||
export {
|
||||
augmentModelCatalogWithProviderPlugins,
|
||||
resetProviderRuntimeHookCacheForTest,
|
||||
resolveProviderBuiltInModelSuppression,
|
||||
} from "../plugins/provider-runtime.js";
|
||||
export {
|
||||
resolveCatalogHookProviderPluginIds,
|
||||
resolveOwningPluginIdsForProvider,
|
||||
} from "../plugins/providers.js";
|
||||
export {
|
||||
isPluginProvidersLoadInFlight,
|
||||
resolvePluginProviders,
|
||||
} from "../plugins/providers.runtime.js";
|
||||
@@ -11,7 +11,7 @@ export {
|
||||
} from "../../../src/test-utils/bundled-plugin-public-surface.js";
|
||||
|
||||
type ProviderRuntimeCatalogModule = Pick<
|
||||
typeof import("../../../src/plugins/provider-runtime.js"),
|
||||
typeof import("openclaw/plugin-sdk/provider-catalog-runtime"),
|
||||
| "augmentModelCatalogWithProviderPlugins"
|
||||
| "resetProviderRuntimeHookCacheForTest"
|
||||
| "resolveProviderBuiltInModelSuppression"
|
||||
@@ -22,7 +22,7 @@ export async function importProviderRuntimeCatalogModule(): Promise<ProviderRunt
|
||||
augmentModelCatalogWithProviderPlugins,
|
||||
resetProviderRuntimeHookCacheForTest,
|
||||
resolveProviderBuiltInModelSuppression,
|
||||
} = await import("../../../src/plugins/provider-runtime.js");
|
||||
} = await import("openclaw/plugin-sdk/provider-catalog-runtime");
|
||||
return {
|
||||
augmentModelCatalogWithProviderPlugins,
|
||||
resetProviderRuntimeHookCacheForTest,
|
||||
|
||||
Reference in New Issue
Block a user