diff --git a/.github/labeler.yml b/.github/labeler.yml index cb64e7ad0e54..5e507fdf807b 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -464,6 +464,11 @@ - any-glob-to-any-file: - "extensions/longcat/**" - "docs/providers/longcat.md" +"extensions: meta": + - changed-files: + - any-glob-to-any-file: + - "extensions/meta/**" + - "docs/providers/meta.md" "extensions: minimax": - changed-files: - any-glob-to-any-file: diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b089858029..67fbedb9e68a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai ### Changes +- **Meta provider:** add bundled `muse-spark-1.1` model support with Responses API streaming, tool calls, encrypted reasoning replay, onboarding, and standalone npm/ClawHub distribution. (#102873) Thanks @HamidShojanazeri. - **Android chat agent selector:** switch the active agent directly from the live chat screen while keeping chat, Talk mode, and home canvas on the same canonical session. (#80422) Thanks @bcperry. - **Gateway host status:** show the connected Gateway's host, network address, OS, runtime, uptime, CPU, memory, and disk details in Control UI Settings. (#100478) - **iOS offline chat:** pre-paint recent sessions and canonical transcripts from a protected, bounded per-gateway cache, keep sending disabled offline, and purge cached conversation text when pairing is reset. (#100194) diff --git a/docs/docs.json b/docs/docs.json index 8506ef46d224..788e06de959d 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1485,6 +1485,7 @@ "providers/litellm", "providers/lmstudio", "providers/longcat", + "providers/meta", "providers/minimax", "providers/mistral", "providers/moonshot", diff --git a/docs/docs_map.md b/docs/docs_map.md index dd5b72fe2c9b..23707fa153df 100644 --- a/docs/docs_map.md +++ b/docs/docs_map.md @@ -6379,6 +6379,15 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H2: Surface - H2: Related docs +## plugins/reference/meta.md + +- Route: /plugins/reference/meta +- Headings: + - H1: Meta plugin + - H2: Distribution + - H2: Surface + - H2: Related docs + ## plugins/reference/microsoft-foundry.md - Route: /plugins/reference/microsoft-foundry @@ -7689,9 +7698,9 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H2: Troubleshooting - H2: Related -## providers/meta-model-api.md +## providers/meta.md -- Route: /providers/meta-model-api +- Route: /providers/meta - Headings: - H2: Getting started - H2: Non-interactive setup diff --git a/docs/plugins/plugin-inventory.md b/docs/plugins/plugin-inventory.md index 5ce7fe5a45b9..282b21417304 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 -62 plugins +63 plugins - **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint. @@ -111,6 +111,8 @@ Each entry lists the package, distribution route, and description. - **[memory-wiki](/plugins/reference/memory-wiki)** (`@openclaw/memory-wiki`) - included in OpenClaw. Persistent wiki compiler and Obsidian-friendly knowledge vault for OpenClaw. +- **[meta](/plugins/reference/meta)** (`@openclaw/meta-provider`) - included in OpenClaw; npm; ClawHub: `clawhub:@openclaw/meta-provider`. Adds Meta model provider support to OpenClaw. + - **[microsoft](/plugins/reference/microsoft)** (`@openclaw/microsoft-speech`) - included in OpenClaw. Adds text-to-speech provider support. - **[microsoft-foundry](/plugins/reference/microsoft-foundry)** (`@openclaw/microsoft-foundry`) - included in OpenClaw. Adds Microsoft Foundry model provider support to OpenClaw. diff --git a/docs/plugins/reference.md b/docs/plugins/reference.md index e2c4191acac5..1f1fb404bd77 100644 --- a/docs/plugins/reference.md +++ b/docs/plugins/reference.md @@ -15,5 +15,5 @@ This page is generated from `extensions/*/package.json` and pnpm plugins:inventory:gen ``` -Use [Plugin inventory](/plugins/plugin-inventory) to browse all 134 +Use [Plugin inventory](/plugins/plugin-inventory) to browse all 135 generated plugin reference pages by distribution, package, and description. diff --git a/docs/plugins/reference/meta.md b/docs/plugins/reference/meta.md new file mode 100644 index 000000000000..6f25c2af491c --- /dev/null +++ b/docs/plugins/reference/meta.md @@ -0,0 +1,23 @@ +--- +summary: "Adds Meta model provider support to OpenClaw." +read_when: + - You are installing, configuring, or auditing the meta plugin +title: "Meta plugin" +--- + +# Meta plugin + +Adds Meta model provider support to OpenClaw. + +## Distribution + +- Package: `@openclaw/meta-provider` +- Install route: included in OpenClaw; npm; ClawHub: `clawhub:@openclaw/meta-provider` + +## Surface + +providers: meta + +## Related docs + +- [meta](/providers/meta) diff --git a/docs/providers/meta-model-api.md b/docs/providers/meta.md similarity index 57% rename from docs/providers/meta-model-api.md rename to docs/providers/meta.md index ea987aca4c00..492262b8f821 100644 --- a/docs/providers/meta-model-api.md +++ b/docs/providers/meta.md @@ -1,26 +1,26 @@ --- -summary: "Meta Model API setup (auth + muse-spark-1.1 model selection)" -title: "Meta Model API" +summary: "Meta setup (auth + muse-spark-1.1 model selection)" +title: "Meta" read_when: - - You want to use the Meta Model API with OpenClaw + - You want to use Meta with OpenClaw - You need the MODEL_API_KEY env var or CLI auth choice --- -The **Meta Model API** uses the OpenAI-compatible **Responses API** (`POST /v1/responses`) +The **Meta API** uses the OpenAI-compatible **Responses API** (`POST /v1/responses`) for the `muse-spark-1.1` reasoning model. The provider ships as a bundled OpenClaw plugin. -| Property | Value | -| ----------------- | -------------------------------------- | -| Provider id | `meta-model-api` | -| Plugin | bundled provider | -| Auth env var | `MODEL_API_KEY` | -| Onboarding flag | `--auth-choice meta-model-api-api-key` | -| Direct CLI flag | `--meta-model-api-key ` | -| API | Responses API (`openai-responses`) | -| Base URL | `https://api.ai.meta.com/v1` | -| Default model | `meta-model-api/muse-spark-1.1` | -| Default reasoning | `high` (`reasoning.effort`) | +| Property | Value | +| ----------------- | ---------------------------------- | +| Provider id | `meta` | +| Plugin | bundled provider | +| Auth env var | `MODEL_API_KEY` | +| Onboarding flag | `--auth-choice meta-api-key` | +| Direct CLI flag | `--meta-api-key ` | +| API | Responses API (`openai-responses`) | +| Base URL | `https://api.ai.meta.com/v1` | +| Default model | `meta/muse-spark-1.1` | +| Default reasoning | `high` (`reasoning.effort`) | ## Getting started @@ -29,13 +29,13 @@ plugin. ```bash Onboarding -openclaw onboard --auth-choice meta-model-api-api-key +openclaw onboard --auth-choice meta-api-key ``` ```bash Direct flag openclaw onboard --non-interactive --accept-risk \ - --auth-choice meta-model-api-api-key \ - --meta-model-api-key "$MODEL_API_KEY" + --auth-choice meta-api-key \ + --meta-api-key "$MODEL_API_KEY" ``` ```bash Env only @@ -47,7 +47,7 @@ export MODEL_API_KEY= ```bash - openclaw models list --provider meta-model-api + openclaw models list --provider meta ``` Lists the static `muse-spark-1.1` catalog entry. If `MODEL_API_KEY` is unresolved, @@ -62,15 +62,15 @@ export MODEL_API_KEY= ```bash openclaw onboard --non-interactive --accept-risk \ --mode local \ - --auth-choice meta-model-api-api-key \ - --meta-model-api-key "$MODEL_API_KEY" + --auth-choice meta-api-key \ + --meta-api-key "$MODEL_API_KEY" ``` ## Built-in catalog -| Model ref | Name | Reasoning | Context window | Max output | -| ------------------------------- | -------------- | --------- | -------------- | ---------- | -| `meta-model-api/muse-spark-1.1` | Muse Spark 1.1 | yes | 1,048,576 | 128,000 | +| Model ref | Name | Reasoning | Context window | Max output | +| --------------------- | -------------- | --------- | -------------- | ---------- | +| `meta/muse-spark-1.1` | Muse Spark 1.1 | yes | 1,048,576 | 128,000 | Capabilities: @@ -86,7 +86,7 @@ Capabilities: Until `muse-spark-1.1` is deployed, smoke tests and manual checks can use the -deployed `muse-spark` model id: `--model meta-model-api/muse-spark`. +deployed `muse-spark` model id: `--model meta/muse-spark`. ## Manual config @@ -96,9 +96,9 @@ deployed `muse-spark` model id: `--model meta-model-api/muse-spark`. env: { MODEL_API_KEY: "" }, agents: { defaults: { - model: { primary: "meta-model-api/muse-spark-1.1" }, + model: { primary: "meta/muse-spark-1.1" }, models: { - "meta-model-api/muse-spark-1.1": { alias: "Muse Spark 1.1" }, + "meta/muse-spark-1.1": { alias: "Muse Spark 1.1" }, }, }, }, @@ -118,8 +118,8 @@ separately. ```bash export MODEL_API_KEY= export OPENCLAW_LIVE_TEST=1 -export META_MODEL_API_LIVE_TEST=1 -pnpm test extensions/meta-model-api/meta-model-api.live.test.ts +export META_LIVE_TEST=1 +pnpm test extensions/meta/meta.live.test.ts ``` Live tests use deployed `muse-spark` against `POST /v1/responses`. diff --git a/extensions/meta-model-api/api.ts b/extensions/meta-model-api/api.ts deleted file mode 100644 index 3496cb2e3147..000000000000 --- a/extensions/meta-model-api/api.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Public Meta Model API provider plugin API exports. - */ -export { - buildMetaModelApiCatalogModels, - buildMetaModelApiModelDefinition, - META_MODEL_API_BASE_URL, - META_MODEL_API_MODEL_CATALOG, -} from "./models.js"; -export { buildMetaModelApiProvider } from "./provider-catalog.js"; -export { applyMetaModelApiConfig, META_MODEL_API_DEFAULT_MODEL_REF } from "./onboard.js"; diff --git a/extensions/meta-model-api/index.ts b/extensions/meta-model-api/index.ts deleted file mode 100644 index 16e71a2017ac..000000000000 --- a/extensions/meta-model-api/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Meta Model API provider plugin entrypoint. - */ -import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry"; -import { OPENAI_COMPATIBLE_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared"; -import { applyMetaModelApiConfig, META_MODEL_API_DEFAULT_MODEL_REF } from "./onboard.js"; -import { buildMetaModelApiProvider } from "./provider-catalog.js"; -import { wrapMetaModelApiProviderStream } from "./stream.js"; -import { resolveMetaModelApiThinkingProfile } from "./thinking.js"; - -const PROVIDER_ID = "meta-model-api"; - -export default defineSingleProviderPluginEntry({ - id: PROVIDER_ID, - name: "Meta Model API Provider", - description: "Bundled Meta Model API provider plugin", - provider: { - label: "Meta Model API", - docsPath: "/providers/meta-model-api", - auth: [ - { - methodId: "api-key", - label: "Meta Model API key", - hint: "Meta Model API (Responses API)", - optionKey: "metaModelApiKey", - flagName: "--meta-model-api-key", - envVar: "MODEL_API_KEY", - promptMessage: "Enter Meta Model API key", - defaultModel: META_MODEL_API_DEFAULT_MODEL_REF, - applyConfig: (cfg) => applyMetaModelApiConfig(cfg), - noteMessage: ["Meta Model API provides Responses API inference."].join("\n"), - noteTitle: "Meta Model API", - wizard: { - groupLabel: "Meta Model API", - groupHint: "Meta Model API (Responses API)", - }, - }, - ], - catalog: { - buildProvider: buildMetaModelApiProvider, - buildStaticProvider: buildMetaModelApiProvider, - }, - ...OPENAI_COMPATIBLE_REPLAY_HOOKS, - wrapStreamFn: wrapMetaModelApiProviderStream, - resolveThinkingProfile: ({ modelId }) => resolveMetaModelApiThinkingProfile(modelId), - }, -}); diff --git a/extensions/meta-model-api/models.ts b/extensions/meta-model-api/models.ts deleted file mode 100644 index 868464073af2..000000000000 --- a/extensions/meta-model-api/models.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Meta Model API model catalog helpers derived from the plugin manifest. - */ -import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared"; -import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared"; -import manifest from "./openclaw.plugin.json" with { type: "json" }; - -const META_MODEL_API_MANIFEST_CATALOG = manifest.modelCatalog.providers["meta-model-api"]; - -/** Base URL for Meta Model API OpenAI-compatible inference. */ -export const META_MODEL_API_BASE_URL = META_MODEL_API_MANIFEST_CATALOG.baseUrl; -/** Meta Model API model catalog entries from the plugin manifest. */ -export const META_MODEL_API_MODEL_CATALOG = META_MODEL_API_MANIFEST_CATALOG.models; - -/** Builds normalized Meta Model API catalog model definitions. */ -export function buildMetaModelApiCatalogModels(): ModelDefinitionConfig[] { - return buildManifestModelProviderConfig({ - providerId: "meta-model-api", - catalog: META_MODEL_API_MANIFEST_CATALOG, - }).models; -} - -/** Builds one normalized Meta Model API model definition from a manifest entry. */ -export function buildMetaModelApiModelDefinition( - model: (typeof META_MODEL_API_MODEL_CATALOG)[number], -): ModelDefinitionConfig { - const providerConfig = buildManifestModelProviderConfig({ - providerId: "meta-model-api", - catalog: { ...META_MODEL_API_MANIFEST_CATALOG, models: [model] }, - }); - return providerConfig.models[0]; -} diff --git a/extensions/meta-model-api/onboard.ts b/extensions/meta-model-api/onboard.ts deleted file mode 100644 index 22d62fdd7670..000000000000 --- a/extensions/meta-model-api/onboard.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Meta Model API onboarding config helpers. - */ -import { - createModelCatalogPresetAppliers, - type OpenClawConfig, -} from "openclaw/plugin-sdk/provider-onboard"; -import { - buildMetaModelApiModelDefinition, - META_MODEL_API_BASE_URL, - META_MODEL_API_MODEL_CATALOG, -} from "./models.js"; - -/** Default Meta Model API model reference used after onboarding. */ -export const META_MODEL_API_DEFAULT_MODEL_REF = "meta-model-api/muse-spark-1.1"; - -const metaModelApiPresetAppliers = createModelCatalogPresetAppliers({ - primaryModelRef: META_MODEL_API_DEFAULT_MODEL_REF, - resolveParams: (_cfg: OpenClawConfig) => ({ - providerId: "meta-model-api", - api: "openai-responses", - baseUrl: META_MODEL_API_BASE_URL, - catalogModels: META_MODEL_API_MODEL_CATALOG.map(buildMetaModelApiModelDefinition), - aliases: [{ modelRef: META_MODEL_API_DEFAULT_MODEL_REF, alias: "Muse Spark 1.1" }], - }), -}); - -/** Applies Meta Model API provider/catalog config and default model aliases. */ -export function applyMetaModelApiConfig(cfg: OpenClawConfig): OpenClawConfig { - return metaModelApiPresetAppliers.applyConfig(cfg); -} diff --git a/extensions/meta-model-api/package.json b/extensions/meta-model-api/package.json deleted file mode 100644 index f04cbe2ee6d1..000000000000 --- a/extensions/meta-model-api/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@openclaw/meta-model-api-provider", - "version": "2026.6.11", - "private": true, - "description": "OpenClaw Meta Model API provider plugin.", - "type": "module", - "devDependencies": { - "@openclaw/plugin-sdk": "workspace:*" - }, - "openclaw": { - "extensions": [ - "./index.ts" - ] - } -} diff --git a/extensions/meta-model-api/provider-catalog.ts b/extensions/meta-model-api/provider-catalog.ts deleted file mode 100644 index 5007b289e465..000000000000 --- a/extensions/meta-model-api/provider-catalog.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Meta Model API model provider builder. - */ -import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared"; -import { buildMetaModelApiCatalogModels, META_MODEL_API_BASE_URL } from "./models.js"; - -/** Builds the Meta Model API OpenAI-compatible model provider config. */ -export function buildMetaModelApiProvider(): ModelProviderConfig { - return { - baseUrl: META_MODEL_API_BASE_URL, - api: "openai-responses", - models: buildMetaModelApiCatalogModels(), - }; -} diff --git a/extensions/meta-model-api/thinking.ts b/extensions/meta-model-api/thinking.ts deleted file mode 100644 index 4d857f5f126a..000000000000 --- a/extensions/meta-model-api/thinking.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Meta Model API plugin module implements thinking behavior. -import type { ProviderThinkingProfile } from "openclaw/plugin-sdk/plugin-entry"; - -const META_MODEL_API_REASONING_MODEL_IDS = new Set(["muse-spark", "muse-spark-1.1"]); - -function isMetaModelApiReasoningModelId(modelId: string): boolean { - return META_MODEL_API_REASONING_MODEL_IDS.has(modelId.toLowerCase()); -} - -const META_THINKING_LEVEL_IDS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const; - -const META_THINKING_PROFILE = { - levels: META_THINKING_LEVEL_IDS.map((id) => ({ id })), - defaultLevel: "high", -} satisfies ProviderThinkingProfile; - -export function resolveMetaModelApiThinkingProfile( - modelId: string, -): ProviderThinkingProfile | undefined { - return isMetaModelApiReasoningModelId(modelId) ? META_THINKING_PROFILE : undefined; -} diff --git a/extensions/meta-model-api/README.md b/extensions/meta/README.md similarity index 72% rename from extensions/meta-model-api/README.md rename to extensions/meta/README.md index 758841a7d0b8..1433bfcb0b2d 100644 --- a/extensions/meta-model-api/README.md +++ b/extensions/meta/README.md @@ -1,6 +1,6 @@ -# Meta Model API provider +# Meta provider -Bundled OpenClaw provider plugin for the **Meta Model API** — an OpenAI-compatible +Bundled OpenClaw provider plugin for the **Meta API** — an OpenAI-compatible **Responses API** endpoint (`POST /v1/responses`). - **Base URL:** `https://api.ai.meta.com/v1` @@ -25,13 +25,13 @@ export MODEL_API_KEY= { agents: { defaults: { - model: { primary: "meta-model-api/muse-spark-1.1" }, + model: { primary: "meta/muse-spark-1.1" }, }, }, } ``` -Or run onboarding and choose **Meta Model API**. +Or run onboarding and choose **Meta**. ## Thinking / reasoning @@ -41,15 +41,15 @@ not accept `none`. ## Docs -See `docs/providers/meta-model-api.md` for setup, onboarding, and smoke tests. +See `docs/providers/meta.md` for setup, onboarding, and smoke tests. ## Live test ```bash export MODEL_API_KEY= export OPENCLAW_LIVE_TEST=1 -export META_MODEL_API_LIVE_TEST=1 -pnpm test extensions/meta-model-api/meta-model-api.live.test.ts +export META_LIVE_TEST=1 +pnpm test extensions/meta/meta.live.test.ts ``` Live tests call `muse-spark` on `/v1/responses`. diff --git a/extensions/meta/api.ts b/extensions/meta/api.ts new file mode 100644 index 000000000000..99a639a53b9f --- /dev/null +++ b/extensions/meta/api.ts @@ -0,0 +1,11 @@ +/** + * Public Meta provider plugin API exports. + */ +export { + buildMetaCatalogModels, + buildMetaModelDefinition, + META_BASE_URL, + META_MODEL_CATALOG, +} from "./models.js"; +export { buildMetaProvider } from "./provider-catalog.js"; +export { applyMetaConfig, META_DEFAULT_MODEL_REF } from "./onboard.js"; diff --git a/extensions/meta-model-api/index.test.ts b/extensions/meta/index.test.ts similarity index 72% rename from extensions/meta-model-api/index.test.ts rename to extensions/meta/index.test.ts index 399c6f789cab..24f8d4a1ec0d 100644 --- a/extensions/meta-model-api/index.test.ts +++ b/extensions/meta/index.test.ts @@ -1,40 +1,40 @@ -// Meta Model API tests cover plugin registration and catalog shape. +// Meta tests cover plugin registration and catalog shape. import { capturePluginRegistration } from "openclaw/plugin-sdk/plugin-test-runtime"; import { describe, expect, it } from "vitest"; -import { buildMetaModelApiProvider } from "./api.js"; +import { buildMetaProvider } from "./api.js"; import plugin from "./index.js"; function requireThinkingProfileResolver( provider: ReturnType["providers"][number], ) { if (!provider.resolveThinkingProfile) { - throw new Error("Expected resolveThinkingProfile on Meta Model API provider"); + throw new Error("Expected resolveThinkingProfile on Meta provider"); } return provider.resolveThinkingProfile; } -describe("meta-model-api provider", () => { - it("registers the Meta Model API provider with api-key auth", () => { +describe("meta provider", () => { + it("registers the Meta provider with api-key auth", () => { const captured = capturePluginRegistration(plugin); const [provider] = captured.providers; if (!provider) { - throw new Error("Expected Meta Model API provider"); + throw new Error("Expected Meta provider"); } expect(provider).toMatchObject({ - id: "meta-model-api", - label: "Meta Model API", - docsPath: "/providers/meta-model-api", + id: "meta", + label: "Meta", + docsPath: "/providers/meta", }); expect(provider.auth).toHaveLength(1); expect(provider.auth[0]).toMatchObject({ id: "api-key", kind: "api_key", - label: "Meta Model API key", + label: "Meta API key", }); }); it("builds the muse-spark-1.1 catalog entry over openai-responses", () => { - const providerConfig = buildMetaModelApiProvider(); + const providerConfig = buildMetaProvider(); expect(providerConfig.baseUrl).toBe("https://api.ai.meta.com/v1"); expect(providerConfig.api).toBe("openai-responses"); const model = providerConfig.models.find((m) => m.id === "muse-spark-1.1"); @@ -50,11 +50,11 @@ describe("meta-model-api provider", () => { const captured = capturePluginRegistration(plugin); const [provider] = captured.providers; if (!provider) { - throw new Error("Expected Meta Model API provider"); + throw new Error("Expected Meta provider"); } const resolveThinkingProfile = requireThinkingProfileResolver(provider); const profile = resolveThinkingProfile({ - provider: "meta-model-api", + provider: "meta", modelId: "muse-spark-1.1", } as never); expect(profile?.defaultLevel).toBe("high"); diff --git a/extensions/meta/index.ts b/extensions/meta/index.ts new file mode 100644 index 000000000000..97b723ca3ba7 --- /dev/null +++ b/extensions/meta/index.ts @@ -0,0 +1,47 @@ +/** + * Meta provider plugin entrypoint. + */ +import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry"; +import { OPENAI_COMPATIBLE_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared"; +import { applyMetaConfig, META_DEFAULT_MODEL_REF } from "./onboard.js"; +import { buildMetaProvider } from "./provider-catalog.js"; +import { wrapMetaProviderStream } from "./stream.js"; +import { resolveMetaThinkingProfile } from "./thinking.js"; + +const PROVIDER_ID = "meta"; + +export default defineSingleProviderPluginEntry({ + id: PROVIDER_ID, + name: "Meta Provider", + description: "Bundled Meta provider plugin", + provider: { + label: "Meta", + docsPath: "/providers/meta", + auth: [ + { + methodId: "api-key", + label: "Meta API key", + hint: "Meta (Responses API)", + optionKey: "metaApiKey", + flagName: "--meta-api-key", + envVar: "MODEL_API_KEY", + promptMessage: "Enter Meta API key", + defaultModel: META_DEFAULT_MODEL_REF, + applyConfig: (cfg) => applyMetaConfig(cfg), + noteMessage: ["Meta provides Responses API inference."].join("\n"), + noteTitle: "Meta", + wizard: { + groupLabel: "Meta", + groupHint: "Meta (Responses API)", + }, + }, + ], + catalog: { + buildProvider: buildMetaProvider, + buildStaticProvider: buildMetaProvider, + }, + ...OPENAI_COMPATIBLE_REPLAY_HOOKS, + wrapStreamFn: wrapMetaProviderStream, + resolveThinkingProfile: ({ modelId }) => resolveMetaThinkingProfile(modelId), + }, +}); diff --git a/extensions/meta-model-api/meta-model-api.live.test.ts b/extensions/meta/meta.live.test.ts similarity index 79% rename from extensions/meta-model-api/meta-model-api.live.test.ts rename to extensions/meta/meta.live.test.ts index 732707f61132..4ea6f7b49617 100644 --- a/extensions/meta-model-api/meta-model-api.live.test.ts +++ b/extensions/meta/meta.live.test.ts @@ -1,25 +1,25 @@ -// Meta Model API live tests prove muse-spark auth and Responses API completion. +// Meta live tests prove muse-spark auth and Responses API completion. import { streamSimple, type Model } from "openclaw/plugin-sdk/llm"; import { extractNonEmptyAssistantText, isLiveTestEnabled } from "openclaw/plugin-sdk/test-env"; import { describe, expect, it } from "vitest"; -import { buildMetaModelApiProvider } from "./provider-catalog.js"; -import { wrapMetaModelApiProviderStream } from "./stream.js"; +import { buildMetaProvider } from "./provider-catalog.js"; +import { wrapMetaProviderStream } from "./stream.js"; const MODEL_API_KEY = process.env.MODEL_API_KEY?.trim() ?? ""; const LIVE_MODEL_ID = "muse-spark"; const LIVE = - isLiveTestEnabled(["META_MODEL_API_LIVE_TEST", "MODEL_API_LIVE_TEST"]) && + isLiveTestEnabled(["META_LIVE_TEST", "MODEL_API_LIVE_TEST"]) && MODEL_API_KEY.length > 0; const describeLive = LIVE ? describe : describe.skip; function resolveLiveModel(): Model<"openai-responses"> { - const provider = buildMetaModelApiProvider(); + const provider = buildMetaProvider(); const catalogModel = provider.models?.find((entry) => entry.id === "muse-spark-1.1"); if (!catalogModel) { - throw new Error("Meta Model API catalog does not include muse-spark-1.1"); + throw new Error("Meta catalog does not include muse-spark-1.1"); } return { - provider: "meta-model-api", + provider: "meta", baseUrl: provider.baseUrl, ...catalogModel, id: LIVE_MODEL_ID, @@ -30,8 +30,8 @@ function resolveLiveModel(): Model<"openai-responses"> { function resolveLiveStreamFn() { const model = resolveLiveModel(); return ( - wrapMetaModelApiProviderStream({ - provider: "meta-model-api", + wrapMetaProviderStream({ + provider: "meta", modelId: model.id, model, streamFn: streamSimple, @@ -39,7 +39,7 @@ function resolveLiveStreamFn() { ); } -describeLive("meta-model-api plugin live", () => { +describeLive("meta plugin live", () => { it("lists muse-spark via the /models endpoint", async () => { const response = await fetch("https://api.ai.meta.com/v1/models", { headers: { Authorization: `Bearer ${MODEL_API_KEY}` }, @@ -76,7 +76,7 @@ describeLive("meta-model-api plugin live", () => { const result = await stream.result(); if (result.stopReason === "error") { - throw new Error(result.errorMessage || "Meta Model API returned an error"); + throw new Error(result.errorMessage || "Meta returned an error"); } expect(capturedPayload?.store).toBe(false); diff --git a/extensions/meta/models.ts b/extensions/meta/models.ts new file mode 100644 index 000000000000..ad373b2c6d1c --- /dev/null +++ b/extensions/meta/models.ts @@ -0,0 +1,32 @@ +/** + * Meta model catalog helpers derived from the plugin manifest. + */ +import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared"; +import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared"; +import manifest from "./openclaw.plugin.json" with { type: "json" }; + +const META_MANIFEST_CATALOG = manifest.modelCatalog.providers["meta"]; + +/** Base URL for Meta OpenAI-compatible inference. */ +export const META_BASE_URL = META_MANIFEST_CATALOG.baseUrl; +/** Meta model catalog entries from the plugin manifest. */ +export const META_MODEL_CATALOG = META_MANIFEST_CATALOG.models; + +/** Builds normalized Meta catalog model definitions. */ +export function buildMetaCatalogModels(): ModelDefinitionConfig[] { + return buildManifestModelProviderConfig({ + providerId: "meta", + catalog: META_MANIFEST_CATALOG, + }).models; +} + +/** Builds one normalized Meta model definition from a manifest entry. */ +export function buildMetaModelDefinition( + model: (typeof META_MODEL_CATALOG)[number], +): ModelDefinitionConfig { + const providerConfig = buildManifestModelProviderConfig({ + providerId: "meta", + catalog: { ...META_MANIFEST_CATALOG, models: [model] }, + }); + return providerConfig.models[0]; +} diff --git a/extensions/meta/npm-shrinkwrap.json b/extensions/meta/npm-shrinkwrap.json new file mode 100644 index 000000000000..06aa3b0483a5 --- /dev/null +++ b/extensions/meta/npm-shrinkwrap.json @@ -0,0 +1,12 @@ +{ + "name": "@openclaw/meta-provider", + "version": "2026.6.11", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@openclaw/meta-provider", + "version": "2026.6.11" + } + } +} diff --git a/extensions/meta/onboard.ts b/extensions/meta/onboard.ts new file mode 100644 index 000000000000..eb83f116eb5b --- /dev/null +++ b/extensions/meta/onboard.ts @@ -0,0 +1,31 @@ +/** + * Meta onboarding config helpers. + */ +import { + createModelCatalogPresetAppliers, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; +import { + buildMetaModelDefinition, + META_BASE_URL, + META_MODEL_CATALOG, +} from "./models.js"; + +/** Default Meta model reference used after onboarding. */ +export const META_DEFAULT_MODEL_REF = "meta/muse-spark-1.1"; + +const metaPresetAppliers = createModelCatalogPresetAppliers({ + primaryModelRef: META_DEFAULT_MODEL_REF, + resolveParams: (_cfg: OpenClawConfig) => ({ + providerId: "meta", + api: "openai-responses", + baseUrl: META_BASE_URL, + catalogModels: META_MODEL_CATALOG.map(buildMetaModelDefinition), + aliases: [{ modelRef: META_DEFAULT_MODEL_REF, alias: "Muse Spark 1.1" }], + }), +}); + +/** Applies Meta provider/catalog config and default model aliases. */ +export function applyMetaConfig(cfg: OpenClawConfig): OpenClawConfig { + return metaPresetAppliers.applyConfig(cfg); +} diff --git a/extensions/meta-model-api/openclaw.plugin.json b/extensions/meta/openclaw.plugin.json similarity index 70% rename from extensions/meta-model-api/openclaw.plugin.json rename to extensions/meta/openclaw.plugin.json index af7318f4edfd..d2a6eb29733d 100644 --- a/extensions/meta-model-api/openclaw.plugin.json +++ b/extensions/meta/openclaw.plugin.json @@ -1,26 +1,26 @@ { - "id": "meta-model-api", + "id": "meta", "activation": { "onStartup": false }, "enabledByDefault": true, - "providers": ["meta-model-api"], + "providers": ["meta"], "providerEndpoints": [ { - "endpointClass": "meta-model-api-native", + "endpointClass": "meta-native", "hosts": ["api.ai.meta.com"] } ], "providerRequest": { "providers": { - "meta-model-api": { - "family": "meta-model-api" + "meta": { + "family": "meta" } } }, "modelCatalog": { "providers": { - "meta-model-api": { + "meta": { "baseUrl": "https://api.ai.meta.com/v1", "api": "openai-responses", "models": [ @@ -61,13 +61,13 @@ } }, "discovery": { - "meta-model-api": "static" + "meta": "static" } }, "setup": { "providers": [ { - "id": "meta-model-api", + "id": "meta", "authMethods": ["api-key"], "envVars": ["MODEL_API_KEY"] } @@ -75,20 +75,20 @@ }, "providerAuthChoices": [ { - "provider": "meta-model-api", + "provider": "meta", "method": "api-key", - "choiceId": "meta-model-api-api-key", + "choiceId": "meta-api-key", "appGuidedSecret": true, - "choiceLabel": "Meta Model API key", - "choiceHint": "Meta Model API (Responses API)", - "groupId": "meta-model-api", - "groupLabel": "Meta Model API", - "groupHint": "Meta Model API (Responses API)", + "choiceLabel": "Meta API key", + "choiceHint": "Meta (Responses API)", + "groupId": "meta", + "groupLabel": "Meta", + "groupHint": "Meta (Responses API)", "onboardingFeatured": true, - "optionKey": "metaModelApiKey", - "cliFlag": "--meta-model-api-key", - "cliOption": "--meta-model-api-key ", - "cliDescription": "Meta Model API key" + "optionKey": "metaApiKey", + "cliFlag": "--meta-api-key", + "cliOption": "--meta-api-key ", + "cliDescription": "Meta API key" } ], "configSchema": { diff --git a/extensions/meta/package.json b/extensions/meta/package.json new file mode 100644 index 000000000000..c999e95860e0 --- /dev/null +++ b/extensions/meta/package.json @@ -0,0 +1,35 @@ +{ + "name": "@openclaw/meta-provider", + "version": "2026.6.11", + "description": "OpenClaw Meta provider plugin.", + "repository": { + "type": "git", + "url": "https://github.com/openclaw/openclaw" + }, + "type": "module", + "devDependencies": { + "@openclaw/plugin-sdk": "workspace:*" + }, + "openclaw": { + "extensions": [ + "./index.ts" + ], + "install": { + "clawhubSpec": "clawhub:@openclaw/meta-provider", + "npmSpec": "@openclaw/meta-provider", + "defaultChoice": "npm", + "minHostVersion": ">=2026.6.11" + }, + "compat": { + "pluginApi": ">=2026.6.11" + }, + "build": { + "openclawVersion": "2026.6.11", + "bundledDist": true + }, + "release": { + "publishToClawHub": true, + "publishToNpm": true + } + } +} diff --git a/extensions/meta/provider-catalog.ts b/extensions/meta/provider-catalog.ts new file mode 100644 index 000000000000..cdf644b094a3 --- /dev/null +++ b/extensions/meta/provider-catalog.ts @@ -0,0 +1,14 @@ +/** + * Meta model provider builder. + */ +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared"; +import { buildMetaCatalogModels, META_BASE_URL } from "./models.js"; + +/** Builds the Meta OpenAI-compatible model provider config. */ +export function buildMetaProvider(): ModelProviderConfig { + return { + baseUrl: META_BASE_URL, + api: "openai-responses", + models: buildMetaCatalogModels(), + }; +} diff --git a/extensions/meta-model-api/stream.ts b/extensions/meta/stream.ts similarity index 73% rename from extensions/meta-model-api/stream.ts rename to extensions/meta/stream.ts index 11ac05884d72..98e787d4a5ef 100644 --- a/extensions/meta-model-api/stream.ts +++ b/extensions/meta/stream.ts @@ -1,4 +1,4 @@ -// Meta Model API plugin module implements stream behavior. +// Meta plugin module implements stream behavior. import type { StreamFn } from "openclaw/plugin-sdk/agent-core"; import { streamSimple } from "openclaw/plugin-sdk/llm"; import type { ProviderWrapStreamFnContext } from "openclaw/plugin-sdk/plugin-entry"; @@ -18,11 +18,11 @@ function ensureMetaResponsesReplayFields(payloadObj: Record): v payloadObj.store = false; } -export function createMetaModelApiResponsesWrapper(baseStreamFn: StreamFn | undefined): StreamFn { +export function createMetaResponsesWrapper(baseStreamFn: StreamFn | undefined): StreamFn { const underlying = baseStreamFn ?? streamSimple; return (model, context, options) => streamWithPayloadPatch(underlying, model, context, options, (payloadObj) => { - if (model.provider !== "meta-model-api" || model.api !== "openai-responses") { + if (model.provider !== "meta" || model.api !== "openai-responses") { return; } if (!model.reasoning) { @@ -32,11 +32,11 @@ export function createMetaModelApiResponsesWrapper(baseStreamFn: StreamFn | unde }); } -export function wrapMetaModelApiProviderStream( +export function wrapMetaProviderStream( ctx: ProviderWrapStreamFnContext, ): StreamFn | undefined { - if (ctx.provider !== "meta-model-api" || ctx.model?.api !== "openai-responses") { + if (ctx.provider !== "meta" || ctx.model?.api !== "openai-responses") { return undefined; } - return createMetaModelApiResponsesWrapper(ctx.streamFn); + return createMetaResponsesWrapper(ctx.streamFn); } diff --git a/extensions/meta/thinking.ts b/extensions/meta/thinking.ts new file mode 100644 index 000000000000..00ec067ce30b --- /dev/null +++ b/extensions/meta/thinking.ts @@ -0,0 +1,21 @@ +// Meta plugin module implements thinking behavior. +import type { ProviderThinkingProfile } from "openclaw/plugin-sdk/plugin-entry"; + +const META_REASONING_MODEL_IDS = new Set(["muse-spark", "muse-spark-1.1"]); + +function isMetaReasoningModelId(modelId: string): boolean { + return META_REASONING_MODEL_IDS.has(modelId.toLowerCase()); +} + +const META_THINKING_LEVEL_IDS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const; + +const META_THINKING_PROFILE = { + levels: META_THINKING_LEVEL_IDS.map((id) => ({ id })), + defaultLevel: "high", +} satisfies ProviderThinkingProfile; + +export function resolveMetaThinkingProfile( + modelId: string, +): ProviderThinkingProfile | undefined { + return isMetaReasoningModelId(modelId) ? META_THINKING_PROFILE : undefined; +} diff --git a/extensions/meta-model-api/tsconfig.json b/extensions/meta/tsconfig.json similarity index 100% rename from extensions/meta-model-api/tsconfig.json rename to extensions/meta/tsconfig.json diff --git a/packages/ai/src/env-api-keys.ts b/packages/ai/src/env-api-keys.ts index c5af6d0fef73..8f1a5f677cf8 100644 --- a/packages/ai/src/env-api-keys.ts +++ b/packages/ai/src/env-api-keys.ts @@ -163,7 +163,7 @@ function getApiKeyEnvVars(provider: string): readonly string[] | undefined { const envMap: Record = { openai: "OPENAI_API_KEY", - "meta-model-api": "MODEL_API_KEY", + "meta": "MODEL_API_KEY", "azure-openai-responses": "AZURE_OPENAI_API_KEY", deepseek: "DEEPSEEK_API_KEY", google: "GEMINI_API_KEY", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c7aa9802f07..74f343255054 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1119,7 +1119,7 @@ importers: specifier: workspace:* version: link:../.. - extensions/meta-model-api: + extensions/meta: devDependencies: '@openclaw/plugin-sdk': specifier: workspace:* diff --git a/scripts/lib/official-external-provider-catalog.json b/scripts/lib/official-external-provider-catalog.json index a684997fa6c3..8a114efaa620 100644 --- a/scripts/lib/official-external-provider-catalog.json +++ b/scripts/lib/official-external-provider-catalog.json @@ -682,6 +682,55 @@ } } }, + { + "name": "@openclaw/meta-provider", + "description": "OpenClaw Meta provider plugin.", + "source": "official", + "kind": "provider", + "openclaw": { + "plugin": { + "id": "meta", + "label": "Meta" + }, + "providerEndpoints": [ + { + "endpointClass": "meta-native", + "hosts": ["api.ai.meta.com"] + } + ], + "providers": [ + { + "id": "meta", + "name": "Meta", + "docs": "/providers/meta", + "categories": ["cloud", "llm"], + "envVars": ["MODEL_API_KEY"], + "authChoices": [ + { + "method": "api-key", + "choiceId": "meta-api-key", + "choiceLabel": "Meta API key", + "choiceHint": "Meta (Responses API)", + "groupId": "meta", + "groupLabel": "Meta", + "groupHint": "Meta (Responses API)", + "optionKey": "metaApiKey", + "cliFlag": "--meta-api-key", + "cliOption": "--meta-api-key ", + "cliDescription": "Meta API key", + "onboardingScopes": ["text-inference"] + } + ] + } + ], + "install": { + "clawhubSpec": "clawhub:@openclaw/meta-provider", + "npmSpec": "@openclaw/meta-provider", + "defaultChoice": "npm", + "minHostVersion": ">=2026.6.11" + } + } + }, { "name": "@openclaw/groq-provider", "description": "OpenClaw Groq media-understanding provider.", diff --git a/src/agents/sessions/provider-display-names.ts b/src/agents/sessions/provider-display-names.ts index aef253fedca9..b4878750866b 100644 --- a/src/agents/sessions/provider-display-names.ts +++ b/src/agents/sessions/provider-display-names.ts @@ -16,7 +16,7 @@ export const BUILT_IN_PROVIDER_DISPLAY_NAMES: Record = { groq: "Groq", huggingface: "Hugging Face", "kimi-coding": "Kimi For Coding", - "meta-model-api": "Meta Model API", + "meta": "Meta", mistral: "Mistral", minimax: "MiniMax", "minimax-cn": "MiniMax (China)", diff --git a/src/config/zod-schema.core.ts b/src/config/zod-schema.core.ts index 5574c5739b05..e1f53feadfbc 100644 --- a/src/config/zod-schema.core.ts +++ b/src/config/zod-schema.core.ts @@ -468,7 +468,7 @@ const BUILT_IN_MODEL_PROVIDER_OVERLAY_IDS = new Set([ "kimi-coding", "litellm", "lmstudio", - "meta-model-api", + "meta", "microsoft-foundry", "minimax", "minimax-portal", diff --git a/src/secrets/provider-env-vars.ts b/src/secrets/provider-env-vars.ts index 7428f48a3350..44492e94f7ed 100644 --- a/src/secrets/provider-env-vars.ts +++ b/src/secrets/provider-env-vars.ts @@ -24,7 +24,6 @@ const CORE_PROVIDER_AUTH_ENV_VAR_CANDIDATES = { openai: ["CODEX_API_KEY", "OPENAI_API_KEY"], voyage: ["VOYAGE_API_KEY"], cerebras: ["CEREBRAS_API_KEY"], - "meta-model-api": ["MODEL_API_KEY"], "anthropic-openai": ["ANTHROPIC_API_KEY"], "qwen-dashscope": ["DASHSCOPE_API_KEY"], } as const; diff --git a/test/scripts/test-live-shard.test.ts b/test/scripts/test-live-shard.test.ts index 4d8cb9edae1a..d0510e1e93b7 100644 --- a/test/scripts/test-live-shard.test.ts +++ b/test/scripts/test-live-shard.test.ts @@ -123,7 +123,7 @@ describe("scripts/test-live-shard", () => { ]); expect(selectLiveShardFiles("native-live-extensions-l-n", allFiles)).toEqual([ "extensions/memory-lancedb/memory-lancedb.live.test.ts", - "extensions/meta-model-api/meta-model-api.live.test.ts", + "extensions/meta/meta.live.test.ts", "extensions/microsoft/microsoft.live.test.ts", "extensions/mistral/mistral.live.test.ts", ]);