mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-20 05:31:30 +00:00
refactor: move voice-call realtime providers into extensions
This commit is contained in:
@@ -8,6 +8,8 @@ import {
|
||||
pluginRegistrationContractRegistry,
|
||||
providerContractLoadError,
|
||||
providerContractPluginIds,
|
||||
realtimeTranscriptionProviderContractRegistry,
|
||||
realtimeVoiceProviderContractRegistry,
|
||||
resolveWebFetchProviderContractEntriesForPluginId,
|
||||
resolveWebSearchProviderContractEntriesForPluginId,
|
||||
speechProviderContractRegistry,
|
||||
@@ -27,7 +29,11 @@ describe("plugin contract registry", () => {
|
||||
predicate: (plugin: {
|
||||
origin: string;
|
||||
providers: unknown[];
|
||||
contracts?: { speechProviders?: unknown[] };
|
||||
contracts?: {
|
||||
speechProviders?: unknown[];
|
||||
realtimeTranscriptionProviders?: unknown[];
|
||||
realtimeVoiceProviders?: unknown[];
|
||||
};
|
||||
}) => boolean;
|
||||
}) {
|
||||
expect(uniqueSortedStrings(params.actualPluginIds)).toEqual(
|
||||
@@ -39,7 +45,11 @@ describe("plugin contract registry", () => {
|
||||
predicate: (plugin: {
|
||||
origin: string;
|
||||
providers: unknown[];
|
||||
contracts?: { speechProviders?: unknown[] };
|
||||
contracts?: {
|
||||
speechProviders?: unknown[];
|
||||
realtimeTranscriptionProviders?: unknown[];
|
||||
realtimeVoiceProviders?: unknown[];
|
||||
};
|
||||
}) => boolean,
|
||||
) {
|
||||
return loadPluginManifestRegistry({})
|
||||
@@ -70,6 +80,14 @@ describe("plugin contract registry", () => {
|
||||
name: "does not duplicate bundled media provider ids",
|
||||
ids: () => mediaUnderstandingProviderContractRegistry.map((entry) => entry.provider.id),
|
||||
},
|
||||
{
|
||||
name: "does not duplicate bundled realtime transcription provider ids",
|
||||
ids: () => realtimeTranscriptionProviderContractRegistry.map((entry) => entry.provider.id),
|
||||
},
|
||||
{
|
||||
name: "does not duplicate bundled realtime voice provider ids",
|
||||
ids: () => realtimeVoiceProviderContractRegistry.map((entry) => entry.provider.id),
|
||||
},
|
||||
{
|
||||
name: "does not duplicate bundled image-generation provider ids",
|
||||
ids: () => imageGenerationProviderContractRegistry.map((entry) => entry.provider.id),
|
||||
@@ -101,6 +119,23 @@ describe("plugin contract registry", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("covers every bundled realtime voice plugin discovered from manifests", () => {
|
||||
expectRegistryPluginIds({
|
||||
actualPluginIds: realtimeVoiceProviderContractRegistry.map((entry) => entry.pluginId),
|
||||
predicate: (plugin) =>
|
||||
plugin.origin === "bundled" && (plugin.contracts?.realtimeVoiceProviders?.length ?? 0) > 0,
|
||||
});
|
||||
});
|
||||
|
||||
it("covers every bundled realtime transcription plugin discovered from manifests", () => {
|
||||
expectRegistryPluginIds({
|
||||
actualPluginIds: realtimeTranscriptionProviderContractRegistry.map((entry) => entry.pluginId),
|
||||
predicate: (plugin) =>
|
||||
plugin.origin === "bundled" &&
|
||||
(plugin.contracts?.realtimeTranscriptionProviders?.length ?? 0) > 0,
|
||||
});
|
||||
});
|
||||
|
||||
it("covers every bundled web fetch plugin from the shared resolver", () => {
|
||||
const bundledWebFetchPluginIds = resolveBundledWebFetchPluginIds({});
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
BUNDLED_MEDIA_UNDERSTANDING_PLUGIN_IDS,
|
||||
BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS,
|
||||
BUNDLED_PROVIDER_PLUGIN_IDS,
|
||||
BUNDLED_REALTIME_TRANSCRIPTION_PLUGIN_IDS,
|
||||
BUNDLED_REALTIME_VOICE_PLUGIN_IDS,
|
||||
BUNDLED_SPEECH_PLUGIN_IDS,
|
||||
BUNDLED_WEB_FETCH_PLUGIN_IDS,
|
||||
BUNDLED_WEB_SEARCH_PLUGIN_IDS,
|
||||
@@ -12,6 +14,8 @@ import type {
|
||||
ImageGenerationProviderPlugin,
|
||||
MediaUnderstandingProviderPlugin,
|
||||
ProviderPlugin,
|
||||
RealtimeTranscriptionProviderPlugin,
|
||||
RealtimeVoiceProviderPlugin,
|
||||
SpeechProviderPlugin,
|
||||
WebFetchProviderPlugin,
|
||||
WebSearchProviderPlugin,
|
||||
@@ -19,6 +23,8 @@ import type {
|
||||
import {
|
||||
loadVitestImageGenerationProviderContractRegistry,
|
||||
loadVitestMediaUnderstandingProviderContractRegistry,
|
||||
loadVitestRealtimeTranscriptionProviderContractRegistry,
|
||||
loadVitestRealtimeVoiceProviderContractRegistry,
|
||||
loadVitestSpeechProviderContractRegistry,
|
||||
} from "./speech-vitest-registry.js";
|
||||
|
||||
@@ -38,6 +44,9 @@ type WebFetchProviderContractEntry = CapabilityContractEntry<WebFetchProviderPlu
|
||||
};
|
||||
|
||||
type SpeechProviderContractEntry = CapabilityContractEntry<SpeechProviderPlugin>;
|
||||
type RealtimeTranscriptionProviderContractEntry =
|
||||
CapabilityContractEntry<RealtimeTranscriptionProviderPlugin>;
|
||||
type RealtimeVoiceProviderContractEntry = CapabilityContractEntry<RealtimeVoiceProviderPlugin>;
|
||||
type MediaUnderstandingProviderContractEntry =
|
||||
CapabilityContractEntry<MediaUnderstandingProviderPlugin>;
|
||||
type ImageGenerationProviderContractEntry = CapabilityContractEntry<ImageGenerationProviderPlugin>;
|
||||
@@ -47,6 +56,8 @@ type PluginRegistrationContractEntry = {
|
||||
cliBackendIds: string[];
|
||||
providerIds: string[];
|
||||
speechProviderIds: string[];
|
||||
realtimeTranscriptionProviderIds: string[];
|
||||
realtimeVoiceProviderIds: string[];
|
||||
mediaUnderstandingProviderIds: string[];
|
||||
imageGenerationProviderIds: string[];
|
||||
webFetchProviderIds: string[];
|
||||
@@ -94,6 +105,10 @@ let webSearchProviderContractRegistryByPluginIdCache: Map<
|
||||
WebSearchProviderContractEntry[]
|
||||
> | null = null;
|
||||
let speechProviderContractRegistryCache: SpeechProviderContractEntry[] | null = null;
|
||||
let realtimeTranscriptionProviderContractRegistryCache:
|
||||
| RealtimeTranscriptionProviderContractEntry[]
|
||||
| null = null;
|
||||
let realtimeVoiceProviderContractRegistryCache: RealtimeVoiceProviderContractEntry[] | null = null;
|
||||
let mediaUnderstandingProviderContractRegistryCache:
|
||||
| MediaUnderstandingProviderContractEntry[]
|
||||
| null = null;
|
||||
@@ -387,6 +402,36 @@ function loadSpeechProviderContractRegistry(): SpeechProviderContractEntry[] {
|
||||
return speechProviderContractRegistryCache;
|
||||
}
|
||||
|
||||
function loadRealtimeVoiceProviderContractRegistry(): RealtimeVoiceProviderContractEntry[] {
|
||||
if (!realtimeVoiceProviderContractRegistryCache) {
|
||||
realtimeVoiceProviderContractRegistryCache = process.env.VITEST
|
||||
? loadVitestRealtimeVoiceProviderContractRegistry()
|
||||
: loadBundledCapabilityRuntimeRegistry({
|
||||
pluginIds: BUNDLED_REALTIME_VOICE_PLUGIN_IDS,
|
||||
pluginSdkResolution: "dist",
|
||||
}).realtimeVoiceProviders.map((entry) => ({
|
||||
pluginId: entry.pluginId,
|
||||
provider: entry.provider,
|
||||
}));
|
||||
}
|
||||
return realtimeVoiceProviderContractRegistryCache;
|
||||
}
|
||||
|
||||
function loadRealtimeTranscriptionProviderContractRegistry(): RealtimeTranscriptionProviderContractEntry[] {
|
||||
if (!realtimeTranscriptionProviderContractRegistryCache) {
|
||||
realtimeTranscriptionProviderContractRegistryCache = process.env.VITEST
|
||||
? loadVitestRealtimeTranscriptionProviderContractRegistry()
|
||||
: loadBundledCapabilityRuntimeRegistry({
|
||||
pluginIds: BUNDLED_REALTIME_TRANSCRIPTION_PLUGIN_IDS,
|
||||
pluginSdkResolution: "dist",
|
||||
}).realtimeTranscriptionProviders.map((entry) => ({
|
||||
pluginId: entry.pluginId,
|
||||
provider: entry.provider,
|
||||
}));
|
||||
}
|
||||
return realtimeTranscriptionProviderContractRegistryCache;
|
||||
}
|
||||
|
||||
function loadMediaUnderstandingProviderContractRegistry(): MediaUnderstandingProviderContractEntry[] {
|
||||
if (!mediaUnderstandingProviderContractRegistryCache) {
|
||||
mediaUnderstandingProviderContractRegistryCache = process.env.VITEST
|
||||
@@ -519,6 +564,12 @@ export const speechProviderContractRegistry: SpeechProviderContractEntry[] = cre
|
||||
loadSpeechProviderContractRegistry,
|
||||
);
|
||||
|
||||
export const realtimeTranscriptionProviderContractRegistry: RealtimeTranscriptionProviderContractEntry[] =
|
||||
createLazyArrayView(loadRealtimeTranscriptionProviderContractRegistry);
|
||||
|
||||
export const realtimeVoiceProviderContractRegistry: RealtimeVoiceProviderContractEntry[] =
|
||||
createLazyArrayView(loadRealtimeVoiceProviderContractRegistry);
|
||||
|
||||
export const mediaUnderstandingProviderContractRegistry: MediaUnderstandingProviderContractEntry[] =
|
||||
createLazyArrayView(loadMediaUnderstandingProviderContractRegistry);
|
||||
|
||||
@@ -531,6 +582,8 @@ function loadPluginRegistrationContractRegistry(): PluginRegistrationContractEnt
|
||||
cliBackendIds: uniqueStrings(entry.cliBackendIds),
|
||||
providerIds: uniqueStrings(entry.providerIds),
|
||||
speechProviderIds: uniqueStrings(entry.speechProviderIds),
|
||||
realtimeTranscriptionProviderIds: uniqueStrings(entry.realtimeTranscriptionProviderIds),
|
||||
realtimeVoiceProviderIds: uniqueStrings(entry.realtimeVoiceProviderIds),
|
||||
mediaUnderstandingProviderIds: uniqueStrings(entry.mediaUnderstandingProviderIds),
|
||||
imageGenerationProviderIds: uniqueStrings(entry.imageGenerationProviderIds),
|
||||
webFetchProviderIds: uniqueStrings(entry.webFetchProviderIds),
|
||||
|
||||
@@ -5,6 +5,8 @@ import { createJiti } from "jiti";
|
||||
import {
|
||||
BUNDLED_IMAGE_GENERATION_PLUGIN_IDS,
|
||||
BUNDLED_MEDIA_UNDERSTANDING_PLUGIN_IDS,
|
||||
BUNDLED_REALTIME_TRANSCRIPTION_PLUGIN_IDS,
|
||||
BUNDLED_REALTIME_VOICE_PLUGIN_IDS,
|
||||
BUNDLED_SPEECH_PLUGIN_IDS,
|
||||
} from "../bundled-capability-metadata.js";
|
||||
import { loadBundledCapabilityRuntimeRegistry } from "../bundled-capability-runtime.js";
|
||||
@@ -13,6 +15,8 @@ import { buildPluginLoaderAliasMap, buildPluginLoaderJitiOptions } from "../sdk-
|
||||
import type {
|
||||
ImageGenerationProviderPlugin,
|
||||
MediaUnderstandingProviderPlugin,
|
||||
RealtimeTranscriptionProviderPlugin,
|
||||
RealtimeVoiceProviderPlugin,
|
||||
SpeechProviderPlugin,
|
||||
} from "../types.js";
|
||||
|
||||
@@ -26,6 +30,16 @@ export type MediaUnderstandingProviderContractEntry = {
|
||||
provider: MediaUnderstandingProviderPlugin;
|
||||
};
|
||||
|
||||
export type RealtimeVoiceProviderContractEntry = {
|
||||
pluginId: string;
|
||||
provider: RealtimeVoiceProviderPlugin;
|
||||
};
|
||||
|
||||
export type RealtimeTranscriptionProviderContractEntry = {
|
||||
pluginId: string;
|
||||
provider: RealtimeTranscriptionProviderPlugin;
|
||||
};
|
||||
|
||||
export type ImageGenerationProviderContractEntry = {
|
||||
pluginId: string;
|
||||
provider: ImageGenerationProviderPlugin;
|
||||
@@ -190,6 +204,96 @@ export function loadVitestMediaUnderstandingProviderContractRegistry(): MediaUnd
|
||||
return registrations;
|
||||
}
|
||||
|
||||
export function loadVitestRealtimeVoiceProviderContractRegistry(): RealtimeVoiceProviderContractEntry[] {
|
||||
const registrations: RealtimeVoiceProviderContractEntry[] = [];
|
||||
const { manifests, unresolvedPluginIds } = resolveTestApiModuleRecords(
|
||||
BUNDLED_REALTIME_VOICE_PLUGIN_IDS,
|
||||
);
|
||||
|
||||
for (const plugin of manifests) {
|
||||
if (!plugin.rootDir) {
|
||||
continue;
|
||||
}
|
||||
const testApiPath = path.join(plugin.rootDir, "test-api.ts");
|
||||
if (!fs.existsSync(testApiPath)) {
|
||||
continue;
|
||||
}
|
||||
const builder = resolveNamedBuilder<RealtimeVoiceProviderPlugin>(
|
||||
createVitestCapabilityLoader(testApiPath)(testApiPath),
|
||||
/^build.+RealtimeVoiceProvider$/u,
|
||||
);
|
||||
if (!builder) {
|
||||
continue;
|
||||
}
|
||||
registrations.push({
|
||||
pluginId: plugin.id,
|
||||
provider: builder(),
|
||||
});
|
||||
unresolvedPluginIds.delete(plugin.id);
|
||||
}
|
||||
|
||||
if (unresolvedPluginIds.size === 0) {
|
||||
return registrations;
|
||||
}
|
||||
|
||||
const runtimeRegistry = loadBundledCapabilityRuntimeRegistry({
|
||||
pluginIds: [...unresolvedPluginIds],
|
||||
pluginSdkResolution: "dist",
|
||||
});
|
||||
registrations.push(
|
||||
...runtimeRegistry.realtimeVoiceProviders.map((entry) => ({
|
||||
pluginId: entry.pluginId,
|
||||
provider: entry.provider,
|
||||
})),
|
||||
);
|
||||
return registrations;
|
||||
}
|
||||
|
||||
export function loadVitestRealtimeTranscriptionProviderContractRegistry(): RealtimeTranscriptionProviderContractEntry[] {
|
||||
const registrations: RealtimeTranscriptionProviderContractEntry[] = [];
|
||||
const { manifests, unresolvedPluginIds } = resolveTestApiModuleRecords(
|
||||
BUNDLED_REALTIME_TRANSCRIPTION_PLUGIN_IDS,
|
||||
);
|
||||
|
||||
for (const plugin of manifests) {
|
||||
if (!plugin.rootDir) {
|
||||
continue;
|
||||
}
|
||||
const testApiPath = path.join(plugin.rootDir, "test-api.ts");
|
||||
if (!fs.existsSync(testApiPath)) {
|
||||
continue;
|
||||
}
|
||||
const builder = resolveNamedBuilder<RealtimeTranscriptionProviderPlugin>(
|
||||
createVitestCapabilityLoader(testApiPath)(testApiPath),
|
||||
/^build.+RealtimeTranscriptionProvider$/u,
|
||||
);
|
||||
if (!builder) {
|
||||
continue;
|
||||
}
|
||||
registrations.push({
|
||||
pluginId: plugin.id,
|
||||
provider: builder(),
|
||||
});
|
||||
unresolvedPluginIds.delete(plugin.id);
|
||||
}
|
||||
|
||||
if (unresolvedPluginIds.size === 0) {
|
||||
return registrations;
|
||||
}
|
||||
|
||||
const runtimeRegistry = loadBundledCapabilityRuntimeRegistry({
|
||||
pluginIds: [...unresolvedPluginIds],
|
||||
pluginSdkResolution: "dist",
|
||||
});
|
||||
registrations.push(
|
||||
...runtimeRegistry.realtimeTranscriptionProviders.map((entry) => ({
|
||||
pluginId: entry.pluginId,
|
||||
provider: entry.provider,
|
||||
})),
|
||||
);
|
||||
return registrations;
|
||||
}
|
||||
|
||||
export function loadVitestImageGenerationProviderContractRegistry(): ImageGenerationProviderContractEntry[] {
|
||||
const registrations: ImageGenerationProviderContractEntry[] = [];
|
||||
const { manifests, unresolvedPluginIds } = resolveTestApiModuleRecords(
|
||||
|
||||
Reference in New Issue
Block a user