feat(voice-call): improve realtime Meet voice agent

* feat(voice-call): inject agent context into realtime voice

* fix(voice-call): stabilize realtime meet audio

* fix(voice-call): delegate realtime consults to agent

* Improve realtime Meet voice consult routing

* Pin voice consult delivery to call session

* Move voice changelog entries to changes

* fix(voice-call): isolate final realtime transcripts

* test(voice-call): trim redundant realtime coverage
This commit is contained in:
scoootscooob
2026-05-05 12:56:31 -07:00
committed by GitHub
parent 782963ae66
commit 79dd65e208
35 changed files with 2088 additions and 137 deletions

View File

@@ -924,6 +924,45 @@ describe("resolvePluginCapabilityProviders", () => {
});
});
it("loads requested realtime voice providers missing from active registry", () => {
const active = createEmptyPluginRegistry();
active.realtimeVoiceProviders.push({
pluginId: "openai",
pluginName: "openai",
source: "test",
provider: { id: "openai" },
} as never);
const loaded = createEmptyPluginRegistry();
loaded.realtimeVoiceProviders.push({
pluginId: "google",
pluginName: "Google",
source: "test",
provider: { id: "google" },
} as never);
mocks.loadPluginManifestRegistry.mockReturnValue({
plugins: [
{
id: "google",
origin: "bundled",
contracts: { realtimeVoiceProviders: ["google"] },
},
] as never,
diagnostics: [],
});
mocks.resolveRuntimePluginRegistry.mockImplementation((params?: unknown) =>
params === undefined ? active : loaded,
);
const provider = resolvePluginCapabilityProvider({
key: "realtimeVoiceProviders",
providerId: "google",
cfg: { plugins: { allow: ["openai", "google"] } } as OpenClawConfig,
});
expect(provider?.id).toBe("google");
expectActiveRegistryLookup(["google"]);
});
it("does not merge unrelated bundled capability providers when cfg requests one provider", () => {
const active = createEmptyPluginRegistry();
active.speechProviders.push({

View File

@@ -361,7 +361,12 @@ function filterLoadedProvidersForRequestedConfig<K extends CapabilityProviderReg
requested: Set<string>;
entries: PluginRegistry[K];
}): PluginRegistry[K] {
if (params.key !== "speechProviders" && params.key !== "mediaUnderstandingProviders") {
if (
params.key !== "speechProviders" &&
params.key !== "realtimeTranscriptionProviders" &&
params.key !== "realtimeVoiceProviders" &&
params.key !== "mediaUnderstandingProviders"
) {
return [] as unknown as PluginRegistry[K];
}
if (params.requested.size === 0) {
@@ -386,7 +391,7 @@ function resolveRequestedCapabilityPluginIds(params: {
cfg?: OpenClawConfig;
requested?: Set<string>;
}): CapabilityPluginResolution | undefined {
if (params.key !== "speechProviders" || !params.requested || params.requested.size === 0) {
if (!params.requested || params.requested.size === 0) {
return undefined;
}
const runtimePluginIds = new Set<string>();
@@ -436,9 +441,7 @@ function loadCapabilityProviderEntries<K extends CapabilityProviderRegistryKey>(
? loadedEntries
: coldEntries;
const missingRequested =
params.key === "speechProviders" && params.requested && params.requested.size > 0
? new Set(params.requested)
: undefined;
params.requested && params.requested.size > 0 ? new Set(params.requested) : undefined;
if (missingRequested) {
removeActiveProviderIds(missingRequested, entries);
}
@@ -551,17 +554,19 @@ export function resolvePluginCapabilityProviders<K extends CapabilityProviderReg
return activeProviders.map((entry) => entry.provider) as CapabilityProviderForKey<K>[];
}
}
let requestedSpeechProviders: Set<string> | undefined;
let requestedProviders: Set<string> | undefined;
if (params.key === "speechProviders") {
requestedSpeechProviders =
requestedProviders =
missingRequestedProviders ??
(activeProviders.length === 0 ? collectRequestedSpeechProviderIds(params.cfg) : undefined);
(activeProviders.length === 0
? collectRequestedCapabilityProviderIds({ key: params.key, cfg: params.cfg })
: undefined);
}
const pluginIds =
resolveRequestedCapabilityPluginIds({
key: params.key,
cfg: params.cfg,
requested: requestedSpeechProviders,
requested: requestedProviders,
}) ??
resolveCapabilityPluginIds({
key: params.key,
@@ -581,7 +586,7 @@ export function resolvePluginCapabilityProviders<K extends CapabilityProviderReg
cfg: params.cfg,
bundledCompatPluginIds: pluginIds.bundledCompatPluginIds,
loadOptions,
requested: requestedSpeechProviders,
requested: requestedProviders,
});
if (params.key !== "memoryEmbeddingProviders") {
const mergeLoadedProviders =