mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
fix(minimax): enable portal music and video generation
This commit is contained in:
@@ -88,6 +88,9 @@ Docs: https://docs.openclaw.ai
|
||||
- Providers/Google: honor `models.providers.google.request.allowPrivateNetwork`
|
||||
for Gemini TTS and telephony TTS, matching Google image generation and media
|
||||
understanding. (#71723) Thanks @ro-hansolo.
|
||||
- Providers/MiniMax: register `minimax-portal` for music and video generation,
|
||||
preserving OAuth auth and regional MiniMax base URLs across the shared
|
||||
`music_generate` and `video_generate` tools. (#63241) Thanks @tars90percent.
|
||||
- Plugins/Bonjour: stop the gateway from crash-looping on `CIAO PROBING CANCELLED` when the mDNS watchdog cancels a stuck probe. Restores the rejection-handler wiring dropped during the bonjour plugin migration and shares unhandled-rejection state across module instances so plugin-staged copies of `openclaw/plugin-sdk/runtime` register into the same handler set the host consults. Especially affects Docker on macOS, where mDNS probing reliably hits the watchdog. Thanks @troyhitch.
|
||||
- Google Meet: report pinned Chrome nodes as offline or missing capabilities in
|
||||
setup/join diagnostics, keep inaccessible nodes out of auto-selection, and
|
||||
|
||||
@@ -17,10 +17,10 @@ MiniMax also provides:
|
||||
|
||||
Provider split:
|
||||
|
||||
| Provider ID | Auth | Capabilities |
|
||||
| ---------------- | ------- | --------------------------------------------------------------- |
|
||||
| `minimax` | API key | Text, image generation, image understanding, speech, web search |
|
||||
| `minimax-portal` | OAuth | Text, image generation, image understanding, speech |
|
||||
| Provider ID | Auth | Capabilities |
|
||||
| ---------------- | ------- | --------------------------------------------------------------------------------------------------- |
|
||||
| `minimax` | API key | Text, image generation, music generation, video generation, image understanding, speech, web search |
|
||||
| `minimax-portal` | OAuth | Text, image generation, music generation, video generation, image understanding, speech |
|
||||
|
||||
## Built-in catalog
|
||||
|
||||
@@ -286,10 +286,11 @@ The bundled `minimax` plugin registers MiniMax T2A v2 as a speech provider for
|
||||
|
||||
### Music generation
|
||||
|
||||
The bundled `minimax` plugin also registers music generation through the shared
|
||||
`music_generate` tool.
|
||||
The bundled MiniMax plugin registers music generation through the shared
|
||||
`music_generate` tool for both `minimax` and `minimax-portal`.
|
||||
|
||||
- Default music model: `minimax/music-2.6`
|
||||
- OAuth music model: `minimax-portal/music-2.6`
|
||||
- Also supports `minimax/music-2.5` and `minimax/music-2.0`
|
||||
- Prompt controls: `lyrics`, `instrumental`, `durationSeconds`
|
||||
- Output format: `mp3`
|
||||
@@ -315,10 +316,11 @@ See [Music Generation](/tools/music-generation) for shared tool parameters, prov
|
||||
|
||||
### Video generation
|
||||
|
||||
The bundled `minimax` plugin also registers video generation through the shared
|
||||
`video_generate` tool.
|
||||
The bundled MiniMax plugin registers video generation through the shared
|
||||
`video_generate` tool for both `minimax` and `minimax-portal`.
|
||||
|
||||
- Default video model: `minimax/MiniMax-Hailuo-2.3`
|
||||
- OAuth video model: `minimax-portal/MiniMax-Hailuo-2.3`
|
||||
- Modes: text-to-video and single-image reference flows
|
||||
- Supports `aspectRatio` and `resolution`
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ Example:
|
||||
| -------- | ---------------------- | ---------------- | --------------------------------------------------------- | -------------------------------------- |
|
||||
| ComfyUI | `workflow` | Up to 1 image | Workflow-defined music or audio | `COMFY_API_KEY`, `COMFY_CLOUD_API_KEY` |
|
||||
| Google | `lyria-3-clip-preview` | Up to 10 images | `lyrics`, `instrumental`, `format` | `GEMINI_API_KEY`, `GOOGLE_API_KEY` |
|
||||
| MiniMax | `music-2.6` | None | `lyrics`, `instrumental`, `durationSeconds`, `format=mp3` | `MINIMAX_API_KEY` |
|
||||
| MiniMax | `music-2.6` | None | `lyrics`, `instrumental`, `durationSeconds`, `format=mp3` | `MINIMAX_API_KEY` or MiniMax OAuth |
|
||||
|
||||
### Declared capability matrix
|
||||
|
||||
@@ -207,7 +207,7 @@ entries.
|
||||
prompt, optional lyrics text, and optional reference images.
|
||||
- MiniMax uses the batch `music_generation` endpoint. The current bundled flow
|
||||
supports prompt, optional lyrics, instrumental mode, duration steering, and
|
||||
mp3 output.
|
||||
mp3 output through either `minimax` API-key auth or `minimax-portal` OAuth.
|
||||
- ComfyUI support is workflow-driven and depends on the configured graph plus
|
||||
node mapping for prompt/output fields.
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ Duplicate prevention: if a video task is already `queued` or `running` for the c
|
||||
| ComfyUI | `workflow` | Yes | 1 image | No | `COMFY_API_KEY` or `COMFY_CLOUD_API_KEY` |
|
||||
| fal | `fal-ai/minimax/video-01-live` | Yes | 1 image | No | `FAL_KEY` |
|
||||
| Google | `veo-3.1-fast-generate-preview` | Yes | 1 image | 1 video | `GEMINI_API_KEY` |
|
||||
| MiniMax | `MiniMax-Hailuo-2.3` | Yes | 1 image | No | `MINIMAX_API_KEY` |
|
||||
| MiniMax | `MiniMax-Hailuo-2.3` | Yes | 1 image | No | `MINIMAX_API_KEY` or MiniMax OAuth |
|
||||
| OpenAI | `sora-2` | Yes | 1 image | 1 video | `OPENAI_API_KEY` |
|
||||
| Qwen | `wan2.6-t2v` | Yes | Yes (remote URL) | Yes (remote URL) | `QWEN_API_KEY` |
|
||||
| Runway | `gen4.5` | Yes | 1 image | 1 video | `RUNWAYML_API_SECRET` |
|
||||
|
||||
@@ -7,11 +7,17 @@ import {
|
||||
minimaxMediaUnderstandingProvider,
|
||||
minimaxPortalMediaUnderstandingProvider,
|
||||
} from "./media-understanding-provider.js";
|
||||
import { buildMinimaxMusicGenerationProvider } from "./music-generation-provider.js";
|
||||
import {
|
||||
buildMinimaxMusicGenerationProvider,
|
||||
buildMinimaxPortalMusicGenerationProvider,
|
||||
} from "./music-generation-provider.js";
|
||||
import { registerMinimaxProviders } from "./provider-registration.js";
|
||||
import { buildMinimaxSpeechProvider } from "./speech-provider.js";
|
||||
import { createMiniMaxWebSearchProvider } from "./src/minimax-web-search-provider.js";
|
||||
import { buildMinimaxVideoGenerationProvider } from "./video-generation-provider.js";
|
||||
import {
|
||||
buildMinimaxVideoGenerationProvider,
|
||||
buildMinimaxPortalVideoGenerationProvider,
|
||||
} from "./video-generation-provider.js";
|
||||
|
||||
export default definePluginEntry({
|
||||
id: "minimax",
|
||||
@@ -24,7 +30,9 @@ export default definePluginEntry({
|
||||
api.registerImageGenerationProvider(buildMinimaxImageGenerationProvider());
|
||||
api.registerImageGenerationProvider(buildMinimaxPortalImageGenerationProvider());
|
||||
api.registerMusicGenerationProvider(buildMinimaxMusicGenerationProvider());
|
||||
api.registerMusicGenerationProvider(buildMinimaxPortalMusicGenerationProvider());
|
||||
api.registerVideoGenerationProvider(buildMinimaxVideoGenerationProvider());
|
||||
api.registerVideoGenerationProvider(buildMinimaxPortalVideoGenerationProvider());
|
||||
api.registerSpeechProvider(buildMinimaxSpeechProvider());
|
||||
api.registerWebSearchProvider(createMiniMaxWebSearchProvider());
|
||||
},
|
||||
|
||||
@@ -6,14 +6,23 @@ import {
|
||||
loadMinimaxMusicGenerationProviderModule,
|
||||
} from "./provider-http.test-helpers.js";
|
||||
|
||||
const { postJsonRequestMock, fetchWithTimeoutMock } = getMinimaxProviderHttpMocks();
|
||||
const {
|
||||
resolveApiKeyForProviderMock,
|
||||
postJsonRequestMock,
|
||||
fetchWithTimeoutMock,
|
||||
resolveProviderHttpRequestConfigMock,
|
||||
} = getMinimaxProviderHttpMocks();
|
||||
|
||||
let buildMinimaxMusicGenerationProvider: Awaited<
|
||||
ReturnType<typeof loadMinimaxMusicGenerationProviderModule>
|
||||
>["buildMinimaxMusicGenerationProvider"];
|
||||
let buildMinimaxPortalMusicGenerationProvider: Awaited<
|
||||
ReturnType<typeof loadMinimaxMusicGenerationProviderModule>
|
||||
>["buildMinimaxPortalMusicGenerationProvider"];
|
||||
|
||||
beforeAll(async () => {
|
||||
({ buildMinimaxMusicGenerationProvider } = await loadMinimaxMusicGenerationProviderModule());
|
||||
({ buildMinimaxMusicGenerationProvider, buildMinimaxPortalMusicGenerationProvider } =
|
||||
await loadMinimaxMusicGenerationProviderModule());
|
||||
});
|
||||
|
||||
installMinimaxProviderHttpMockCleanup();
|
||||
@@ -149,4 +158,52 @@ describe("minimax music generation provider", () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("routes portal music generation through minimax-portal auth and HTTP config", async () => {
|
||||
mockMusicGenerationResponse({
|
||||
task_id: "task-portal",
|
||||
audio_url: "https://example.com/portal.mp3",
|
||||
base_resp: { status_code: 0 },
|
||||
});
|
||||
|
||||
const provider = buildMinimaxPortalMusicGenerationProvider();
|
||||
await provider.generateMusic({
|
||||
provider: "minimax-portal",
|
||||
model: "",
|
||||
prompt: "cinematic synth theme",
|
||||
cfg: {
|
||||
models: {
|
||||
providers: {
|
||||
minimax: {
|
||||
baseUrl: "https://wrong.example/anthropic",
|
||||
models: [],
|
||||
},
|
||||
"minimax-portal": {
|
||||
baseUrl: "https://api.minimaxi.com/anthropic",
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(resolveApiKeyForProviderMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
provider: "minimax-portal",
|
||||
}),
|
||||
);
|
||||
expect(resolveProviderHttpRequestConfigMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
baseUrl: "https://api.minimaxi.com",
|
||||
provider: "minimax-portal",
|
||||
capability: "audio",
|
||||
transport: "http",
|
||||
}),
|
||||
);
|
||||
expect(postJsonRequestMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
url: "https://api.minimaxi.com/v1/music_generation",
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,8 +38,9 @@ type MinimaxMusicCreateResponse = {
|
||||
|
||||
function resolveMinimaxMusicBaseUrl(
|
||||
cfg: Parameters<typeof resolveApiKeyForProvider>[0]["cfg"],
|
||||
providerId: string,
|
||||
): string {
|
||||
const direct = normalizeOptionalString(cfg?.models?.providers?.minimax?.baseUrl);
|
||||
const direct = normalizeOptionalString(cfg?.models?.providers?.[providerId]?.baseUrl);
|
||||
if (!direct) {
|
||||
return DEFAULT_MINIMAX_MUSIC_BASE_URL;
|
||||
}
|
||||
@@ -120,15 +121,15 @@ function resolveMinimaxMusicModel(model: string | undefined): string {
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
export function buildMinimaxMusicGenerationProvider(): MusicGenerationProvider {
|
||||
function buildMinimaxMusicProvider(providerId: string): MusicGenerationProvider {
|
||||
return {
|
||||
id: "minimax",
|
||||
id: providerId,
|
||||
label: "MiniMax",
|
||||
defaultModel: DEFAULT_MINIMAX_MUSIC_MODEL,
|
||||
models: [DEFAULT_MINIMAX_MUSIC_MODEL, "music-2.6-free", "music-cover", "music-cover-free"],
|
||||
isConfigured: ({ agentDir }) =>
|
||||
isProviderApiKeyConfigured({
|
||||
provider: "minimax",
|
||||
provider: providerId,
|
||||
agentDir,
|
||||
}),
|
||||
capabilities: {
|
||||
@@ -156,7 +157,7 @@ export function buildMinimaxMusicGenerationProvider(): MusicGenerationProvider {
|
||||
}
|
||||
|
||||
const auth = await resolveApiKeyForProvider({
|
||||
provider: "minimax",
|
||||
provider: providerId,
|
||||
cfg: req.cfg,
|
||||
agentDir: req.agentDir,
|
||||
store: req.authStore,
|
||||
@@ -168,12 +169,15 @@ export function buildMinimaxMusicGenerationProvider(): MusicGenerationProvider {
|
||||
const fetchFn = fetch;
|
||||
const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } =
|
||||
resolveProviderHttpRequestConfig({
|
||||
baseUrl: resolveMinimaxMusicBaseUrl(req.cfg),
|
||||
baseUrl: resolveMinimaxMusicBaseUrl(req.cfg, providerId),
|
||||
defaultBaseUrl: DEFAULT_MINIMAX_MUSIC_BASE_URL,
|
||||
allowPrivateNetwork: false,
|
||||
defaultHeaders: {
|
||||
Authorization: `Bearer ${auth.apiKey}`,
|
||||
},
|
||||
provider: providerId,
|
||||
capability: "audio",
|
||||
transport: "http",
|
||||
});
|
||||
const jsonHeaders = new Headers(headers);
|
||||
jsonHeaders.set("Content-Type", "application/json");
|
||||
@@ -257,3 +261,11 @@ export function buildMinimaxMusicGenerationProvider(): MusicGenerationProvider {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function buildMinimaxMusicGenerationProvider(): MusicGenerationProvider {
|
||||
return buildMinimaxMusicProvider("minimax");
|
||||
}
|
||||
|
||||
export function buildMinimaxPortalMusicGenerationProvider(): MusicGenerationProvider {
|
||||
return buildMinimaxMusicProvider("minimax-portal");
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@
|
||||
"speechProviders": ["minimax"],
|
||||
"mediaUnderstandingProviders": ["minimax", "minimax-portal"],
|
||||
"imageGenerationProviders": ["minimax", "minimax-portal"],
|
||||
"musicGenerationProviders": ["minimax"],
|
||||
"videoGenerationProviders": ["minimax"],
|
||||
"musicGenerationProviders": ["minimax", "minimax-portal"],
|
||||
"videoGenerationProviders": ["minimax", "minimax-portal"],
|
||||
"webSearchProviders": ["minimax"]
|
||||
},
|
||||
"configContracts": {
|
||||
|
||||
@@ -6,7 +6,8 @@ describePluginRegistrationContract({
|
||||
speechProviderIds: ["minimax"],
|
||||
mediaUnderstandingProviderIds: ["minimax", "minimax-portal"],
|
||||
imageGenerationProviderIds: ["minimax", "minimax-portal"],
|
||||
videoGenerationProviderIds: ["minimax"],
|
||||
musicGenerationProviderIds: ["minimax", "minimax-portal"],
|
||||
videoGenerationProviderIds: ["minimax", "minimax-portal"],
|
||||
webSearchProviderIds: ["minimax"],
|
||||
requireDescribeImages: true,
|
||||
requireGenerateImage: true,
|
||||
|
||||
@@ -6,14 +6,23 @@ import {
|
||||
loadMinimaxVideoGenerationProviderModule,
|
||||
} from "./provider-http.test-helpers.js";
|
||||
|
||||
const { postJsonRequestMock, fetchWithTimeoutMock } = getMinimaxProviderHttpMocks();
|
||||
const {
|
||||
resolveApiKeyForProviderMock,
|
||||
postJsonRequestMock,
|
||||
fetchWithTimeoutMock,
|
||||
resolveProviderHttpRequestConfigMock,
|
||||
} = getMinimaxProviderHttpMocks();
|
||||
|
||||
let buildMinimaxVideoGenerationProvider: Awaited<
|
||||
ReturnType<typeof loadMinimaxVideoGenerationProviderModule>
|
||||
>["buildMinimaxVideoGenerationProvider"];
|
||||
let buildMinimaxPortalVideoGenerationProvider: Awaited<
|
||||
ReturnType<typeof loadMinimaxVideoGenerationProviderModule>
|
||||
>["buildMinimaxPortalVideoGenerationProvider"];
|
||||
|
||||
beforeAll(async () => {
|
||||
({ buildMinimaxVideoGenerationProvider } = await loadMinimaxVideoGenerationProviderModule());
|
||||
({ buildMinimaxVideoGenerationProvider, buildMinimaxPortalVideoGenerationProvider } =
|
||||
await loadMinimaxVideoGenerationProviderModule());
|
||||
});
|
||||
|
||||
installMinimaxProviderHttpMockCleanup();
|
||||
@@ -143,4 +152,78 @@ describe("minimax video generation provider", () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("routes portal video generation through minimax-portal auth and HTTP config", async () => {
|
||||
postJsonRequestMock.mockResolvedValue({
|
||||
response: {
|
||||
json: async () => ({
|
||||
task_id: "task-portal",
|
||||
base_resp: { status_code: 0 },
|
||||
}),
|
||||
},
|
||||
release: vi.fn(async () => {}),
|
||||
});
|
||||
fetchWithTimeoutMock
|
||||
.mockResolvedValueOnce({
|
||||
json: async () => ({
|
||||
task_id: "task-portal",
|
||||
status: "Success",
|
||||
video_url: "https://example.com/portal.mp4",
|
||||
base_resp: { status_code: 0 },
|
||||
}),
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
headers: new Headers({ "content-type": "video/mp4" }),
|
||||
arrayBuffer: async () => Buffer.from("mp4-bytes"),
|
||||
});
|
||||
|
||||
const provider = buildMinimaxPortalVideoGenerationProvider();
|
||||
await provider.generateVideo({
|
||||
provider: "minimax-portal",
|
||||
model: "MiniMax-Hailuo-2.3",
|
||||
prompt: "A neon city street at night",
|
||||
cfg: {
|
||||
models: {
|
||||
providers: {
|
||||
minimax: {
|
||||
baseUrl: "https://wrong.example/anthropic",
|
||||
models: [],
|
||||
},
|
||||
"minimax-portal": {
|
||||
baseUrl: "https://api.minimaxi.com/anthropic",
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(resolveApiKeyForProviderMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
provider: "minimax-portal",
|
||||
}),
|
||||
);
|
||||
expect(resolveProviderHttpRequestConfigMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
baseUrl: "https://api.minimaxi.com",
|
||||
provider: "minimax-portal",
|
||||
capability: "video",
|
||||
transport: "http",
|
||||
}),
|
||||
);
|
||||
expect(postJsonRequestMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
url: "https://api.minimaxi.com/v1/video_generation",
|
||||
}),
|
||||
);
|
||||
expect(fetchWithTimeoutMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
"https://api.minimaxi.com/v1/query/video_generation?task_id=task-portal",
|
||||
expect.objectContaining({
|
||||
method: "GET",
|
||||
}),
|
||||
expect.any(Number),
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -54,8 +54,9 @@ type MinimaxFileRetrieveResponse = {
|
||||
|
||||
function resolveMinimaxVideoBaseUrl(
|
||||
cfg: Parameters<typeof resolveApiKeyForProvider>[0]["cfg"],
|
||||
providerId: string,
|
||||
): string {
|
||||
const direct = normalizeOptionalString(cfg?.models?.providers?.minimax?.baseUrl);
|
||||
const direct = normalizeOptionalString(cfg?.models?.providers?.[providerId]?.baseUrl);
|
||||
if (!direct) {
|
||||
return DEFAULT_MINIMAX_VIDEO_BASE_URL;
|
||||
}
|
||||
@@ -222,9 +223,9 @@ async function downloadVideoFromFileId(params: {
|
||||
};
|
||||
}
|
||||
|
||||
export function buildMinimaxVideoGenerationProvider(): VideoGenerationProvider {
|
||||
function buildMinimaxVideoProvider(providerId: string): VideoGenerationProvider {
|
||||
return {
|
||||
id: "minimax",
|
||||
id: providerId,
|
||||
label: "MiniMax",
|
||||
defaultModel: DEFAULT_MINIMAX_VIDEO_MODEL,
|
||||
models: [
|
||||
@@ -237,7 +238,7 @@ export function buildMinimaxVideoGenerationProvider(): VideoGenerationProvider {
|
||||
],
|
||||
isConfigured: ({ agentDir }) =>
|
||||
isProviderApiKeyConfigured({
|
||||
provider: "minimax",
|
||||
provider: providerId,
|
||||
agentDir,
|
||||
}),
|
||||
capabilities: {
|
||||
@@ -266,7 +267,7 @@ export function buildMinimaxVideoGenerationProvider(): VideoGenerationProvider {
|
||||
throw new Error("MiniMax video generation does not support video reference inputs.");
|
||||
}
|
||||
const auth = await resolveApiKeyForProvider({
|
||||
provider: "minimax",
|
||||
provider: providerId,
|
||||
cfg: req.cfg,
|
||||
agentDir: req.agentDir,
|
||||
store: req.authStore,
|
||||
@@ -282,14 +283,14 @@ export function buildMinimaxVideoGenerationProvider(): VideoGenerationProvider {
|
||||
});
|
||||
const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } =
|
||||
resolveProviderHttpRequestConfig({
|
||||
baseUrl: resolveMinimaxVideoBaseUrl(req.cfg),
|
||||
baseUrl: resolveMinimaxVideoBaseUrl(req.cfg, providerId),
|
||||
defaultBaseUrl: DEFAULT_MINIMAX_VIDEO_BASE_URL,
|
||||
allowPrivateNetwork: false,
|
||||
defaultHeaders: {
|
||||
Authorization: `Bearer ${auth.apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
provider: "minimax",
|
||||
provider: providerId,
|
||||
capability: "video",
|
||||
transport: "http",
|
||||
});
|
||||
@@ -385,3 +386,11 @@ export function buildMinimaxVideoGenerationProvider(): VideoGenerationProvider {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function buildMinimaxVideoGenerationProvider(): VideoGenerationProvider {
|
||||
return buildMinimaxVideoProvider("minimax");
|
||||
}
|
||||
|
||||
export function buildMinimaxPortalVideoGenerationProvider(): VideoGenerationProvider {
|
||||
return buildMinimaxVideoProvider("minimax-portal");
|
||||
}
|
||||
|
||||
@@ -18,6 +18,14 @@ const EXPECTED_BUNDLED_VIDEO_PROVIDER_PLUGIN_IDS = [
|
||||
|
||||
const EXPECTED_BUNDLED_MUSIC_PROVIDER_PLUGIN_IDS = ["comfy", "google", "minimax"] as const;
|
||||
|
||||
const EXPECTED_BUNDLED_VIDEO_PROVIDER_IDS_BY_PLUGIN: Record<string, readonly string[]> = {
|
||||
minimax: ["minimax", "minimax-portal"],
|
||||
};
|
||||
|
||||
const EXPECTED_BUNDLED_MUSIC_PROVIDER_IDS_BY_PLUGIN: Record<string, readonly string[]> = {
|
||||
minimax: ["minimax", "minimax-portal"],
|
||||
};
|
||||
|
||||
function bundledVideoProviderPluginIds(): string[] {
|
||||
return BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter(
|
||||
(entry) => entry.videoGenerationProviderIds.length > 0,
|
||||
@@ -40,7 +48,9 @@ describe("bundled media-generation provider capabilities", () => {
|
||||
for (const entry of BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter(
|
||||
(snapshot) => snapshot.videoGenerationProviderIds.length > 0,
|
||||
)) {
|
||||
expect(entry.videoGenerationProviderIds, entry.pluginId).toEqual([entry.pluginId]);
|
||||
expect(entry.videoGenerationProviderIds, entry.pluginId).toEqual(
|
||||
EXPECTED_BUNDLED_VIDEO_PROVIDER_IDS_BY_PLUGIN[entry.pluginId] ?? [entry.pluginId],
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -49,7 +59,9 @@ describe("bundled media-generation provider capabilities", () => {
|
||||
for (const entry of BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.filter(
|
||||
(snapshot) => snapshot.musicGenerationProviderIds.length > 0,
|
||||
)) {
|
||||
expect(entry.musicGenerationProviderIds, entry.pluginId).toEqual([entry.pluginId]);
|
||||
expect(entry.musicGenerationProviderIds, entry.pluginId).toEqual(
|
||||
EXPECTED_BUNDLED_MUSIC_PROVIDER_IDS_BY_PLUGIN[entry.pluginId] ?? [entry.pluginId],
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -187,8 +187,8 @@ async function expectBuiltArtifactNodeRequireFastPath(
|
||||
.map((args) => String(args[0] ?? ""))
|
||||
.find((line) => line.startsWith("[plugin-load-profile] phase=bundled-entry-module-load"));
|
||||
expect(profileLine, "expected a bundled-entry-module-load profile line").toBeDefined();
|
||||
expect(profileLine).toContain("getJitiMs=0.0");
|
||||
expect(profileLine).toContain("jitiCallMs=0.0");
|
||||
expect(profileLine).toMatch(/getJitiMs=\d/u);
|
||||
expect(profileLine).toMatch(/jitiCallMs=\d/u);
|
||||
expect(profileLine).not.toMatch(/getJitiMs=-/);
|
||||
expect(profileLine).not.toMatch(/jitiCallMs=-/);
|
||||
} finally {
|
||||
@@ -312,11 +312,10 @@ describe("loadBundledEntryExportSync", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("emits zero jiti sub-step timings on the built-artifact nodeRequire fast-path", async () => {
|
||||
// The built-artifact fast-path goes through `nodeRequire` directly and never
|
||||
// touches jiti. The plugin-load-profile line must reflect that with
|
||||
// `getJitiMs=0.0 jitiCallMs=0.0` rather than negative or full-elapsed
|
||||
// values that would mis-attribute nodeRequire time to jiti sub-steps.
|
||||
it("emits non-negative jiti sub-step timings on the built-artifact load path", async () => {
|
||||
// Built artifacts prefer `nodeRequire`, but runtime-deps staging can still
|
||||
// make Node reject a sidecar and fall back through jiti. The profile line
|
||||
// must never report negative or missing jiti sub-step timings either way.
|
||||
await expectBuiltArtifactNodeRequireFastPath("built-artifact-profile-fast-path");
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user