mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:50:43 +00:00
perf(test): trim media runner import cost
This commit is contained in:
32
src/media-understanding/defaults.constants.ts
Normal file
32
src/media-understanding/defaults.constants.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import type { MediaUnderstandingCapability } from "./types.js";
|
||||
|
||||
const MB = 1024 * 1024;
|
||||
|
||||
export const DEFAULT_MAX_CHARS = 500;
|
||||
export const DEFAULT_MAX_CHARS_BY_CAPABILITY: Record<
|
||||
MediaUnderstandingCapability,
|
||||
number | undefined
|
||||
> = {
|
||||
image: DEFAULT_MAX_CHARS,
|
||||
audio: undefined,
|
||||
video: DEFAULT_MAX_CHARS,
|
||||
};
|
||||
export const DEFAULT_MAX_BYTES: Record<MediaUnderstandingCapability, number> = {
|
||||
image: 10 * MB,
|
||||
audio: 20 * MB,
|
||||
video: 50 * MB,
|
||||
};
|
||||
export const DEFAULT_TIMEOUT_SECONDS: Record<MediaUnderstandingCapability, number> = {
|
||||
image: 60,
|
||||
audio: 60,
|
||||
video: 120,
|
||||
};
|
||||
export const DEFAULT_PROMPT: Record<MediaUnderstandingCapability, string> = {
|
||||
image: "Describe the image.",
|
||||
audio: "Transcribe the audio.",
|
||||
video: "Describe the video.",
|
||||
};
|
||||
export const DEFAULT_VIDEO_MAX_BASE64_BYTES = 70 * MB;
|
||||
export const CLI_OUTPUT_MAX_BUFFER = 5 * MB;
|
||||
export const DEFAULT_MEDIA_CONCURRENCY = 2;
|
||||
export const MIN_AUDIO_FILE_BYTES = 1024;
|
||||
@@ -5,36 +5,17 @@ import { buildMediaUnderstandingManifestMetadataRegistry } from "./manifest-meta
|
||||
import { normalizeMediaProviderId } from "./provider-registry.js";
|
||||
import { providerSupportsCapability } from "./provider-supports.js";
|
||||
import type { MediaUnderstandingCapability, MediaUnderstandingProvider } from "./types.js";
|
||||
|
||||
const MB = 1024 * 1024;
|
||||
|
||||
export const DEFAULT_MAX_CHARS = 500;
|
||||
export const DEFAULT_MAX_CHARS_BY_CAPABILITY: Record<
|
||||
MediaUnderstandingCapability,
|
||||
number | undefined
|
||||
> = {
|
||||
image: DEFAULT_MAX_CHARS,
|
||||
audio: undefined,
|
||||
video: DEFAULT_MAX_CHARS,
|
||||
};
|
||||
export const DEFAULT_MAX_BYTES: Record<MediaUnderstandingCapability, number> = {
|
||||
image: 10 * MB,
|
||||
audio: 20 * MB,
|
||||
video: 50 * MB,
|
||||
};
|
||||
export const DEFAULT_TIMEOUT_SECONDS: Record<MediaUnderstandingCapability, number> = {
|
||||
image: 60,
|
||||
audio: 60,
|
||||
video: 120,
|
||||
};
|
||||
export const DEFAULT_PROMPT: Record<MediaUnderstandingCapability, string> = {
|
||||
image: "Describe the image.",
|
||||
audio: "Transcribe the audio.",
|
||||
video: "Describe the video.",
|
||||
};
|
||||
export const DEFAULT_VIDEO_MAX_BASE64_BYTES = 70 * MB;
|
||||
export const CLI_OUTPUT_MAX_BUFFER = 5 * MB;
|
||||
export const DEFAULT_MEDIA_CONCURRENCY = 2;
|
||||
export {
|
||||
CLI_OUTPUT_MAX_BUFFER,
|
||||
DEFAULT_MAX_BYTES,
|
||||
DEFAULT_MAX_CHARS,
|
||||
DEFAULT_MAX_CHARS_BY_CAPABILITY,
|
||||
DEFAULT_MEDIA_CONCURRENCY,
|
||||
DEFAULT_PROMPT,
|
||||
DEFAULT_TIMEOUT_SECONDS,
|
||||
DEFAULT_VIDEO_MAX_BASE64_BYTES,
|
||||
MIN_AUDIO_FILE_BYTES,
|
||||
} from "./defaults.constants.js";
|
||||
|
||||
let defaultRegistryCache: Map<string, MediaUnderstandingProvider> | null = null;
|
||||
const configRegistryCache = new Map<string, Map<string, MediaUnderstandingProvider>>();
|
||||
@@ -192,10 +173,3 @@ export function providerSupportsNativePdfDocument(params: {
|
||||
const provider = registry.get(normalizeMediaProviderId(params.providerId));
|
||||
return provider?.nativeDocumentInputs?.includes("pdf") ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum audio file size in bytes below which transcription is skipped.
|
||||
* Files smaller than this threshold are almost certainly empty or corrupt
|
||||
* and would cause unhelpful API errors from Whisper/transcription providers.
|
||||
*/
|
||||
export const MIN_AUDIO_FILE_BYTES = 1024;
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
DEFAULT_MAX_CHARS_BY_CAPABILITY,
|
||||
DEFAULT_MEDIA_CONCURRENCY,
|
||||
DEFAULT_PROMPT,
|
||||
} from "./defaults.js";
|
||||
} from "./defaults.constants.js";
|
||||
import { resolveEffectiveMediaEntryCapabilities } from "./entry-capabilities.js";
|
||||
import { normalizeMediaProviderId } from "./provider-id.js";
|
||||
import { normalizeMediaUnderstandingChatType, resolveMediaUnderstandingScope } from "./scope.js";
|
||||
|
||||
@@ -27,8 +27,7 @@ import {
|
||||
CLI_OUTPUT_MAX_BUFFER,
|
||||
DEFAULT_TIMEOUT_SECONDS,
|
||||
MIN_AUDIO_FILE_BYTES,
|
||||
resolveDefaultMediaModel,
|
||||
} from "./defaults.js";
|
||||
} from "./defaults.constants.js";
|
||||
import { MediaUnderstandingSkipError } from "./errors.js";
|
||||
import { fileExists } from "./fs.js";
|
||||
import { describeImageWithModel } from "./image-runtime.js";
|
||||
@@ -632,7 +631,7 @@ export async function runProviderEntry(params: {
|
||||
});
|
||||
const model =
|
||||
entry.model?.trim() ||
|
||||
resolveDefaultMediaModel({
|
||||
(await import("./defaults.js")).resolveDefaultMediaModel({
|
||||
cfg,
|
||||
providerId,
|
||||
capability: "audio",
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { withEnvAsync } from "../test-utils/env.js";
|
||||
import { MIN_AUDIO_FILE_BYTES } from "./defaults.js";
|
||||
import { MIN_AUDIO_FILE_BYTES } from "./defaults.constants.js";
|
||||
import { createMediaAttachmentCache, normalizeMediaAttachments } from "./runner.attachments.js";
|
||||
|
||||
type MediaFixtureParams = {
|
||||
|
||||
@@ -5,6 +5,18 @@ import { withEnvAsync } from "../test-utils/env.js";
|
||||
import { runCapability } from "./runner.js";
|
||||
import { withVideoFixture } from "./runner.test-utils.js";
|
||||
|
||||
vi.mock("../media/channel-inbound-roots.js", () => ({
|
||||
resolveChannelInboundAttachmentRoots: () => undefined,
|
||||
}));
|
||||
|
||||
vi.mock("../agents/api-key-rotation.js", () => ({
|
||||
collectProviderApiKeysForExecution: ({ primaryApiKey }: { primaryApiKey?: string }) => [
|
||||
primaryApiKey ?? "test-key",
|
||||
],
|
||||
executeWithApiKeyRotation: async <T>({ execute }: { execute: (apiKey: string) => Promise<T> }) =>
|
||||
execute("test-key"),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/capability-provider-runtime.js", async () => {
|
||||
const { createEmptyCapabilityProviderMockModule } = await import("./runner.test-mocks.js");
|
||||
return createEmptyCapabilityProviderMockModule();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DEFAULT_VIDEO_MAX_BASE64_BYTES } from "./defaults.js";
|
||||
import { DEFAULT_VIDEO_MAX_BASE64_BYTES } from "./defaults.constants.js";
|
||||
|
||||
export function estimateBase64Size(bytes: number): number {
|
||||
return Math.ceil(bytes / 3) * 4;
|
||||
|
||||
@@ -3,9 +3,11 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
|
||||
type RegistryModule = typeof import("./registry.js");
|
||||
type RuntimeModule = typeof import("./runtime.js");
|
||||
type WebSearchProvidersRuntimeModule = typeof import("./web-search-providers.runtime.js");
|
||||
type ManifestRegistryModule = typeof import("./manifest-registry.js");
|
||||
type PluginAutoEnableModule = typeof import("../config/plugin-auto-enable.js");
|
||||
type WebSearchProvidersSharedModule = typeof import("./web-search-providers.shared.js");
|
||||
type PluginManifestRegistry = import("./manifest-registry.js").PluginManifestRegistry;
|
||||
type LoadPluginManifestRegistryForPluginRegistry =
|
||||
typeof import("./plugin-registry.js").loadPluginManifestRegistryForPluginRegistry;
|
||||
|
||||
const BUNDLED_WEB_SEARCH_PROVIDERS = [
|
||||
{ pluginId: "brave", id: "brave", order: 10 },
|
||||
@@ -20,13 +22,14 @@ const BUNDLED_WEB_SEARCH_PROVIDERS = [
|
||||
] as const;
|
||||
|
||||
let createEmptyPluginRegistry: RegistryModule["createEmptyPluginRegistry"];
|
||||
let loadPluginManifestRegistryMock: ReturnType<typeof vi.fn>;
|
||||
let loadPluginManifestRegistryMock: ReturnType<
|
||||
typeof vi.fn<LoadPluginManifestRegistryForPluginRegistry>
|
||||
>;
|
||||
let setActivePluginRegistry: RuntimeModule["setActivePluginRegistry"];
|
||||
let resolvePluginWebSearchProviders: WebSearchProvidersRuntimeModule["resolvePluginWebSearchProviders"];
|
||||
let resolveRuntimeWebSearchProviders: WebSearchProvidersRuntimeModule["resolveRuntimeWebSearchProviders"];
|
||||
let loadOpenClawPluginsMock: ReturnType<typeof vi.fn>;
|
||||
let loaderModule: typeof import("./loader.js");
|
||||
let manifestRegistryModule: ManifestRegistryModule;
|
||||
let pluginAutoEnableModule: PluginAutoEnableModule;
|
||||
let applyPluginAutoEnableSpy: ReturnType<typeof vi.fn>;
|
||||
let webSearchProvidersSharedModule: WebSearchProvidersSharedModule;
|
||||
@@ -135,7 +138,7 @@ function expectBundledRuntimeProviderKeys(
|
||||
);
|
||||
}
|
||||
|
||||
function createManifestRegistryFixture() {
|
||||
function createManifestRegistryFixture(): PluginManifestRegistry {
|
||||
return {
|
||||
plugins: [
|
||||
{
|
||||
@@ -316,8 +319,19 @@ function expectRuntimeProviderResolution(
|
||||
|
||||
describe("resolvePluginWebSearchProviders", () => {
|
||||
beforeAll(async () => {
|
||||
loadPluginManifestRegistryMock = vi.fn<LoadPluginManifestRegistryForPluginRegistry>();
|
||||
vi.doMock("./plugin-registry.js", async () => {
|
||||
const actual =
|
||||
await vi.importActual<typeof import("./plugin-registry.js")>("./plugin-registry.js");
|
||||
return {
|
||||
...actual,
|
||||
loadPluginManifestRegistryForPluginRegistry: (
|
||||
...args: Parameters<LoadPluginManifestRegistryForPluginRegistry>
|
||||
) => loadPluginManifestRegistryMock(...args),
|
||||
};
|
||||
});
|
||||
|
||||
({ createEmptyPluginRegistry } = await import("./registry-empty.js"));
|
||||
manifestRegistryModule = await import("./manifest-registry.js");
|
||||
loaderModule = await import("./loader.js");
|
||||
pluginAutoEnableModule = await import("../config/plugin-auto-enable.js");
|
||||
webSearchProvidersSharedModule = await import("./web-search-providers.shared.js");
|
||||
@@ -338,15 +352,8 @@ describe("resolvePluginWebSearchProviders", () => {
|
||||
autoEnabledReasons: {},
|
||||
}) as ReturnType<PluginAutoEnableModule["applyPluginAutoEnable"]>,
|
||||
);
|
||||
loadPluginManifestRegistryMock = vi
|
||||
.spyOn(manifestRegistryModule, "loadPluginManifestRegistry")
|
||||
.mockReturnValue(
|
||||
createManifestRegistryFixture() as ManifestRegistryModule["loadPluginManifestRegistry"] extends (
|
||||
...args: unknown[]
|
||||
) => infer R
|
||||
? R
|
||||
: never,
|
||||
);
|
||||
loadPluginManifestRegistryMock.mockReset();
|
||||
loadPluginManifestRegistryMock.mockReturnValue(createManifestRegistryFixture());
|
||||
loadOpenClawPluginsMock = vi
|
||||
.spyOn(loaderModule, "loadOpenClawPlugins")
|
||||
.mockImplementation((params) => {
|
||||
|
||||
Reference in New Issue
Block a user