From ba1a6722bb6707a37fdbc25b966c7cc1d286a2e5 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 31 Jul 2026 20:35:43 +0800 Subject: [PATCH] feat(plugins): externalize Vydra provider (#116813) --- docs/plugins/plugin-inventory.md | 8 +-- docs/plugins/reference/vydra.md | 2 +- docs/providers/vydra.md | 23 ++++--- docs/tools/video-generation.md | 4 +- extensions/vydra/README.md | 13 ++++ extensions/vydra/image-generation-provider.ts | 2 +- extensions/vydra/index.ts | 2 +- extensions/vydra/package.json | 26 +++++++- extensions/vydra/video-generation-provider.ts | 4 +- package.json | 1 + .../official-external-provider-catalog.json | 60 +++++++++++++++++++ src/cli/plugins-location-bridges.test.ts | 1 + .../official-external-plugin-catalog.test.ts | 19 ++++++ .../bundled-plugin-build-entries.test.ts | 8 +++ 14 files changed, 150 insertions(+), 23 deletions(-) create mode 100644 extensions/vydra/README.md diff --git a/docs/plugins/plugin-inventory.md b/docs/plugins/plugin-inventory.md index e8a1162c8435..f49327f19354 100644 --- a/docs/plugins/plugin-inventory.md +++ b/docs/plugins/plugin-inventory.md @@ -51,7 +51,7 @@ Each entry lists the package, distribution route, and description. ## Core npm package -64 plugins +63 plugins - **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint. @@ -169,8 +169,6 @@ Each entry lists the package, distribution route, and description. - **[volcengine](/plugins/reference/volcengine)** (`@openclaw/volcengine-provider`) - included in OpenClaw. Adds Volcengine, Volcengine Plan model provider support to OpenClaw. -- **[vydra](/plugins/reference/vydra)** (`@openclaw/vydra-provider`) - included in OpenClaw. Adds Vydra model provider support to OpenClaw. - - **[web-readability](/plugins/reference/web-readability)** (`@openclaw/web-readability-plugin`) - included in OpenClaw. Extract readable article content from local HTML web fetch responses. - **[webhooks](/plugins/reference/webhooks)** (`@openclaw/webhooks`) - included in OpenClaw. Authenticated inbound webhooks that bind external automation to OpenClaw TaskFlows. @@ -183,7 +181,7 @@ Each entry lists the package, distribution route, and description. ## Official external packages -81 plugins +82 plugins - **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management. @@ -337,6 +335,8 @@ Each entry lists the package, distribution route, and description. - **[voyage](/plugins/reference/voyage)** (`@openclaw/voyage-provider`) - npm; ClawHub: `clawhub:@openclaw/voyage-provider`. Adds memory embedding provider support. +- **[vydra](/plugins/reference/vydra)** (`@openclaw/vydra-provider`) - npm; ClawHub: `clawhub:@openclaw/vydra-provider`. Adds Vydra model provider support to OpenClaw. + - **[whatsapp](/plugins/reference/whatsapp)** (`@openclaw/whatsapp`) - ClawHub: `clawhub:@openclaw/whatsapp`; npm. OpenClaw WhatsApp channel plugin for WhatsApp Web chats. - **[zai](/plugins/reference/zai)** (`@openclaw/zai-provider`) - npm; ClawHub: `clawhub:@openclaw/zai-provider`. Adds Z.AI model provider support to OpenClaw. diff --git a/docs/plugins/reference/vydra.md b/docs/plugins/reference/vydra.md index be5dc7d3cd22..70fa9253a934 100644 --- a/docs/plugins/reference/vydra.md +++ b/docs/plugins/reference/vydra.md @@ -12,7 +12,7 @@ Adds Vydra model provider support to OpenClaw. ## Distribution - Package: `@openclaw/vydra-provider` -- Install route: included in OpenClaw +- Install route: npm; ClawHub: `clawhub:@openclaw/vydra-provider` ## Surface diff --git a/docs/providers/vydra.md b/docs/providers/vydra.md index acacc06c9950..ca8af9398071 100644 --- a/docs/providers/vydra.md +++ b/docs/providers/vydra.md @@ -6,7 +6,7 @@ read_when: title: "Vydra" --- -The bundled Vydra plugin adds: +The official Vydra plugin adds: - Image generation via `vydra/grok-imagine` - Video generation via `vydra/veo3` (text-to-video) and `vydra/kling` (image-to-video) @@ -17,7 +17,7 @@ OpenClaw uses the same `VYDRA_API_KEY` for all three capabilities. | Property | Value | | --------------- | ------------------------------------------------------------------------- | | Provider id | `vydra` | -| Plugin | bundled, `enabledByDefault: true` | +| Plugin | `@openclaw/vydra-provider` | | Auth env var | `VYDRA_API_KEY` | | Onboarding flag | `--auth-choice vydra-api-key` | | Direct CLI flag | `--vydra-api-key ` | @@ -31,6 +31,13 @@ Use `https://www.vydra.ai/api/v1` as the base URL. Vydra's apex host (`https://v ## Setup + + ```bash + openclaw plugins install @openclaw/vydra-provider + openclaw gateway restart + ``` + + ```bash openclaw onboard --auth-choice vydra-api-key @@ -52,7 +59,7 @@ Use `https://www.vydra.ai/api/v1` as the base URL. Vydra's apex host (`https://v - Default and only bundled image model: + Default and only Vydra image model: - `vydra/grok-imagine` @@ -70,7 +77,7 @@ Use `https://www.vydra.ai/api/v1` as the base URL. Vydra's apex host (`https://v } ``` - Bundled support is text-to-image only, at most one image per request. Vydra's hosted edit routes expect remote image URLs, and the bundled plugin does not add a Vydra-specific upload bridge. + Vydra support is text-to-image only, at most one image per request. Vydra's hosted edit routes expect remote image URLs, and the plugin does not add a Vydra-specific upload bridge. See [Image Generation](/tools/image-generation) for shared tool parameters, provider selection, and failover behavior. @@ -101,8 +108,8 @@ Use `https://www.vydra.ai/api/v1` as the base URL. Vydra's apex host (`https://v Notes: - `vydra/kling` rejects local file uploads up front; only a remote image URL reference works. - - Vydra's `kling` HTTP route has been inconsistent about whether it requires `image_url` or `video_url`; the bundled provider sends the same remote image URL in both fields. - - The bundled plugin stays conservative and does not forward undocumented style knobs such as aspect ratio, resolution, watermark, or generated audio. + - Vydra's `kling` HTTP route has been inconsistent about whether it requires `image_url` or `video_url`; the plugin sends the same remote image URL in both fields. + - The plugin stays conservative and does not forward undocumented style knobs such as aspect ratio, resolution, watermark, or generated audio. See [Video Generation](/tools/video-generation) for shared tool parameters, provider selection, and failover behavior. @@ -119,7 +126,7 @@ Use `https://www.vydra.ai/api/v1` as the base URL. Vydra's apex host (`https://v pnpm test:live -- extensions/vydra/vydra.live.test.ts ``` - The bundled Vydra live file covers: + The Vydra live file covers: - `vydra/veo3` text-to-video - `vydra/kling` image-to-video using a remote image URL @@ -154,7 +161,7 @@ Use `https://www.vydra.ai/api/v1` as the base URL. Vydra's apex host (`https://v - Model: `elevenlabs/tts` - Voice id: `21m00Tcm4TlvDq8ikWAM` ("Rachel") - The bundled plugin exposes this one known-good default voice and returns MP3 audio files. + The plugin exposes this one known-good default voice and returns MP3 audio files. diff --git a/docs/tools/video-generation.md b/docs/tools/video-generation.md index 8438265e17a6..e94aedb2966b 100644 --- a/docs/tools/video-generation.md +++ b/docs/tools/video-generation.md @@ -146,7 +146,7 @@ the shared live sweep: | Qwen | ✓ | ✓ | ✓ | `generate`, `imageToVideo`; `videoToVideo` skipped because this provider needs remote `http(s)` video URLs | | Runway | ✓ | ✓ | ✓ | `generate`, `imageToVideo`; `videoToVideo` runs only when the selected model is `runway/gen4_aleph` | | Together | ✓ | ✓ | - | `generate`, `imageToVideo` | -| Vydra | ✓ | ✓ | - | `generate`; shared `imageToVideo` skipped because bundled `veo3` is text-only and bundled `kling` requires a remote image URL | +| Vydra | ✓ | ✓ | - | `generate`; shared `imageToVideo` skipped because `veo3` is text-only and `kling` requires a remote image URL | | xAI | ✓ | ✓ | ✓ | Classic supports all modes; Video 1.5 is image-to-video only; remote MP4 input keeps `videoToVideo` out of the shared sweep | ## Tool parameters @@ -416,7 +416,7 @@ Automatic fallback across authenticated providers is always enabled. A per-call Uses `https://www.vydra.ai/api/v1` directly to avoid auth-dropping - redirects. `veo3` is bundled as text-to-video only; `kling` requires + redirects. `veo3` is text-to-video only; `kling` requires a remote image URL. diff --git a/extensions/vydra/README.md b/extensions/vydra/README.md new file mode 100644 index 000000000000..cf545431d9bf --- /dev/null +++ b/extensions/vydra/README.md @@ -0,0 +1,13 @@ +# OpenClaw Vydra Provider + +Official OpenClaw provider plugin for Vydra image, video, and speech generation. + +Install from OpenClaw: + +```bash +openclaw plugins install @openclaw/vydra-provider +openclaw gateway restart +``` + +Set `VYDRA_API_KEY`, then configure an image, video, or speech model. See + for capability details and examples. diff --git a/extensions/vydra/image-generation-provider.ts b/extensions/vydra/image-generation-provider.ts index d0db23ffd8a5..b9b183fe5c8b 100644 --- a/extensions/vydra/image-generation-provider.ts +++ b/extensions/vydra/image-generation-provider.ts @@ -47,7 +47,7 @@ export function buildVydraImageGenerationProvider(): ImageGenerationProvider { async generateImage(req) { if ((req.inputImages?.length ?? 0) > 0) { throw new Error( - "Vydra image generation currently supports text-to-image only in the bundled plugin.", + "Vydra image generation currently supports text-to-image only in the Vydra plugin.", ); } if ((req.count ?? 1) > 1) { diff --git a/extensions/vydra/index.ts b/extensions/vydra/index.ts index 8944dca30d49..b93c9c7e60c3 100644 --- a/extensions/vydra/index.ts +++ b/extensions/vydra/index.ts @@ -11,7 +11,7 @@ const PROVIDER_ID = "vydra"; export default definePluginEntry({ id: PROVIDER_ID, name: "Vydra Provider", - description: "Bundled Vydra image, video, and speech provider", + description: "Vydra image, video, and speech provider", register(api) { api.registerProvider({ id: PROVIDER_ID, diff --git a/extensions/vydra/package.json b/extensions/vydra/package.json index b16403b07257..59cdcc719443 100644 --- a/extensions/vydra/package.json +++ b/extensions/vydra/package.json @@ -1,8 +1,11 @@ { "name": "@openclaw/vydra-provider", "version": "2026.7.2", - "private": true, - "description": "OpenClaw Vydra media provider plugin", + "description": "OpenClaw Vydra media provider plugin.", + "repository": { + "type": "git", + "url": "https://github.com/openclaw/openclaw" + }, "type": "module", "devDependencies": { "@openclaw/plugin-sdk": "workspace:*" @@ -10,6 +13,23 @@ "openclaw": { "extensions": [ "./index.ts" - ] + ], + "install": { + "clawhubSpec": "clawhub:@openclaw/vydra-provider", + "npmSpec": "@openclaw/vydra-provider", + "defaultChoice": "npm", + "minHostVersion": ">=2026.7.2" + }, + "compat": { + "pluginApi": ">=2026.7.2" + }, + "build": { + "openclawVersion": "2026.7.2", + "bundledDist": false + }, + "release": { + "publishToClawHub": true, + "publishToNpm": true + } } } diff --git a/extensions/vydra/video-generation-provider.ts b/extensions/vydra/video-generation-provider.ts index a2b19f1b7b3f..a0f93657cd8a 100644 --- a/extensions/vydra/video-generation-provider.ts +++ b/extensions/vydra/video-generation-provider.ts @@ -44,9 +44,7 @@ function resolveVydraVideoRequestBody( }; } if ((req.inputImages?.length ?? 0) > 0) { - throw new Error( - `Vydra ${model} does not support image reference inputs in the bundled plugin.`, - ); + throw new Error(`Vydra ${model} does not support image reference inputs in the Vydra plugin.`); } return { model, diff --git a/package.json b/package.json index 28b0fed71bc7..65b0b90f8caa 100644 --- a/package.json +++ b/package.json @@ -317,6 +317,7 @@ "!dist/extensions/vercel-ai-gateway/**", "!dist/extensions/voice-call/**", "!dist/extensions/voyage/**", + "!dist/extensions/vydra/**", "!dist/extensions/whatsapp/**", "!dist/extensions/zai/**", "!dist/extensions/zalo/**", diff --git a/scripts/lib/official-external-provider-catalog.json b/scripts/lib/official-external-provider-catalog.json index 9388b8164643..22d2137992a3 100644 --- a/scripts/lib/official-external-provider-catalog.json +++ b/scripts/lib/official-external-provider-catalog.json @@ -1528,6 +1528,66 @@ } } }, + { + "name": "@openclaw/vydra-provider", + "description": "OpenClaw Vydra media provider plugin.", + "source": "official", + "kind": "provider", + "openclaw": { + "plugin": { + "id": "vydra", + "label": "Vydra" + }, + "providers": [ + { + "id": "vydra", + "name": "Vydra", + "docs": "/providers/vydra", + "categories": [ + "cloud", + "media" + ], + "envVars": [ + "VYDRA_API_KEY" + ], + "authChoices": [ + { + "method": "api-key", + "choiceId": "vydra-api-key", + "choiceLabel": "Vydra API key", + "groupId": "vydra", + "groupLabel": "Vydra", + "groupHint": "Image, video, and speech", + "optionKey": "vydraApiKey", + "cliFlag": "--vydra-api-key", + "cliOption": "--vydra-api-key ", + "cliDescription": "Vydra API key", + "onboardingScopes": [ + "image-generation" + ] + } + ] + } + ], + "contracts": { + "speechProviders": [ + "vydra" + ], + "imageGenerationProviders": [ + "vydra" + ], + "videoGenerationProviders": [ + "vydra" + ] + }, + "install": { + "clawhubSpec": "clawhub:@openclaw/vydra-provider", + "npmSpec": "@openclaw/vydra-provider", + "defaultChoice": "npm", + "minHostVersion": ">=2026.7.2" + } + } + }, { "name": "@openclaw/zai-provider", "description": "OpenClaw Z.AI provider plugin", diff --git a/src/cli/plugins-location-bridges.test.ts b/src/cli/plugins-location-bridges.test.ts index f6c1a75a78bb..dc519e5641ce 100644 --- a/src/cli/plugins-location-bridges.test.ts +++ b/src/cli/plugins-location-bridges.test.ts @@ -169,6 +169,7 @@ describe("listPersistedBundledPluginLocationBridges", () => { ["synthetic", "@openclaw/synthetic-provider", true], ["teams-meetings", "@openclaw/teams-meetings", true], ["voyage", "@openclaw/voyage-provider", true], + ["vydra", "@openclaw/vydra-provider", true], ["zoom-meetings", "@openclaw/zoom-meetings", true], ] as const)( "externalizes the shipped bundled %s plugin using official install metadata", diff --git a/src/plugins/official-external-plugin-catalog.test.ts b/src/plugins/official-external-plugin-catalog.test.ts index c4a04dd73614..0d45808ae313 100644 --- a/src/plugins/official-external-plugin-catalog.test.ts +++ b/src/plugins/official-external-plugin-catalog.test.ts @@ -2020,6 +2020,25 @@ describe("official external plugin catalog", () => { ]); }); + it("lists Vydra as an official external media provider", () => { + const vydra = expectCatalogEntry("vydra"); + const manifest = getOfficialExternalPluginCatalogManifest(vydra); + + expect(resolveOfficialExternalPluginId(vydra)).toBe("vydra"); + expect(resolveOfficialExternalPluginInstall(vydra)).toEqual({ + clawhubSpec: "clawhub:@openclaw/vydra-provider", + npmSpec: "@openclaw/vydra-provider", + defaultChoice: "npm", + minHostVersion: ">=2026.7.2", + }); + expect(manifest?.providers?.map((provider) => provider.id)).toEqual(["vydra"]); + expect(manifest?.contracts).toMatchObject({ + speechProviders: ["vydra"], + imageGenerationProviders: ["vydra"], + videoGenerationProviders: ["vydra"], + }); + }); + it.each([ ["teams-meetings", "@openclaw/teams-meetings", "teams_meetings", "teams"], ["zoom-meetings", "@openclaw/zoom-meetings", "zoom_meetings", "zoom"], diff --git a/test/scripts/bundled-plugin-build-entries.test.ts b/test/scripts/bundled-plugin-build-entries.test.ts index d8f337a6d754..4aed9b00f132 100644 --- a/test/scripts/bundled-plugin-build-entries.test.ts +++ b/test/scripts/bundled-plugin-build-entries.test.ts @@ -349,6 +349,14 @@ describe("bundled plugin build entries", () => { } }); + it("excludes the externalized Vydra provider from bundled artifacts", () => { + const artifacts = listBundledPluginPackArtifacts(); + + expect(artifacts).not.toContain("dist/extensions/vydra/index.js"); + expect(artifacts).not.toContain("dist/extensions/vydra/openclaw.plugin.json"); + expect(artifacts).not.toContain("dist/extensions/vydra/package.json"); + }); + it("excludes externalized meeting plugins from bundled artifacts", () => { const artifacts = listBundledPluginPackArtifacts();