mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:20:43 +00:00
test: merge provider contract wrappers
This commit is contained in:
@@ -18,14 +18,34 @@ import {
|
||||
normalizeOptionalStringifiedId,
|
||||
} from "openclaw/plugin-sdk/text-runtime";
|
||||
import type { DiscordComponentMessageSpec } from "./components.js";
|
||||
import { getThreadBindingManager, type ThreadBindingRecord } from "./monitor/thread-bindings.js";
|
||||
import type { ThreadBindingRecord } from "./monitor/thread-bindings.js";
|
||||
import { normalizeDiscordOutboundTarget } from "./normalize.js";
|
||||
import { sendDiscordComponentMessage } from "./send.components.js";
|
||||
import { sendMessageDiscord, sendPollDiscord, sendWebhookMessageDiscord } from "./send.js";
|
||||
import { buildDiscordInteractiveComponents } from "./shared-interactive.js";
|
||||
|
||||
export const DISCORD_TEXT_CHUNK_LIMIT = 2000;
|
||||
|
||||
type DiscordSendRuntime = typeof import("./send.js");
|
||||
type DiscordSendFn = DiscordSendRuntime["sendMessageDiscord"];
|
||||
type DiscordComponentSendFn = typeof import("./send.components.js").sendDiscordComponentMessage;
|
||||
|
||||
let discordSendRuntimePromise: Promise<DiscordSendRuntime> | undefined;
|
||||
let discordComponentSendPromise: Promise<DiscordComponentSendFn> | undefined;
|
||||
|
||||
async function loadDiscordSendRuntime(): Promise<DiscordSendRuntime> {
|
||||
discordSendRuntimePromise ??= import("./send.js");
|
||||
return await discordSendRuntimePromise;
|
||||
}
|
||||
|
||||
async function sendDiscordComponentMessageLazy(
|
||||
...args: Parameters<DiscordComponentSendFn>
|
||||
): ReturnType<DiscordComponentSendFn> {
|
||||
discordComponentSendPromise ??= import("./send.components.js").then(
|
||||
(module) => module.sendDiscordComponentMessage,
|
||||
);
|
||||
return await (
|
||||
await discordComponentSendPromise
|
||||
)(...args);
|
||||
}
|
||||
|
||||
function hasApprovalChannelData(payload: { channelData?: unknown }): boolean {
|
||||
const channelData = payload.channelData;
|
||||
if (!channelData || typeof channelData !== "object" || Array.isArray(channelData)) {
|
||||
@@ -93,6 +113,7 @@ async function maybeSendDiscordWebhookText(params: {
|
||||
if (!threadId) {
|
||||
return null;
|
||||
}
|
||||
const { getThreadBindingManager } = await import("./monitor/thread-bindings.js");
|
||||
const manager = getThreadBindingManager(params.accountId ?? undefined);
|
||||
if (!manager) {
|
||||
return null;
|
||||
@@ -105,6 +126,7 @@ async function maybeSendDiscordWebhookText(params: {
|
||||
identity: params.identity,
|
||||
binding,
|
||||
});
|
||||
const { sendWebhookMessageDiscord } = await loadDiscordSendRuntime();
|
||||
const result = await sendWebhookMessageDiscord(params.text, {
|
||||
webhookId: binding.webhookId,
|
||||
webhookToken: binding.webhookToken,
|
||||
@@ -134,7 +156,12 @@ export const discordOutbound: ChannelOutboundAdapter = {
|
||||
| { components?: DiscordComponentMessageSpec }
|
||||
| undefined;
|
||||
const rawComponentSpec =
|
||||
discordData?.components ?? buildDiscordInteractiveComponents(payload.interactive);
|
||||
discordData?.components ??
|
||||
(payload.interactive
|
||||
? (await import("./shared-interactive.js")).buildDiscordInteractiveComponents(
|
||||
payload.interactive,
|
||||
)
|
||||
: undefined);
|
||||
const componentSpec = rawComponentSpec
|
||||
? rawComponentSpec.text
|
||||
? rawComponentSpec
|
||||
@@ -154,7 +181,8 @@ export const discordOutbound: ChannelOutboundAdapter = {
|
||||
});
|
||||
}
|
||||
const send =
|
||||
resolveOutboundSendDep<typeof sendMessageDiscord>(ctx.deps, "discord") ?? sendMessageDiscord;
|
||||
resolveOutboundSendDep<DiscordSendFn>(ctx.deps, "discord") ??
|
||||
(await loadDiscordSendRuntime()).sendMessageDiscord;
|
||||
const target = resolveDiscordOutboundTarget({ to: ctx.to, threadId: ctx.threadId });
|
||||
const mediaUrls = resolvePayloadMediaUrls(payload);
|
||||
const result = await sendPayloadMediaSequenceOrFallback({
|
||||
@@ -162,7 +190,7 @@ export const discordOutbound: ChannelOutboundAdapter = {
|
||||
mediaUrls,
|
||||
fallbackResult: { messageId: "", channelId: target },
|
||||
sendNoMedia: async () =>
|
||||
await sendDiscordComponentMessage(target, componentSpec, {
|
||||
await sendDiscordComponentMessageLazy(target, componentSpec, {
|
||||
replyTo: ctx.replyToId ?? undefined,
|
||||
accountId: ctx.accountId ?? undefined,
|
||||
silent: ctx.silent ?? undefined,
|
||||
@@ -170,7 +198,7 @@ export const discordOutbound: ChannelOutboundAdapter = {
|
||||
}),
|
||||
send: async ({ text, mediaUrl, isFirst }) => {
|
||||
if (isFirst) {
|
||||
return await sendDiscordComponentMessage(target, componentSpec, {
|
||||
return await sendDiscordComponentMessageLazy(target, componentSpec, {
|
||||
mediaUrl,
|
||||
mediaAccess: ctx.mediaAccess,
|
||||
mediaLocalRoots: ctx.mediaLocalRoots,
|
||||
@@ -213,7 +241,8 @@ export const discordOutbound: ChannelOutboundAdapter = {
|
||||
}
|
||||
}
|
||||
const send =
|
||||
resolveOutboundSendDep<typeof sendMessageDiscord>(deps, "discord") ?? sendMessageDiscord;
|
||||
resolveOutboundSendDep<DiscordSendFn>(deps, "discord") ??
|
||||
(await loadDiscordSendRuntime()).sendMessageDiscord;
|
||||
return await send(resolveDiscordOutboundTarget({ to, threadId }), text, {
|
||||
verbose: false,
|
||||
replyTo: replyToId ?? undefined,
|
||||
@@ -236,7 +265,8 @@ export const discordOutbound: ChannelOutboundAdapter = {
|
||||
silent,
|
||||
}) => {
|
||||
const send =
|
||||
resolveOutboundSendDep<typeof sendMessageDiscord>(deps, "discord") ?? sendMessageDiscord;
|
||||
resolveOutboundSendDep<DiscordSendFn>(deps, "discord") ??
|
||||
(await loadDiscordSendRuntime()).sendMessageDiscord;
|
||||
return await send(resolveDiscordOutboundTarget({ to, threadId }), text, {
|
||||
verbose: false,
|
||||
mediaUrl,
|
||||
@@ -249,7 +279,9 @@ export const discordOutbound: ChannelOutboundAdapter = {
|
||||
});
|
||||
},
|
||||
sendPoll: async ({ cfg, to, poll, accountId, threadId, silent }) =>
|
||||
await sendPollDiscord(resolveDiscordOutboundTarget({ to, threadId }), poll, {
|
||||
await (
|
||||
await loadDiscordSendRuntime()
|
||||
).sendPollDiscord(resolveDiscordOutboundTarget({ to, threadId }), poll, {
|
||||
accountId: accountId ?? undefined,
|
||||
silent: silent ?? undefined,
|
||||
cfg,
|
||||
|
||||
@@ -5,6 +5,8 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
const SRC_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const REPO_ROOT = resolve(SRC_ROOT, "..");
|
||||
const sourceCache = new Map<string, string>();
|
||||
const tsFilesCache = new Map<string, string[]>();
|
||||
|
||||
const ALLOWED_BUNDLED_CAPABILITY_METADATA_CONSUMERS = new Set([
|
||||
"src/media-generation/provider-capabilities.contract.test.ts",
|
||||
@@ -39,6 +41,11 @@ type FileFilter = {
|
||||
};
|
||||
|
||||
function listTsFiles(rootRelativePath: string, filter: FileFilter = {}): string[] {
|
||||
const cacheKey = `${rootRelativePath}:${filter.excludeTests ? "exclude-tests" : ""}:${filter.testOnly ? "test-only" : ""}`;
|
||||
const cached = tsFilesCache.get(cacheKey);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const root = resolve(REPO_ROOT, rootRelativePath);
|
||||
const files: string[] = [];
|
||||
|
||||
@@ -64,7 +71,19 @@ function listTsFiles(rootRelativePath: string, filter: FileFilter = {}): string[
|
||||
}
|
||||
|
||||
walk(root);
|
||||
return files.toSorted();
|
||||
const sorted = files.toSorted();
|
||||
tsFilesCache.set(cacheKey, sorted);
|
||||
return sorted;
|
||||
}
|
||||
|
||||
function readRepoSource(file: string): string {
|
||||
const cached = sourceCache.get(file);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
|
||||
sourceCache.set(file, source);
|
||||
return source;
|
||||
}
|
||||
|
||||
describe("plugin contract boundary invariants", () => {
|
||||
@@ -74,8 +93,7 @@ describe("plugin contract boundary invariants", () => {
|
||||
if (ALLOWED_BUNDLED_CAPABILITY_METADATA_CONSUMERS.has(file)) {
|
||||
return false;
|
||||
}
|
||||
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
|
||||
return source.includes("contracts/inventory/bundled-capability-metadata");
|
||||
return readRepoSource(file).includes("contracts/inventory/bundled-capability-metadata");
|
||||
});
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
@@ -83,8 +101,7 @@ describe("plugin contract boundary invariants", () => {
|
||||
it("keeps the bundled contract inventory out of non-test runtime code", () => {
|
||||
const files = listTsFiles("src", { excludeTests: true });
|
||||
const offenders = files.filter((file) => {
|
||||
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
|
||||
return source.includes("contracts/inventory/bundled-capability-metadata");
|
||||
return readRepoSource(file).includes("contracts/inventory/bundled-capability-metadata");
|
||||
});
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
@@ -95,7 +112,7 @@ describe("plugin contract boundary invariants", () => {
|
||||
if (ALLOWED_EXTENSION_PATH_STRING_TESTS.has(file)) {
|
||||
return false;
|
||||
}
|
||||
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
|
||||
const source = readRepoSource(file);
|
||||
return (
|
||||
/from\s+["'][^"']*extensions\/.+(?:api|runtime-api|test-api)\.js["']/u.test(source) ||
|
||||
/vi\.(?:mock|doMock)\(\s*["'][^"']*extensions\/.+["']/u.test(source) ||
|
||||
@@ -111,8 +128,7 @@ describe("plugin contract boundary invariants", () => {
|
||||
if (ALLOWED_CONTRACT_BUNDLED_PATH_HELPERS.has(file)) {
|
||||
return false;
|
||||
}
|
||||
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
|
||||
return source.includes("test/helpers/bundled-plugin-paths");
|
||||
return readRepoSource(file).includes("test/helpers/bundled-plugin-paths");
|
||||
});
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
@@ -123,8 +139,7 @@ describe("plugin contract boundary invariants", () => {
|
||||
if (ALLOWED_CHANNEL_BUNDLED_METADATA_CONSUMERS.has(file)) {
|
||||
return false;
|
||||
}
|
||||
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
|
||||
return source.includes("plugins/bundled-plugin-metadata");
|
||||
return readRepoSource(file).includes("plugins/bundled-plugin-metadata");
|
||||
});
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
@@ -135,7 +150,7 @@ describe("plugin contract boundary invariants", () => {
|
||||
...listTsFiles("src/channels", { excludeTests: true }),
|
||||
].toSorted();
|
||||
const offenders = files.filter((file) => {
|
||||
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
|
||||
const source = readRepoSource(file);
|
||||
return /extensions\/\$\{|\.\.\/\.\.\/\.\.\/\.\.\/extensions\//u.test(source);
|
||||
});
|
||||
expect(offenders).toEqual([]);
|
||||
|
||||
@@ -49,6 +49,7 @@ const SRC_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const REPO_ROOT = resolve(SRC_ROOT, "..");
|
||||
const PLUGIN_SDK_DIR = resolve(SRC_ROOT, "plugin-sdk");
|
||||
const sourceCache = new Map<string, string>();
|
||||
const repoTsFilesCache = new Map<string, string[]>();
|
||||
const representativeRuntimeSmokeSubpaths = ["channel-runtime", "conversation-runtime"] as const;
|
||||
|
||||
const importResolvedPluginSdkSubpath = async (specifier: string) => import(specifier);
|
||||
@@ -226,8 +227,12 @@ function expectNamedExportParity(params: BrowserHelperExportParityContract) {
|
||||
}
|
||||
|
||||
function listRepoTsFiles(dir: string): string[] {
|
||||
const cached = repoTsFilesCache.get(dir);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const entries = readdirSync(dir, { withFileTypes: true });
|
||||
return entries.flatMap((entry) => {
|
||||
const files = entries.flatMap((entry) => {
|
||||
const absolute = resolve(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
if (entry.name === "dist" || entry.name === "node_modules") {
|
||||
@@ -240,6 +245,8 @@ function listRepoTsFiles(dir: string): string[] {
|
||||
}
|
||||
return absolute.endsWith(".ts") ? [absolute] : [];
|
||||
});
|
||||
repoTsFilesCache.set(dir, files);
|
||||
return files;
|
||||
}
|
||||
|
||||
function findRepoFilesContaining(params: {
|
||||
@@ -253,7 +260,7 @@ function findRepoFilesContaining(params: {
|
||||
.flatMap((root) => listRepoTsFiles(root))
|
||||
.filter((file) => !excluded.has(file))
|
||||
.filter((file) => !(params.excludeFilesMatching ?? []).some((pattern) => pattern.test(file)))
|
||||
.filter((file) => params.pattern.test(readFileSync(file, "utf8")))
|
||||
.filter((file) => params.pattern.test(readCachedSource(file)))
|
||||
.map((file) => file.slice(REPO_ROOT.length + 1))
|
||||
.toSorted();
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
|
||||
describeProviderContracts("anthropic");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
|
||||
describeProviderContracts("fal");
|
||||
@@ -1,5 +0,0 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeProviderContracts("google");
|
||||
describeWebSearchProviderContracts("google");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
|
||||
describeProviderContracts("minimax");
|
||||
@@ -1,5 +0,0 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeProviderContracts("moonshot");
|
||||
describeWebSearchProviderContracts("moonshot");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
|
||||
describeProviderContracts("openai");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
|
||||
describeProviderContracts("openrouter");
|
||||
@@ -1,5 +0,0 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeProviderContracts("xai");
|
||||
describeWebSearchProviderContracts("xai");
|
||||
29
src/plugins/contracts/providers.contract.test.ts
Normal file
29
src/plugins/contracts/providers.contract.test.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { describeProviderContracts } from "../../../test/helpers/plugins/provider-contract.js";
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
for (const providerId of [
|
||||
"anthropic",
|
||||
"fal",
|
||||
"google",
|
||||
"minimax",
|
||||
"moonshot",
|
||||
"openai",
|
||||
"openrouter",
|
||||
"xai",
|
||||
] as const) {
|
||||
describeProviderContracts(providerId);
|
||||
}
|
||||
|
||||
for (const providerId of [
|
||||
"brave",
|
||||
"duckduckgo",
|
||||
"exa",
|
||||
"firecrawl",
|
||||
"google",
|
||||
"moonshot",
|
||||
"perplexity",
|
||||
"tavily",
|
||||
"xai",
|
||||
] as const) {
|
||||
describeWebSearchProviderContracts(providerId);
|
||||
}
|
||||
@@ -64,13 +64,6 @@ describe("runtime import side-effect contracts", () => {
|
||||
getActivePluginChannelRegistryVersion.mockClear().mockReturnValue(1);
|
||||
});
|
||||
|
||||
it("keeps config/markdown-tables cold on import", async () => {
|
||||
mockChannelRegistry();
|
||||
await import("../../config/markdown-tables.js");
|
||||
|
||||
expectNoChannelRegistryDuringImport("src/config/markdown-tables.ts");
|
||||
});
|
||||
|
||||
it("keeps markdown table defaults lazy and memoized after import", async () => {
|
||||
mockChannelRegistry();
|
||||
const markdownTables = await import("../../config/markdown-tables.js");
|
||||
@@ -85,52 +78,26 @@ describe("runtime import side-effect contracts", () => {
|
||||
expect(listChannelPlugins).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("keeps plugins/runtime/runtime-channel cold on import", async () => {
|
||||
it("keeps hot runtime imports cold", async () => {
|
||||
mockChannelRegistry();
|
||||
await import("../runtime/runtime-channel.js");
|
||||
|
||||
expectNoChannelRegistryDuringImport("src/plugins/runtime/runtime-channel.ts");
|
||||
});
|
||||
|
||||
it("keeps plugin-sdk/approval-handler-adapter-runtime cold on import", async () => {
|
||||
mockChannelRegistry();
|
||||
await import("../../plugin-sdk/approval-handler-adapter-runtime.js");
|
||||
|
||||
expectNoChannelRegistryDuringImport("src/plugin-sdk/approval-handler-adapter-runtime.ts");
|
||||
});
|
||||
|
||||
it("keeps plugin-sdk/approval-gateway-runtime cold on import", async () => {
|
||||
mockChannelRegistry();
|
||||
await import("../../plugin-sdk/approval-gateway-runtime.js");
|
||||
|
||||
expectNoChannelRegistryDuringImport("src/plugin-sdk/approval-gateway-runtime.ts");
|
||||
});
|
||||
|
||||
it("keeps plugins/runtime/runtime-system cold on import", async () => {
|
||||
mockChannelRegistry();
|
||||
await import("../runtime/runtime-system.js");
|
||||
|
||||
expectNoChannelRegistryDuringImport("src/plugins/runtime/runtime-system.ts");
|
||||
});
|
||||
|
||||
it("keeps web-search/runtime cold on import", async () => {
|
||||
mockChannelRegistry();
|
||||
await import("../../web-search/runtime.js");
|
||||
|
||||
expectNoChannelRegistryDuringImport("src/web-search/runtime.ts");
|
||||
});
|
||||
|
||||
it("keeps web-fetch/runtime cold on import", async () => {
|
||||
mockChannelRegistry();
|
||||
await import("../../web-fetch/runtime.js");
|
||||
|
||||
expectNoChannelRegistryDuringImport("src/web-fetch/runtime.ts");
|
||||
});
|
||||
|
||||
it("keeps plugins/runtime/index cold on import", async () => {
|
||||
mockChannelRegistry();
|
||||
await import("../runtime/index.js");
|
||||
|
||||
expectNoChannelRegistryDuringImport("src/plugins/runtime/index.ts");
|
||||
for (const [moduleId, importModule] of [
|
||||
["src/config/markdown-tables.ts", () => import("../../config/markdown-tables.js")],
|
||||
["src/plugins/runtime/runtime-channel.ts", () => import("../runtime/runtime-channel.js")],
|
||||
[
|
||||
"src/plugin-sdk/approval-handler-adapter-runtime.ts",
|
||||
() => import("../../plugin-sdk/approval-handler-adapter-runtime.js"),
|
||||
],
|
||||
[
|
||||
"src/plugin-sdk/approval-gateway-runtime.ts",
|
||||
() => import("../../plugin-sdk/approval-gateway-runtime.js"),
|
||||
],
|
||||
["src/plugins/runtime/runtime-system.ts", () => import("../runtime/runtime-system.js")],
|
||||
["src/web-search/runtime.ts", () => import("../../web-search/runtime.js")],
|
||||
["src/web-fetch/runtime.ts", () => import("../../web-fetch/runtime.js")],
|
||||
["src/plugins/runtime/index.ts", () => import("../runtime/index.js")],
|
||||
] as const) {
|
||||
await importModule();
|
||||
expectNoChannelRegistryDuringImport(moduleId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeTtsAutoApplyContract } from "../../../test/helpers/plugins/tts-contract-suites.js";
|
||||
|
||||
describeTtsAutoApplyContract();
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeTtsConfigContract } from "../../../test/helpers/plugins/tts-contract-suites.js";
|
||||
|
||||
describeTtsConfigContract();
|
||||
11
src/plugins/contracts/tts.contract.test.ts
Normal file
11
src/plugins/contracts/tts.contract.test.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import {
|
||||
describeTtsAutoApplyContract,
|
||||
describeTtsConfigContract,
|
||||
describeTtsProviderRuntimeContract,
|
||||
describeTtsSummarizationContract,
|
||||
} from "../../../test/helpers/plugins/tts-contract-suites.js";
|
||||
|
||||
describeTtsAutoApplyContract();
|
||||
describeTtsConfigContract();
|
||||
describeTtsProviderRuntimeContract();
|
||||
describeTtsSummarizationContract();
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeTtsProviderRuntimeContract } from "../../../test/helpers/plugins/tts-contract-suites.js";
|
||||
|
||||
describeTtsProviderRuntimeContract();
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeTtsSummarizationContract } from "../../../test/helpers/plugins/tts-contract-suites.js";
|
||||
|
||||
describeTtsSummarizationContract();
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeWebSearchProviderContracts("brave");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeWebSearchProviderContracts("duckduckgo");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeWebSearchProviderContracts("exa");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeWebSearchProviderContracts("firecrawl");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeWebSearchProviderContracts("perplexity");
|
||||
@@ -1,3 +0,0 @@
|
||||
import { describeWebSearchProviderContracts } from "../../../test/helpers/plugins/web-search-provider-contract.js";
|
||||
|
||||
describeWebSearchProviderContracts("tavily");
|
||||
Reference in New Issue
Block a user