feat: externalize GMI provider plugin (#94350)

* feat: externalize gmi provider plugin

* fix(plugins): repair gmi alias installs

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
Patrick Erichsen
2026-06-18 01:47:38 -07:00
committed by GitHub
parent 1e02cc9473
commit 1b19c790bf
18 changed files with 244 additions and 24 deletions
-1
View File
@@ -301,7 +301,6 @@ See [/providers/kilocode](/providers/kilocode) for setup details.
| DeepInfra | `deepinfra` | `DEEPINFRA_API_KEY` | `deepinfra/deepseek-ai/DeepSeek-V4-Flash` |
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek/deepseek-v4-flash` |
| GitHub Copilot | `github-copilot` | `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` / `GITHUB_TOKEN` | - |
| GMI Cloud | `gmi` | `GMI_API_KEY` | `gmi/google/gemini-3.1-flash-lite` |
| Groq | `groq` | `GROQ_API_KEY` | - |
| Hugging Face Inference | `huggingface` | `HUGGINGFACE_HUB_TOKEN` or `HF_TOKEN` | `huggingface/deepseek-ai/DeepSeek-R1` |
| Kilo Gateway | `kilocode` | `KILOCODE_API_KEY` | `kilocode/kilo/auto` |
+4 -4
View File
@@ -51,7 +51,7 @@ Each entry lists the package, distribution route, and description.
## Core npm package
91 plugins
90 plugins
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
@@ -111,8 +111,6 @@ Each entry lists the package, distribution route, and description.
- **[github-copilot](/plugins/reference/github-copilot)** (`@openclaw/github-copilot-provider`) - included in OpenClaw. Adds GitHub Copilot model provider support to OpenClaw.
- **[gmi](/plugins/reference/gmi)** (`@openclaw/gmi-provider`) - included in OpenClaw. Adds Gmi, Gmi Cloud, Gmicloud model provider support to OpenClaw.
- **[google](/plugins/reference/google)** (`@openclaw/google-plugin`) - included in OpenClaw. Adds Google, Google Gemini CLI, Google Vertex model provider support to OpenClaw.
- **[gradium](/plugins/reference/gradium)** (`@openclaw/gradium-speech`) - included in OpenClaw. Adds text-to-speech provider support.
@@ -237,7 +235,7 @@ Each entry lists the package, distribution route, and description.
## Official external packages
35 plugins
36 plugins
- **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management.
@@ -265,6 +263,8 @@ Each entry lists the package, distribution route, and description.
- **[feishu](/plugins/reference/feishu)** (`@openclaw/feishu`) - npm; ClawHub. OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).
- **[gmi](/plugins/reference/gmi)** (`@openclaw/gmi-provider`) - npm; ClawHub: `clawhub:@openclaw/gmi-provider`. OpenClaw GMI Cloud provider plugin.
- **[google-meet](/plugins/reference/google-meet)** (`@openclaw/google-meet`) - npm; ClawHub. OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports.
- **[googlechat](/plugins/reference/googlechat)** (`@openclaw/googlechat`) - npm; ClawHub. OpenClaw Google Chat channel plugin for spaces and direct messages.
+3 -3
View File
@@ -1,5 +1,5 @@
---
summary: "Adds Gmi, Gmi Cloud, Gmicloud model provider support to OpenClaw."
summary: "OpenClaw GMI Cloud provider plugin."
read_when:
- You are installing, configuring, or auditing the gmi plugin
title: "Gmi plugin"
@@ -7,12 +7,12 @@ title: "Gmi plugin"
# Gmi plugin
Adds Gmi, Gmi Cloud, Gmicloud model provider support to OpenClaw.
OpenClaw GMI Cloud provider plugin.
## Distribution
- Package: `@openclaw/gmi-provider`
- Install route: included in OpenClaw
- Install route: npm; ClawHub: `clawhub:@openclaw/gmi-provider`
## Surface
+12 -5
View File
@@ -7,9 +7,9 @@ title: "GMI Cloud"
---
GMI Cloud is a hosted inference platform for frontier and open-weight models
behind an OpenAI-compatible API. In OpenClaw it is a bundled model provider,
which means you can select it with the provider id `gmi`, store credentials
through normal model auth, and use model refs like
behind an OpenAI-compatible API. In OpenClaw it is an official external provider
plugin, which means you install it once, select it with the provider id `gmi`,
store credentials through normal model auth, and use model refs like
`gmi/google/gemini-3.1-flash-lite`.
Use GMI when you want one API key for several hosted model families, including
@@ -24,7 +24,14 @@ model availability, billing, rate limits, and any provider-side routing policy.
## Setup
Create an API key in GMI Cloud, then run:
Install the plugin, restart the gateway, then create an API key in GMI Cloud:
```bash
openclaw plugins install @openclaw/gmi-provider
openclaw gateway restart
```
Then run:
```bash
openclaw onboard --auth-choice gmi-api-key
@@ -60,7 +67,7 @@ GPU control matters more than hosted convenience.
## Models
The bundled catalog seeds commonly available GMI Cloud route ids, including:
The plugin catalog seeds commonly available GMI Cloud route ids, including:
- `gmi/zai-org/GLM-5.1-FP8`
- `gmi/deepseek-ai/DeepSeek-V3.2`
+14
View File
@@ -0,0 +1,14 @@
# OpenClaw GMI Cloud Provider
Official OpenClaw provider plugin for hosted GMI Cloud models through an
OpenAI-compatible API.
Install from OpenClaw:
```bash
openclaw plugins install @openclaw/gmi-provider
openclaw gateway restart
```
Configure a GMI Cloud API key, then select models with refs such as
`gmi/google/gemini-3.1-flash-lite`.
+1 -1
View File
@@ -11,7 +11,7 @@ const PROVIDER_ID = "gmi";
export default defineSingleProviderPluginEntry({
id: PROVIDER_ID,
name: "GMI Cloud Provider",
description: "Bundled GMI Cloud provider plugin",
description: "GMI Cloud provider plugin",
provider: {
label: "GMI Cloud",
docsPath: "/providers/gmi",
+12
View File
@@ -0,0 +1,12 @@
{
"name": "@openclaw/gmi-provider",
"version": "2026.6.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/gmi-provider",
"version": "2026.6.8"
}
}
}
+2
View File
@@ -1,5 +1,7 @@
{
"id": "gmi",
"name": "GMI Cloud",
"description": "OpenClaw GMI Cloud provider plugin.",
"activation": {
"onStartup": false
},
+23 -3
View File
@@ -1,8 +1,11 @@
{
"name": "@openclaw/gmi-provider",
"version": "2026.6.8",
"private": true,
"description": "OpenClaw GMI Cloud provider plugin",
"description": "OpenClaw GMI Cloud 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/gmi-provider",
"npmSpec": "@openclaw/gmi-provider",
"defaultChoice": "npm",
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.8"
},
"build": {
"openclawVersion": "2026.6.8",
"bundledDist": false
},
"release": {
"publishToClawHub": true,
"publishToNpm": true
}
}
}
+1
View File
@@ -90,6 +90,7 @@
"!dist/extensions/feishu/**",
"!dist/extensions/google-meet/**",
"!dist/extensions/googlechat/**",
"!dist/extensions/gmi/**",
"!dist/extensions/line/**",
"!dist/extensions/llama-cpp/**",
"!dist/extensions/lobster/**",
@@ -113,6 +113,49 @@
}
}
},
{
"name": "@openclaw/gmi-provider",
"description": "OpenClaw GMI Cloud provider plugin",
"source": "official",
"kind": "provider",
"openclaw": {
"plugin": {
"id": "gmi",
"label": "GMI Cloud"
},
"providers": [
{
"id": "gmi",
"aliases": ["gmi-cloud", "gmicloud"],
"name": "GMI Cloud",
"docs": "/providers/gmi",
"categories": ["cloud", "llm"],
"authChoices": [
{
"method": "api-key",
"choiceId": "gmi-api-key",
"choiceLabel": "GMI Cloud API key",
"choiceHint": "OpenAI-compatible GMI Cloud endpoint.",
"groupId": "gmi",
"groupLabel": "GMI Cloud",
"groupHint": "OpenAI-compatible GMI Cloud endpoint",
"optionKey": "gmiApiKey",
"cliFlag": "--gmi-api-key",
"cliOption": "--gmi-api-key <key>",
"cliDescription": "GMI Cloud API key",
"onboardingScopes": ["text-inference"]
}
]
}
],
"install": {
"clawhubSpec": "clawhub:@openclaw/gmi-provider",
"npmSpec": "@openclaw/gmi-provider",
"defaultChoice": "npm",
"minHostVersion": ">=2026.6.8"
}
}
},
{
"name": "@openclaw/pixverse-provider",
"description": "OpenClaw PixVerse video provider plugin",
@@ -257,6 +257,48 @@ describe("configured plugin install release step", () => {
expect(result.channelIds).toStrictEqual([]);
});
it("collects provider plugins from documented external provider aliases", async () => {
mocks.resolveProviderInstallCatalogEntries.mockReturnValue([
{
pluginId: "gmi",
providerId: "gmi",
providerAliases: ["gmi-cloud", "gmicloud"],
},
]);
const { collectReleaseConfiguredPluginIds } =
await import("./release-configured-plugin-installs.js");
const result = collectReleaseConfiguredPluginIds({
cfg: {
agents: {
defaults: {
model: "gmi-cloud/google/gemini-3.1-flash-lite",
},
},
auth: {
profiles: {
gmi: {
provider: "gmi-cloud",
mode: "api_key",
},
},
},
models: {
providers: {
gmicloud: {
baseUrl: "https://api.gmi-serving.com/v1",
models: [],
},
},
},
},
env: {},
});
expect(result.pluginIds).toEqual(["gmi"]);
expect(result.channelIds).toStrictEqual([]);
});
it("collects Codex from selectable OpenAI agent models even without integration discovery", async () => {
const { collectReleaseConfiguredPluginIds } =
await import("./release-configured-plugin-installs.js");
@@ -192,7 +192,11 @@ function collectProviderPluginIds(cfg: OpenClawConfig, env: NodeJS.ProcessEnv):
env,
includeUntrustedWorkspacePlugins: false,
})) {
if (configuredProviders.has(entry.providerId.toLowerCase())) {
if (
[entry.providerId, ...(entry.providerAliases ?? [])].some((providerId) =>
configuredProviders.has(providerId.toLowerCase()),
)
) {
ids.add(entry.pluginId);
}
}
@@ -55,6 +55,18 @@ describe("official external plugin catalog", () => {
);
});
it("lists GMI Cloud as an official external provider", () => {
const gmi = expectCatalogEntry("gmi");
expect(resolveOfficialExternalPluginId(gmi)).toBe("gmi");
expect(resolveOfficialExternalPluginInstall(gmi)).toEqual({
clawhubSpec: "clawhub:@openclaw/gmi-provider",
npmSpec: "@openclaw/gmi-provider",
defaultChoice: "npm",
minHostVersion: ">=2026.6.8",
});
});
it("allows invalid-config recovery for externalized stock plugins", () => {
expect(resolveOfficialExternalPluginInstall(expectCatalogEntry("brave"))).toMatchObject({
npmSpec: "@openclaw/brave-plugin",
@@ -33,6 +33,7 @@ export type OfficialExternalProviderAuthChoice = {
export type OfficialExternalProviderCatalogProvider = {
id?: string;
aliases?: readonly string[];
name?: string;
docs?: string;
categories?: readonly string[];
@@ -620,6 +620,43 @@ describe("provider install catalog", () => {
});
});
it("preserves official external provider aliases for configured-plugin repair", () => {
listOfficialExternalProviderCatalogEntries.mockReturnValue([
{
name: "@openclaw/gmi-provider",
source: "official",
kind: "provider",
openclaw: {
plugin: { id: "gmi", label: "GMI Cloud" },
providers: [
{
id: "gmi",
aliases: ["gmi-cloud", "gmicloud"],
name: "GMI Cloud",
authChoices: [
{
method: "api-key",
choiceId: "gmi-api-key",
choiceLabel: "GMI Cloud API key",
},
],
},
],
install: {
npmSpec: "@openclaw/gmi-provider",
defaultChoice: "npm",
},
},
},
]);
expect(resolveProviderInstallCatalogEntry("gmi-api-key")).toMatchObject({
pluginId: "gmi",
providerId: "gmi",
providerAliases: ["gmi-cloud", "gmicloud"],
});
});
it("surfaces provider-index ClawHub install metadata as the preferred source", () => {
loadOpenClawProviderIndex.mockReturnValue({
version: 1,
+9
View File
@@ -27,6 +27,7 @@ import {
/** Provider setup choice paired with install metadata for the owning plugin. */
export type ProviderInstallCatalogEntry = ProviderAuthChoiceMetadata & {
providerAliases?: string[];
label: string;
origin: PluginOrigin;
install: PluginPackageInstall;
@@ -332,6 +333,13 @@ function resolveOfficialExternalProviderInstallCatalogEntries(params: {
if (!providerId || !label) {
continue;
}
const providerAliases = [
...new Set(
(provider.aliases ?? [])
.map((alias) => alias.trim())
.filter((alias) => alias && alias !== providerId),
),
];
for (const choice of provider.authChoices ?? []) {
const methodId = choice.method?.trim();
const choiceId = choice.choiceId?.trim();
@@ -342,6 +350,7 @@ function resolveOfficialExternalProviderInstallCatalogEntries(params: {
entries.push({
pluginId,
providerId,
...(providerAliases.length > 0 ? { providerAliases } : {}),
methodId,
choiceId,
choiceLabel,
+23 -6
View File
@@ -122,10 +122,32 @@ describe("OpenClaw dual-published plugin metadata", () => {
{
extensionId: "diagnostics-otel",
packageName: "@openclaw/diagnostics-otel",
install: {
clawhubSpec: "clawhub:@openclaw/diagnostics-otel",
defaultChoice: "npm",
minHostVersion: ">=2026.4.25",
npmSpec: "@openclaw/diagnostics-otel",
},
},
{
extensionId: "diagnostics-prometheus",
packageName: "@openclaw/diagnostics-prometheus",
install: {
clawhubSpec: "clawhub:@openclaw/diagnostics-prometheus",
defaultChoice: "npm",
minHostVersion: ">=2026.4.25",
npmSpec: "@openclaw/diagnostics-prometheus",
},
},
{
extensionId: "gmi",
packageName: "@openclaw/gmi-provider",
install: {
clawhubSpec: "clawhub:@openclaw/gmi-provider",
defaultChoice: "npm",
minHostVersion: ">=2026.6.8",
npmSpec: "@openclaw/gmi-provider",
},
},
] as const;
@@ -158,12 +180,7 @@ describe("OpenClaw dual-published plugin metadata", () => {
};
};
expect(packageJson.openclaw?.install).toEqual({
clawhubSpec: `clawhub:${plugin.packageName}`,
defaultChoice: "npm",
minHostVersion: ">=2026.4.25",
npmSpec: plugin.packageName,
});
expect(packageJson.openclaw?.install).toEqual(plugin.install);
expect(packageJson.openclaw?.release).toEqual({
publishToClawHub: true,
publishToNpm: true,