mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 19:50:43 +00:00
refactor: move plugin contracts onto SDK testing seams
This commit is contained in:
@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- Channels/QQBot: add full group chat support (history tracking, @-mention gating, activation modes, per-group config, FIFO message queue with deliver debounce), C2C `stream_messages` streaming with a `StreamingController` lifecycle manager, unified `sendMedia` with chunked upload for large files, and refactor the engine into pipeline stages, focused outbound submodules, builtin slash-command modules, and explicit DI ports via `createEngineAdapters()`. (#70624) Thanks @cxyhhhhh.
|
- Channels/QQBot: add full group chat support (history tracking, @-mention gating, activation modes, per-group config, FIFO message queue with deliver debounce), C2C `stream_messages` streaming with a `StreamingController` lifecycle manager, unified `sendMedia` with chunked upload for large files, and refactor the engine into pipeline stages, focused outbound submodules, builtin slash-command modules, and explicit DI ports via `createEngineAdapters()`. (#70624) Thanks @cxyhhhhh.
|
||||||
- Gateway/runtime: reuse the current plugin metadata snapshot for provider discovery so repeated model-provider discovery avoids rebuilding plugin manifest metadata. Thanks @shakkernerd.
|
- Gateway/runtime: reuse the current plugin metadata snapshot for provider discovery so repeated model-provider discovery avoids rebuilding plugin manifest metadata. Thanks @shakkernerd.
|
||||||
- Gateway/startup: pass the plugin metadata snapshot from config validation into plugin bootstrap so startup reuses one manifest product instead of rebuilding plugin metadata. Thanks @shakkernerd.
|
- Gateway/startup: pass the plugin metadata snapshot from config validation into plugin bootstrap so startup reuses one manifest product instead of rebuilding plugin metadata. Thanks @shakkernerd.
|
||||||
|
- Plugin SDK/testing: expose provider catalog, wizard, registry, manifest, public-artifact, outbound, and TTS contract helpers through documented SDK testing seams so bundled plugin tests no longer import repo `src/**` internals. Thanks @vincentkoc.
|
||||||
- Matrix: attach versioned structured approval metadata to pending approval messages so capable Matrix clients can render richer approval UI while body text and reaction fallback keep working. (#72432) Thanks @kakahu2015.
|
- Matrix: attach versioned structured approval metadata to pending approval messages so capable Matrix clients can render richer approval UI while body text and reaction fallback keep working. (#72432) Thanks @kakahu2015.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
af72813b59c6f35912bb5eacb01365d7686e3b2ca4c8813f7582de10c5da3c81 plugin-sdk-api-baseline.json
|
7a2039df8cfdcfea0fbc82bbe425c96631ab27b2210c932c6e3f17d380aff350 plugin-sdk-api-baseline.json
|
||||||
71603527acce8f5e1112a035dad6def83c0b02afd831b288fb655f83f8cb3bd1 plugin-sdk-api-baseline.jsonl
|
ea9f134bc2a1aa17e8abf8f1335daaa927b2272c972523b9d0bd05bf4ac8e149 plugin-sdk-api-baseline.jsonl
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
|
|||||||
| `plugin-sdk/core` | `defineChannelPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase`, `defineSetupPluginEntry`, `buildChannelConfigSchema` |
|
| `plugin-sdk/core` | `defineChannelPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase`, `defineSetupPluginEntry`, `buildChannelConfigSchema` |
|
||||||
| `plugin-sdk/config-schema` | `OpenClawSchema` |
|
| `plugin-sdk/config-schema` | `OpenClawSchema` |
|
||||||
| `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` |
|
| `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` |
|
||||||
|
| `plugin-sdk/testing` | Public plugin test fixtures, provider registration/catalog helpers, wizard contract hooks, and bundled-plugin contract maintenance helpers |
|
||||||
| `plugin-sdk/migration` | Migration provider item helpers such as `createMigrationItem`, reason constants, item status markers, redaction helpers, and `summarizeMigrationItems` |
|
| `plugin-sdk/migration` | Migration provider item helpers such as `createMigrationItem`, reason constants, item status markers, redaction helpers, and `summarizeMigrationItems` |
|
||||||
| `plugin-sdk/migration-runtime` | Runtime migration helpers such as `copyMigrationFileItem` and `writeMigrationReport` |
|
| `plugin-sdk/migration-runtime` | Runtime migration helpers such as `copyMigrationFileItem` and `writeMigrationReport` |
|
||||||
|
|
||||||
|
|||||||
@@ -33,29 +33,40 @@ import {
|
|||||||
|
|
||||||
### Available exports
|
### Available exports
|
||||||
|
|
||||||
| Export | Purpose |
|
| Export | Purpose |
|
||||||
| -------------------------------------- | ------------------------------------------------------ |
|
| ------------------------------------------- | ------------------------------------------------------- |
|
||||||
| `installCommonResolveTargetErrorCases` | Shared test cases for target resolution error handling |
|
| `installCommonResolveTargetErrorCases` | Shared test cases for target resolution error handling |
|
||||||
| `shouldAckReaction` | Check whether a channel should add an ack reaction |
|
| `shouldAckReaction` | Check whether a channel should add an ack reaction |
|
||||||
| `removeAckReactionAfterReply` | Remove ack reaction after reply delivery |
|
| `removeAckReactionAfterReply` | Remove ack reaction after reply delivery |
|
||||||
| `createTestRegistry` | Build a channel plugin registry fixture |
|
| `createTestRegistry` | Build a channel plugin registry fixture |
|
||||||
| `createEmptyPluginRegistry` | Build an empty plugin registry fixture |
|
| `createEmptyPluginRegistry` | Build an empty plugin registry fixture |
|
||||||
| `setActivePluginRegistry` | Install a registry fixture for plugin runtime tests |
|
| `setActivePluginRegistry` | Install a registry fixture for plugin runtime tests |
|
||||||
| `createRequestCaptureJsonFetch` | Capture JSON fetch requests in media helper tests |
|
| `createRequestCaptureJsonFetch` | Capture JSON fetch requests in media helper tests |
|
||||||
| `withFetchPreconnect` | Run fetch tests with preconnect hooks installed |
|
| `withFetchPreconnect` | Run fetch tests with preconnect hooks installed |
|
||||||
| `withEnv` / `withEnvAsync` | Temporarily patch environment variables |
|
| `withEnv` / `withEnvAsync` | Temporarily patch environment variables |
|
||||||
| `createTempHomeEnv` / `withTempDir` | Create isolated filesystem test fixtures |
|
| `createTempHomeEnv` / `withTempDir` | Create isolated filesystem test fixtures |
|
||||||
| `createMockServerResponse` | Create a minimal HTTP server response mock |
|
| `createMockServerResponse` | Create a minimal HTTP server response mock |
|
||||||
| `registerSingleProviderPlugin` | Register one provider plugin in loader smoke tests |
|
| `registerSingleProviderPlugin` | Register one provider plugin in loader smoke tests |
|
||||||
| `registerProviderPlugin` | Capture all provider kinds from one plugin |
|
| `registerProviderPlugin` | Capture all provider kinds from one plugin |
|
||||||
| `requireRegisteredProvider` | Assert that a provider collection contains an id |
|
| `registerProviderPlugins` | Capture provider registrations across multiple plugins |
|
||||||
| `createProviderUsageFetch` | Build provider usage fetch fixtures |
|
| `requireRegisteredProvider` | Assert that a provider collection contains an id |
|
||||||
| `useFrozenTime` / `useRealTime` | Freeze and restore timers for time-sensitive tests |
|
| `runProviderCatalog` | Execute a provider catalog hook with test dependencies |
|
||||||
| `createRuntimeEnv` | Build a mocked CLI/plugin runtime environment |
|
| `resolveProviderWizardOptions` | Resolve provider setup wizard choices in contract tests |
|
||||||
| `createTestWizardPrompter` | Build a mocked setup wizard prompter |
|
| `resolveProviderModelPickerEntries` | Resolve provider model-picker entries in contract tests |
|
||||||
| `createPluginSetupWizardStatus` | Build setup status helpers for channel plugins |
|
| `buildProviderPluginMethodChoice` | Build provider wizard choice ids for assertions |
|
||||||
| `createRuntimeTaskFlow` | Create isolated runtime task-flow state |
|
| `setProviderWizardProvidersResolverForTest` | Inject provider wizard providers for isolated tests |
|
||||||
| `typedCases` | Preserve literal types for table-driven tests |
|
| `createProviderUsageFetch` | Build provider usage fetch fixtures |
|
||||||
|
| `useFrozenTime` / `useRealTime` | Freeze and restore timers for time-sensitive tests |
|
||||||
|
| `createRuntimeEnv` | Build a mocked CLI/plugin runtime environment |
|
||||||
|
| `createTestWizardPrompter` | Build a mocked setup wizard prompter |
|
||||||
|
| `createPluginSetupWizardStatus` | Build setup status helpers for channel plugins |
|
||||||
|
| `createRuntimeTaskFlow` | Create isolated runtime task-flow state |
|
||||||
|
| `typedCases` | Preserve literal types for table-driven tests |
|
||||||
|
|
||||||
|
Bundled-plugin contract suites also use this subpath for test-only registry,
|
||||||
|
manifest, public-artifact, and runtime fixture helpers. Keep new extension tests
|
||||||
|
on `openclaw/plugin-sdk/testing` or a narrower documented SDK subpath rather
|
||||||
|
than importing repo `src/**` files directly.
|
||||||
|
|
||||||
### Types
|
### Types
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,12 @@
|
|||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export type { DmPolicy, GroupPolicy } from "../config/types.js";
|
export type { DmPolicy, GroupPolicy } from "../config/types.js";
|
||||||
export type { SecretInput } from "../config/types.secrets.js";
|
export type { SecretInput } from "../config/types.secrets.js";
|
||||||
export type { WizardPrompter } from "../wizard/prompts.js";
|
export type {
|
||||||
|
WizardMultiSelectParams,
|
||||||
|
WizardProgress,
|
||||||
|
WizardPrompter,
|
||||||
|
WizardSelectParams,
|
||||||
|
} from "../wizard/prompts.js";
|
||||||
export { WizardCancelledError } from "../wizard/prompts.js";
|
export { WizardCancelledError } from "../wizard/prompts.js";
|
||||||
export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
|
export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
|
||||||
export type { ChannelSetupInput } from "../channels/plugins/types.core.js";
|
export type { ChannelSetupInput } from "../channels/plugins/types.core.js";
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
// Narrow public testing surface for plugin authors.
|
// Narrow public testing surface for plugin authors.
|
||||||
// Keep this list additive and limited to helpers we are willing to support.
|
// Keep this list additive and limited to helpers we are willing to support.
|
||||||
|
|
||||||
export { removeAckReactionAfterReply, shouldAckReaction } from "../channels/ack-reactions.js";
|
export {
|
||||||
|
createAckReactionHandle,
|
||||||
|
removeAckReactionAfterReply,
|
||||||
|
removeAckReactionHandleAfterReply,
|
||||||
|
shouldAckReaction,
|
||||||
|
} from "../channels/ack-reactions.js";
|
||||||
export {
|
export {
|
||||||
expectChannelInboundContextContract,
|
expectChannelInboundContextContract,
|
||||||
primeChannelOutboundSendMock,
|
primeChannelOutboundSendMock,
|
||||||
@@ -23,10 +28,48 @@ export { setDefaultChannelPluginRegistryForTests } from "../commands/channel-tes
|
|||||||
export type { ChannelAccountSnapshot } from "../channels/plugins/types.public.js";
|
export type { ChannelAccountSnapshot } from "../channels/plugins/types.public.js";
|
||||||
export type { ChannelGatewayContext } from "../channels/plugins/types.adapters.js";
|
export type { ChannelGatewayContext } from "../channels/plugins/types.adapters.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
|
export { isAtLeast, parseSemver } from "../infra/runtime-guard.js";
|
||||||
export { callGateway } from "../gateway/call.js";
|
export { callGateway } from "../gateway/call.js";
|
||||||
export { createEmptyPluginRegistry } from "../plugins/registry.js";
|
export { deliverOutboundPayloads } from "../infra/outbound/deliver.js";
|
||||||
|
export {
|
||||||
|
createEmptyPluginRegistry,
|
||||||
|
createPluginRegistry,
|
||||||
|
type PluginRecord,
|
||||||
|
} from "../plugins/registry.js";
|
||||||
|
export {
|
||||||
|
providerContractLoadError,
|
||||||
|
pluginRegistrationContractRegistry,
|
||||||
|
resolveProviderContractProvidersForPluginIds,
|
||||||
|
resolveWebFetchProviderContractEntriesForPluginId,
|
||||||
|
resolveWebSearchProviderContractEntriesForPluginId,
|
||||||
|
} from "../plugins/contracts/registry.js";
|
||||||
|
export { BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS } from "../plugins/contracts/inventory/bundled-capability-metadata.js";
|
||||||
|
export { loadPluginManifestRegistry } from "../plugins/manifest-registry.js";
|
||||||
|
export { parseMinHostVersionRequirement } from "../plugins/min-host-version.js";
|
||||||
|
export { resolveBundledExplicitProviderContractsFromPublicArtifacts } from "../plugins/provider-contract-public-artifacts.js";
|
||||||
|
export {
|
||||||
|
expectAugmentedCodexCatalog,
|
||||||
|
expectedAugmentedOpenaiCodexCatalogEntriesWithGpt55,
|
||||||
|
expectCodexBuiltInSuppression,
|
||||||
|
expectCodexMissingAuthHint,
|
||||||
|
} from "../plugins/provider-runtime.test-support.js";
|
||||||
|
export {
|
||||||
|
initializeGlobalHookRunner,
|
||||||
|
resetGlobalHookRunner,
|
||||||
|
} from "../plugins/hook-runner-global.js";
|
||||||
|
export { addTestHook } from "../plugins/hooks.test-helpers.js";
|
||||||
|
export {
|
||||||
|
assertUniqueValues,
|
||||||
|
BUNDLED_RUNTIME_SIDECAR_PATHS,
|
||||||
|
} from "../plugins/runtime-sidecar-paths.js";
|
||||||
|
export { createPluginRecord } from "../plugins/status.test-helpers.js";
|
||||||
|
export {
|
||||||
|
resolveBundledExplicitWebFetchProvidersFromPublicArtifacts,
|
||||||
|
resolveBundledExplicitWebSearchProvidersFromPublicArtifacts,
|
||||||
|
} from "../plugins/web-provider-public-artifacts.explicit.js";
|
||||||
export {
|
export {
|
||||||
getActivePluginRegistry,
|
getActivePluginRegistry,
|
||||||
|
releasePinnedPluginChannelRegistry,
|
||||||
resetPluginRuntimeStateForTest,
|
resetPluginRuntimeStateForTest,
|
||||||
setActivePluginRegistry,
|
setActivePluginRegistry,
|
||||||
} from "../plugins/runtime.js";
|
} from "../plugins/runtime.js";
|
||||||
@@ -35,8 +78,16 @@ export {
|
|||||||
resetFacadeRuntimeStateForTest,
|
resetFacadeRuntimeStateForTest,
|
||||||
} from "./facade-runtime.js";
|
} from "./facade-runtime.js";
|
||||||
export { capturePluginRegistration } from "../plugins/captured-registration.js";
|
export { capturePluginRegistration } from "../plugins/captured-registration.js";
|
||||||
|
export { runProviderCatalog } from "../plugins/provider-discovery.js";
|
||||||
|
export {
|
||||||
|
buildProviderPluginMethodChoice,
|
||||||
|
resolveProviderModelPickerEntries,
|
||||||
|
resolveProviderWizardOptions,
|
||||||
|
setProviderWizardProvidersResolverForTest,
|
||||||
|
} from "../plugins/provider-wizard.js";
|
||||||
export { resolveProviderPluginChoice } from "../plugins/provider-auth-choice.runtime.js";
|
export { resolveProviderPluginChoice } from "../plugins/provider-auth-choice.runtime.js";
|
||||||
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||||
|
export type { PluginHookRegistration } from "../plugins/hook-types.js";
|
||||||
export type { RuntimeEnv } from "../runtime.js";
|
export type { RuntimeEnv } from "../runtime.js";
|
||||||
export type { MockFn } from "../test-utils/vitest-mock-fn.js";
|
export type { MockFn } from "../test-utils/vitest-mock-fn.js";
|
||||||
export {
|
export {
|
||||||
@@ -105,7 +156,7 @@ export type {
|
|||||||
} from "../video-generation/types.js";
|
} from "../video-generation/types.js";
|
||||||
export { jsonResponse, requestBodyText, requestUrl } from "../test-helpers/http.js";
|
export { jsonResponse, requestBodyText, requestUrl } from "../test-helpers/http.js";
|
||||||
export { mockPinnedHostnameResolution } from "../test-helpers/ssrf.js";
|
export { mockPinnedHostnameResolution } from "../test-helpers/ssrf.js";
|
||||||
export { createTestRegistry } from "../test-utils/channel-plugins.js";
|
export { createOutboundTestPlugin, createTestRegistry } from "../test-utils/channel-plugins.js";
|
||||||
export { createWindowsCmdShimFixture } from "../test-helpers/windows-cmd-shim.js";
|
export { createWindowsCmdShimFixture } from "../test-helpers/windows-cmd-shim.js";
|
||||||
export { installCommonResolveTargetErrorCases } from "../test-helpers/resolve-target-error-cases.js";
|
export { installCommonResolveTargetErrorCases } from "../test-helpers/resolve-target-error-cases.js";
|
||||||
export { sanitizeTerminalText } from "../terminal/safe-text.js";
|
export { sanitizeTerminalText } from "../terminal/safe-text.js";
|
||||||
@@ -117,6 +168,7 @@ export { withFetchPreconnect, type FetchMock } from "../test-utils/fetch-mock.js
|
|||||||
export { createMockServerResponse } from "../test-utils/mock-http-response.js";
|
export { createMockServerResponse } from "../test-utils/mock-http-response.js";
|
||||||
export {
|
export {
|
||||||
registerProviderPlugin,
|
registerProviderPlugin,
|
||||||
|
registerProviderPlugins,
|
||||||
registerSingleProviderPlugin,
|
registerSingleProviderPlugin,
|
||||||
requireRegisteredProvider,
|
requireRegisteredProvider,
|
||||||
type RegisteredProviderCollections,
|
type RegisteredProviderCollections,
|
||||||
|
|||||||
@@ -35,6 +35,24 @@ export type ProviderModelPickerEntry = {
|
|||||||
hint?: string;
|
hint?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ProviderWizardProvidersResolver = (params: {
|
||||||
|
config?: OpenClawConfig;
|
||||||
|
workspaceDir?: string;
|
||||||
|
env?: NodeJS.ProcessEnv;
|
||||||
|
}) => ProviderPlugin[];
|
||||||
|
|
||||||
|
let providerWizardProvidersResolverForTest: ProviderWizardProvidersResolver | undefined;
|
||||||
|
|
||||||
|
export function setProviderWizardProvidersResolverForTest(
|
||||||
|
resolver: ProviderWizardProvidersResolver | undefined,
|
||||||
|
): () => void {
|
||||||
|
const previous = providerWizardProvidersResolverForTest;
|
||||||
|
providerWizardProvidersResolverForTest = resolver;
|
||||||
|
return () => {
|
||||||
|
providerWizardProvidersResolverForTest = previous;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function resolveWizardSetupChoiceId(
|
function resolveWizardSetupChoiceId(
|
||||||
provider: ProviderPlugin,
|
provider: ProviderPlugin,
|
||||||
wizard: ProviderPluginWizardSetup,
|
wizard: ProviderPluginWizardSetup,
|
||||||
@@ -113,6 +131,9 @@ function resolveProviderWizardProviders(params: {
|
|||||||
workspaceDir?: string;
|
workspaceDir?: string;
|
||||||
env?: NodeJS.ProcessEnv;
|
env?: NodeJS.ProcessEnv;
|
||||||
}): ProviderPlugin[] {
|
}): ProviderPlugin[] {
|
||||||
|
if (providerWizardProvidersResolverForTest) {
|
||||||
|
return providerWizardProvidersResolverForTest(params);
|
||||||
|
}
|
||||||
return resolvePluginProviders({
|
return resolvePluginProviders({
|
||||||
config: params.config,
|
config: params.config,
|
||||||
workspaceDir: params.workspaceDir,
|
workspaceDir: params.workspaceDir,
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
||||||
import { createPluginRegistry, type PluginRecord } from "../../../src/plugins/registry.js";
|
import {
|
||||||
import type { PluginRuntime } from "../../../src/plugins/runtime/types.js";
|
createPluginRecord,
|
||||||
import { createPluginRecord } from "../../../src/plugins/status.test-helpers.js";
|
createPluginRegistry,
|
||||||
import type { OpenClawPluginApi } from "../../../src/plugins/types.js";
|
|
||||||
|
|
||||||
export {
|
|
||||||
registerProviderPlugins as registerProviders,
|
registerProviderPlugins as registerProviders,
|
||||||
requireRegisteredProvider as requireProvider,
|
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[]) {
|
export function uniqueSortedStrings(values: readonly string[]) {
|
||||||
return [...new Set(values)].toSorted((left, right) => left.localeCompare(right));
|
return [...new Set(values)].toSorted((left, right) => left.localeCompare(right));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
import type { ModelApi } from "openclaw/plugin-sdk/provider-model-shared";
|
||||||
import type { ModelApi } from "../../../src/config/types.models.js";
|
import type { OpenClawConfig } from "openclaw/plugin-sdk/testing";
|
||||||
|
|
||||||
export const EXPECTED_FALLBACKS = ["anthropic/claude-opus-4-5"] as const;
|
export const EXPECTED_FALLBACKS = ["anthropic/claude-opus-4-5"] as const;
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
export {
|
||||||
|
addTestHook,
|
||||||
|
createEmptyPluginRegistry,
|
||||||
createOutboundTestPlugin,
|
createOutboundTestPlugin,
|
||||||
createTestRegistry,
|
createTestRegistry,
|
||||||
} from "../../../src/test-utils/channel-plugins.js";
|
deliverOutboundPayloads,
|
||||||
|
initializeGlobalHookRunner,
|
||||||
|
releasePinnedPluginChannelRegistry,
|
||||||
|
resetGlobalHookRunner,
|
||||||
|
setActivePluginRegistry,
|
||||||
|
type PluginHookRegistration,
|
||||||
|
} from "openclaw/plugin-sdk/testing";
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import {
|
||||||
|
isAtLeast,
|
||||||
|
parseMinHostVersionRequirement,
|
||||||
|
parseSemver,
|
||||||
|
} from "openclaw/plugin-sdk/testing";
|
||||||
import { describe, expect, it } from "vitest";
|
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";
|
import { bundledPluginFile } from "../bundled-plugin-paths.js";
|
||||||
|
|
||||||
type PackageManifest = {
|
type PackageManifest = {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import {
|
||||||
|
loadPluginManifestRegistry,
|
||||||
|
pluginRegistrationContractRegistry,
|
||||||
|
} from "openclaw/plugin-sdk/testing";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { pluginRegistrationContractRegistry } from "../../../src/plugins/contracts/registry.js";
|
|
||||||
import { loadPluginManifestRegistry } from "../../../src/plugins/manifest-registry.js";
|
|
||||||
|
|
||||||
type PluginRegistrationContractParams = {
|
type PluginRegistrationContractParams = {
|
||||||
pluginId: string;
|
pluginId: string;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { vi } from "vitest";
|
import {
|
||||||
|
implicitMentionKindWhen,
|
||||||
|
resolveInboundMentionDecision,
|
||||||
|
} from "openclaw/plugin-sdk/channel-mention-gating";
|
||||||
import {
|
import {
|
||||||
createAckReactionHandle,
|
createAckReactionHandle,
|
||||||
removeAckReactionAfterReply,
|
removeAckReactionAfterReply,
|
||||||
removeAckReactionHandleAfterReply,
|
removeAckReactionHandleAfterReply,
|
||||||
shouldAckReaction,
|
shouldAckReaction,
|
||||||
} from "../../../src/channels/ack-reactions.js";
|
} from "openclaw/plugin-sdk/testing";
|
||||||
import {
|
import type { PluginRuntime } from "openclaw/plugin-sdk/testing";
|
||||||
implicitMentionKindWhen,
|
import { vi } from "vitest";
|
||||||
resolveInboundMentionDecision,
|
|
||||||
} from "../../../src/channels/mention-gating.js";
|
|
||||||
import type { PluginRuntime } from "../../../src/plugins/runtime/types.js";
|
|
||||||
|
|
||||||
const DEFAULT_PROVIDER = "openai";
|
const DEFAULT_PROVIDER = "openai";
|
||||||
const DEFAULT_MODEL = "gpt-5.5";
|
const DEFAULT_MODEL = "gpt-5.5";
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import {
|
||||||
import { clearRuntimeAuthProfileStoreSnapshots } from "../../../src/agents/auth-profiles/store.js";
|
clearRuntimeAuthProfileStoreSnapshots,
|
||||||
import type { AuthProfileStore } from "../../../src/agents/auth-profiles/types.js";
|
type AuthProfileStore,
|
||||||
import { createNonExitingRuntime } from "../../../src/runtime.js";
|
} from "openclaw/plugin-sdk/agent-runtime";
|
||||||
|
import { createNonExitingRuntime } from "openclaw/plugin-sdk/runtime";
|
||||||
import type {
|
import type {
|
||||||
WizardMultiSelectParams,
|
WizardMultiSelectParams,
|
||||||
WizardPrompter,
|
WizardPrompter,
|
||||||
WizardProgress,
|
WizardProgress,
|
||||||
WizardSelectParams,
|
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";
|
import { registerProviders, requireProvider } from "./contracts-testkit.js";
|
||||||
|
|
||||||
type LoginOpenAICodexOAuth =
|
type LoginOpenAICodexOAuth =
|
||||||
(typeof import("openclaw/plugin-sdk/provider-auth-login"))["loginOpenAICodexOAuth"];
|
(typeof import("openclaw/plugin-sdk/provider-auth-login"))["loginOpenAICodexOAuth"];
|
||||||
type GithubCopilotLoginCommand =
|
type GithubCopilotLoginCommand =
|
||||||
(typeof import("openclaw/plugin-sdk/provider-auth-login"))["githubCopilotLoginCommand"];
|
(typeof import("openclaw/plugin-sdk/provider-auth-login"))["githubCopilotLoginCommand"];
|
||||||
type CreateVpsAwareHandlers =
|
|
||||||
(typeof import("../../../src/plugins/provider-oauth-flow.js"))["createVpsAwareOAuthHandlers"];
|
|
||||||
type EnsureAuthProfileStore =
|
type EnsureAuthProfileStore =
|
||||||
typeof import("openclaw/plugin-sdk/provider-auth").ensureAuthProfileStore;
|
typeof import("openclaw/plugin-sdk/provider-auth").ensureAuthProfileStore;
|
||||||
type ListProfilesForProvider =
|
type ListProfilesForProvider =
|
||||||
@@ -83,7 +83,7 @@ function buildAuthContext() {
|
|||||||
isRemote: false,
|
isRemote: false,
|
||||||
openUrl: async () => {},
|
openUrl: async () => {},
|
||||||
oauth: {
|
oauth: {
|
||||||
createVpsAwareHandlers: vi.fn<CreateVpsAwareHandlers>(),
|
createVpsAwareHandlers: vi.fn(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ export {
|
|||||||
expectedAugmentedOpenaiCodexCatalogEntriesWithGpt55,
|
expectedAugmentedOpenaiCodexCatalogEntriesWithGpt55,
|
||||||
expectCodexBuiltInSuppression,
|
expectCodexBuiltInSuppression,
|
||||||
expectCodexMissingAuthHint,
|
expectCodexMissingAuthHint,
|
||||||
} from "../../../src/plugins/provider-runtime.test-support.js";
|
} from "openclaw/plugin-sdk/testing";
|
||||||
export type { ProviderPlugin } from "../../../src/plugins/types.js";
|
export type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
|
||||||
export {
|
export {
|
||||||
loadBundledPluginPublicSurface,
|
loadBundledPluginPublicSurface,
|
||||||
loadBundledPluginPublicSurfaceSync,
|
loadBundledPluginPublicSurfaceSync,
|
||||||
} from "../../../src/test-utils/bundled-plugin-public-surface.js";
|
} from "./public-surface-loader.js";
|
||||||
|
|
||||||
type ProviderRuntimeCatalogModule = Pick<
|
type ProviderRuntimeCatalogModule = Pick<
|
||||||
typeof import("openclaw/plugin-sdk/provider-catalog-runtime"),
|
typeof import("openclaw/plugin-sdk/provider-catalog-runtime"),
|
||||||
|
|||||||
@@ -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 { 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);
|
type Lazy<T> = T | (() => T);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
|
||||||
import {
|
import {
|
||||||
providerContractLoadError,
|
providerContractLoadError,
|
||||||
|
resolveBundledExplicitProviderContractsFromPublicArtifacts,
|
||||||
resolveProviderContractProvidersForPluginIds,
|
resolveProviderContractProvidersForPluginIds,
|
||||||
} from "../../../src/plugins/contracts/registry.js";
|
} from "openclaw/plugin-sdk/testing";
|
||||||
import { resolveBundledExplicitProviderContractsFromPublicArtifacts } from "../../../src/plugins/provider-contract-public-artifacts.js";
|
import { describe, expect, it } from "vitest";
|
||||||
import type { ProviderPlugin } from "../../../src/plugins/types.js";
|
|
||||||
import { installProviderPluginContractSuite } from "./provider-contract-suites.js";
|
import { installProviderPluginContractSuite } from "./provider-contract-suites.js";
|
||||||
|
|
||||||
type ProviderContractEntry = {
|
type ProviderContractEntry = {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import type { AuthProfileStore, OpenClawConfig } from "openclaw/plugin-sdk/provider-auth";
|
||||||
import type { AuthProfileStore } from "../../../src/agents/auth-profiles/types.js";
|
|
||||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
|
||||||
import {
|
import {
|
||||||
registerProviderPlugins as registerProviders,
|
registerProviderPlugins as registerProviders,
|
||||||
requireRegisteredProvider as requireProvider,
|
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 resolveCopilotApiTokenMock = vi.hoisted(() => vi.fn());
|
||||||
const buildVllmProviderMock = 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 ProviderHandle = Awaited<ReturnType<typeof registerProviders>>[number];
|
||||||
|
|
||||||
type DiscoveryState = {
|
type DiscoveryState = {
|
||||||
runProviderCatalog: typeof import("../../../src/plugins/provider-discovery.js").runProviderCatalog;
|
runProviderCatalog: typeof runProviderCatalog;
|
||||||
githubCopilotProvider?: ProviderHandle;
|
githubCopilotProvider?: ProviderHandle;
|
||||||
vllmProvider?: ProviderHandle;
|
vllmProvider?: ProviderHandle;
|
||||||
sglangProvider?: ProviderHandle;
|
sglangProvider?: ProviderHandle;
|
||||||
@@ -183,8 +183,7 @@ function installDiscoveryHooks(state: DiscoveryState, options: DiscoveryContract
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
({ runProviderCatalog: state.runProviderCatalog } =
|
state.runProviderCatalog = runProviderCatalog;
|
||||||
await import("../../../src/plugins/provider-discovery.js"));
|
|
||||||
|
|
||||||
if (options.providerIds.includes("github-copilot")) {
|
if (options.providerIds.includes("github-copilot")) {
|
||||||
const { default: githubCopilotPlugin } = await options.loadGithubCopilot!();
|
const { default: githubCopilotPlugin } = await options.loadGithubCopilot!();
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import {
|
|||||||
resolveAgentModelPrimaryValue,
|
resolveAgentModelPrimaryValue,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
import type { ModelApi } 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 { expect } from "vitest";
|
||||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
|
||||||
import {
|
import {
|
||||||
createConfigWithFallbacks,
|
createConfigWithFallbacks,
|
||||||
createLegacyProviderConfig,
|
createLegacyProviderConfig,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
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 {
|
import {
|
||||||
createProviderUsageFetch,
|
createProviderUsageFetch,
|
||||||
makeResponse,
|
makeResponse,
|
||||||
@@ -8,7 +10,6 @@ import {
|
|||||||
requireRegisteredProvider,
|
requireRegisteredProvider,
|
||||||
} from "openclaw/plugin-sdk/testing";
|
} from "openclaw/plugin-sdk/testing";
|
||||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
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;
|
const CONTRACT_SETUP_TIMEOUT_MS = 300_000;
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
import {
|
||||||
buildProviderPluginMethodChoice,
|
buildProviderPluginMethodChoice,
|
||||||
resolveProviderModelPickerEntries,
|
resolveProviderModelPickerEntries,
|
||||||
resolveProviderPluginChoice,
|
resolveProviderPluginChoice,
|
||||||
resolveProviderWizardOptions,
|
resolveProviderWizardOptions,
|
||||||
} from "../../../src/plugins/provider-wizard.js";
|
setProviderWizardProvidersResolverForTest,
|
||||||
import type { ProviderAuthMethod, ProviderPlugin } from "../../../src/plugins/types.js";
|
} from "openclaw/plugin-sdk/testing";
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
const resolvePluginProvidersMock = vi.fn();
|
const resolvePluginProvidersMock = vi.fn();
|
||||||
|
let restoreProviderResolver: (() => void) | undefined;
|
||||||
vi.mock("../../../src/plugins/providers.runtime.js", () => ({
|
|
||||||
isPluginProvidersLoadInFlight: () => false,
|
|
||||||
resolvePluginProviders: (...args: unknown[]) => resolvePluginProvidersMock(...args),
|
|
||||||
}));
|
|
||||||
|
|
||||||
function createAuthMethod(
|
function createAuthMethod(
|
||||||
params: Pick<ProviderAuthMethod, "id" | "label"> &
|
params: Pick<ProviderAuthMethod, "id" | "label"> &
|
||||||
@@ -175,6 +173,15 @@ function expectAllChoicesResolve(
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resolvePluginProvidersMock.mockReset();
|
resolvePluginProvidersMock.mockReset();
|
||||||
resolvePluginProvidersMock.mockReturnValue(TEST_PROVIDERS);
|
resolvePluginProvidersMock.mockReturnValue(TEST_PROVIDERS);
|
||||||
|
restoreProviderResolver?.();
|
||||||
|
restoreProviderResolver = setProviderWizardProvidersResolverForTest((params) =>
|
||||||
|
resolvePluginProvidersMock(params),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
restoreProviderResolver?.();
|
||||||
|
restoreProviderResolver = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
export function describeProviderWizardSetupOptionsContract() {
|
export function describeProviderWizardSetupOptionsContract() {
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import {
|
import { assertUniqueValues, BUNDLED_RUNTIME_SIDECAR_PATHS } from "openclaw/plugin-sdk/testing";
|
||||||
assertUniqueValues,
|
|
||||||
BUNDLED_RUNTIME_SIDECAR_PATHS,
|
|
||||||
} from "../../../src/plugins/runtime-sidecar-paths.js";
|
|
||||||
|
|
||||||
export function getPublicArtifactBasename(relativePath: string): string {
|
export function getPublicArtifactBasename(relativePath: string): string {
|
||||||
return relativePath.split("/").at(-1) ?? relativePath;
|
return relativePath.split("/").at(-1) ?? relativePath;
|
||||||
|
|||||||
81
test/helpers/plugins/public-surface-loader.ts
Normal file
81
test/helpers/plugins/public-surface-loader.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { createRuntimeEnv } from "openclaw/plugin-sdk/testing";
|
import { createRuntimeEnv } from "openclaw/plugin-sdk/testing";
|
||||||
import { vi } from "vitest";
|
|
||||||
import type {
|
import type {
|
||||||
ChannelAccountSnapshot,
|
ChannelAccountSnapshot,
|
||||||
ChannelGatewayContext,
|
ChannelGatewayContext,
|
||||||
} from "../../../src/channels/plugins/types.js";
|
OpenClawConfig,
|
||||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
RuntimeEnv,
|
||||||
import type { RuntimeEnv } from "../../../src/runtime.js";
|
} from "openclaw/plugin-sdk/testing";
|
||||||
|
import { vi } from "vitest";
|
||||||
|
|
||||||
export function createStartAccountContext<TAccount extends { accountId: string }>(params: {
|
export function createStartAccountContext<TAccount extends { accountId: string }>(params: {
|
||||||
account: TAccount;
|
account: TAccount;
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
|
import type { ChannelAccountSnapshot, ChannelGatewayContext } from "openclaw/plugin-sdk/testing";
|
||||||
import { expect, vi } from "vitest";
|
import { expect, vi } from "vitest";
|
||||||
import type {
|
|
||||||
ChannelAccountSnapshot,
|
|
||||||
ChannelGatewayContext,
|
|
||||||
} from "../../../src/channels/plugins/types.js";
|
|
||||||
import { createStartAccountContext } from "./start-account-context.js";
|
import { createStartAccountContext } from "./start-account-context.js";
|
||||||
|
|
||||||
export function startAccountAndTrackLifecycle<TAccount extends { accountId: string }>(params: {
|
export function startAccountAndTrackLifecycle<TAccount extends { accountId: string }>(params: {
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
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 { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
import { resolveWorkspacePackagePublicModuleUrl } from "./public-surface-loader.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";
|
|
||||||
|
|
||||||
type TtsRuntimeModule = typeof import("../../../src/tts/tts.js");
|
type TtsRuntimeModule = typeof import("openclaw/plugin-sdk/tts-runtime");
|
||||||
type TtsCoreModule = typeof import("../../../src/tts/tts-core.js");
|
type TtsCoreModule = typeof import("openclaw/plugin-sdk/speech-core");
|
||||||
|
type SummarizeTextDeps = NonNullable<Parameters<TtsCoreModule["summarizeText"]>[1]>;
|
||||||
|
|
||||||
const speechCoreRuntimeApiModuleId = resolveWorkspacePackagePublicModuleUrl({
|
const speechCoreRuntimeApiModuleId = resolveWorkspacePackagePublicModuleUrl({
|
||||||
packageName: "@openclaw/speech-core",
|
packageName: "@openclaw/speech-core",
|
||||||
@@ -22,11 +25,11 @@ let ttsRuntimePromise: Promise<TtsRuntimeModule> | null = null;
|
|||||||
let ttsRuntimeInitialized = false;
|
let ttsRuntimeInitialized = false;
|
||||||
let ttsCorePromise: Promise<TtsCoreModule> | null = null;
|
let ttsCorePromise: Promise<TtsCoreModule> | null = null;
|
||||||
let completeSimple: typeof import("@mariozechner/pi-ai").completeSimple;
|
let completeSimple: typeof import("@mariozechner/pi-ai").completeSimple;
|
||||||
let getApiKeyForModelMock: typeof import("../../../src/agents/model-auth.js").getApiKeyForModel;
|
let getApiKeyForModelMock: SummarizeTextDeps["getApiKeyForModel"];
|
||||||
let requireApiKeyMock: typeof import("../../../src/agents/model-auth.js").requireApiKey;
|
let requireApiKeyMock: SummarizeTextDeps["requireApiKey"];
|
||||||
let resolveModelAsyncMock: typeof import("../../../src/agents/pi-embedded-runner/model.js").resolveModelAsync;
|
let resolveModelAsyncMock: SummarizeTextDeps["resolveModelAsync"];
|
||||||
let ensureCustomApiRegisteredMock: typeof import("../../../src/agents/custom-api-registry.js").ensureCustomApiRegistered;
|
let ensureCustomApiRegisteredMock: ReturnType<typeof vi.fn>;
|
||||||
let prepareModelForSimpleCompletionMock: typeof import("../../../src/agents/simple-completion-transport.js").prepareModelForSimpleCompletion;
|
let prepareModelForSimpleCompletionMock: SummarizeTextDeps["prepareModelForSimpleCompletion"];
|
||||||
let summarizeTextCore: TtsCoreModule["summarizeText"];
|
let summarizeTextCore: TtsCoreModule["summarizeText"];
|
||||||
let resolveTtsConfig: TtsRuntimeModule["resolveTtsConfig"];
|
let resolveTtsConfig: TtsRuntimeModule["resolveTtsConfig"];
|
||||||
let maybeApplyTtsToPayload: TtsRuntimeModule["maybeApplyTtsToPayload"];
|
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 {
|
function asLegacyTtsConfig(value: unknown): OpenClawConfig {
|
||||||
return value as OpenClawConfig;
|
return value as OpenClawConfig;
|
||||||
}
|
}
|
||||||
@@ -444,10 +425,16 @@ async function loadTtsRuntime(): Promise<TtsRuntimeModule> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadTtsCore(): Promise<TtsCoreModule> {
|
async function loadTtsCore(): Promise<TtsCoreModule> {
|
||||||
ttsCorePromise ??= import("../../../src/tts/tts-core.js");
|
ttsCorePromise ??= import("openclaw/plugin-sdk/speech-core");
|
||||||
return await ttsCorePromise;
|
return await ttsCorePromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createPrepareModelForSimpleCompletionMock(): SummarizeTextDeps["prepareModelForSimpleCompletion"] {
|
||||||
|
return vi.fn(
|
||||||
|
({ model }: Parameters<SummarizeTextDeps["prepareModelForSimpleCompletion"]>[0]) => model,
|
||||||
|
) as SummarizeTextDeps["prepareModelForSimpleCompletion"];
|
||||||
|
}
|
||||||
|
|
||||||
async function setupTtsRuntime() {
|
async function setupTtsRuntime() {
|
||||||
if (ttsRuntimeInitialized) {
|
if (ttsRuntimeInitialized) {
|
||||||
return;
|
return;
|
||||||
@@ -467,7 +454,7 @@ async function setupTtsRuntime() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setupTestSpeechProviderRegistry() {
|
function setupTestSpeechProviderRegistry() {
|
||||||
prepareModelForSimpleCompletionMock = vi.fn(({ model }) => model);
|
prepareModelForSimpleCompletionMock = createPrepareModelForSimpleCompletionMock();
|
||||||
const registry = createEmptyPluginRegistry();
|
const registry = createEmptyPluginRegistry();
|
||||||
registry.speechProviders = [
|
registry.speechProviders = [
|
||||||
{ pluginId: "openai", provider: buildTestOpenAISpeechProvider(), source: "test" },
|
{ pluginId: "openai", provider: buildTestOpenAISpeechProvider(), source: "test" },
|
||||||
@@ -510,14 +497,12 @@ function createResolvedSummarizationConfig(cfg: OpenClawConfig): ResolvedTtsConf
|
|||||||
|
|
||||||
async function setupSummarizationMocks() {
|
async function setupSummarizationMocks() {
|
||||||
({ summarizeText: summarizeTextCore } = await loadTtsCore());
|
({ summarizeText: summarizeTextCore } = await loadTtsCore());
|
||||||
prepareModelForSimpleCompletionMock = vi.fn(({ model }) => model);
|
|
||||||
({ completeSimple } = await import("@mariozechner/pi-ai"));
|
({ completeSimple } = await import("@mariozechner/pi-ai"));
|
||||||
({ getApiKeyForModel: getApiKeyForModelMock, requireApiKey: requireApiKeyMock } =
|
getApiKeyForModelMock = vi.fn() as SummarizeTextDeps["getApiKeyForModel"];
|
||||||
await import("../../../src/agents/model-auth.js"));
|
requireApiKeyMock = vi.fn() as SummarizeTextDeps["requireApiKey"];
|
||||||
({ resolveModelAsync: resolveModelAsyncMock } =
|
resolveModelAsyncMock = vi.fn() as SummarizeTextDeps["resolveModelAsync"];
|
||||||
await import("../../../src/agents/pi-embedded-runner/model.js"));
|
ensureCustomApiRegisteredMock = vi.fn();
|
||||||
({ ensureCustomApiRegistered: ensureCustomApiRegisteredMock } =
|
prepareModelForSimpleCompletionMock = createPrepareModelForSimpleCompletionMock();
|
||||||
await import("../../../src/agents/custom-api-registry.js"));
|
|
||||||
vi.mocked(completeSimple).mockResolvedValue(
|
vi.mocked(completeSimple).mockResolvedValue(
|
||||||
mockAssistantMessage([{ type: "text", text: "Summary" }]),
|
mockAssistantMessage([{ type: "text", text: "Summary" }]),
|
||||||
);
|
);
|
||||||
@@ -534,7 +519,7 @@ async function setupSummarizationMocks() {
|
|||||||
>,
|
>,
|
||||||
);
|
);
|
||||||
vi.mocked(ensureCustomApiRegisteredMock).mockReset();
|
vi.mocked(ensureCustomApiRegisteredMock).mockReset();
|
||||||
prepareModelForSimpleCompletionMock = vi.fn(({ model }) => model);
|
prepareModelForSimpleCompletionMock = createPrepareModelForSimpleCompletionMock();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupTtsContractTest() {
|
async function setupTtsContractTest() {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import type { WebFetchProviderPlugin } from "openclaw/plugin-sdk/provider-web-fetch-contract";
|
||||||
import {
|
import {
|
||||||
pluginRegistrationContractRegistry,
|
pluginRegistrationContractRegistry,
|
||||||
|
resolveBundledExplicitWebFetchProvidersFromPublicArtifacts,
|
||||||
resolveWebFetchProviderContractEntriesForPluginId,
|
resolveWebFetchProviderContractEntriesForPluginId,
|
||||||
} from "../../../src/plugins/contracts/registry.js";
|
} from "openclaw/plugin-sdk/testing";
|
||||||
import type { WebFetchProviderPlugin } from "../../../src/plugins/types.js";
|
import { describe, expect, it } from "vitest";
|
||||||
import { resolveBundledExplicitWebFetchProvidersFromPublicArtifacts } from "../../../src/plugins/web-provider-public-artifacts.explicit.js";
|
|
||||||
import { installWebFetchProviderContractSuite } from "./provider-contract-suites.js";
|
import { installWebFetchProviderContractSuite } from "./provider-contract-suites.js";
|
||||||
|
|
||||||
function resolveWebFetchCredentialValue(provider: WebFetchProviderPlugin): unknown {
|
function resolveWebFetchCredentialValue(provider: WebFetchProviderPlugin): unknown {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
|
||||||
import {
|
import {
|
||||||
pluginRegistrationContractRegistry,
|
pluginRegistrationContractRegistry,
|
||||||
|
resolveBundledExplicitWebSearchProvidersFromPublicArtifacts,
|
||||||
resolveWebSearchProviderContractEntriesForPluginId,
|
resolveWebSearchProviderContractEntriesForPluginId,
|
||||||
} from "../../../src/plugins/contracts/registry.js";
|
} from "openclaw/plugin-sdk/testing";
|
||||||
import { resolveBundledExplicitWebSearchProvidersFromPublicArtifacts } from "../../../src/plugins/web-provider-public-artifacts.explicit.js";
|
import { describe, expect, it } from "vitest";
|
||||||
import { installWebSearchProviderContractSuite } from "./provider-contract-suites.js";
|
import { installWebSearchProviderContractSuite } from "./provider-contract-suites.js";
|
||||||
|
|
||||||
type WebSearchContractEntry = ReturnType<
|
type WebSearchContractEntry = ReturnType<
|
||||||
|
|||||||
Reference in New Issue
Block a user