diff --git a/.github/labeler.yml b/.github/labeler.yml
index c46dd3bdb29..8aa082e3f67 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -448,6 +448,11 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/kimi-coding/**"
+"extensions: longcat":
+ - changed-files:
+ - any-glob-to-any-file:
+ - "extensions/longcat/**"
+ - "docs/providers/longcat.md"
"extensions: minimax":
- changed-files:
- any-glob-to-any-file:
diff --git a/docs/docs.json b/docs/docs.json
index b46e7efe456..1f261af5965 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -1481,6 +1481,7 @@
"providers/kilocode",
"providers/litellm",
"providers/lmstudio",
+ "providers/longcat",
"providers/minimax",
"providers/mistral",
"providers/moonshot",
diff --git a/docs/docs_map.md b/docs/docs_map.md
index ed281802f19..dc0d21c02e7 100644
--- a/docs/docs_map.md
+++ b/docs/docs_map.md
@@ -6261,6 +6261,24 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H2: Distribution
- H2: Surface
+## plugins/reference/logbook.md
+
+- Route: /plugins/reference/logbook
+- Headings:
+ - H1: Logbook plugin
+ - H2: Distribution
+ - H2: Surface
+ - H2: Related docs
+
+## plugins/reference/longcat.md
+
+- Route: /plugins/reference/longcat
+- Headings:
+ - H1: LongCat plugin
+ - H2: Distribution
+ - H2: Surface
+ - H2: Related docs
+
## plugins/reference/matrix.md
- Route: /plugins/reference/matrix
@@ -7564,6 +7582,19 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H3: Authentication errors (HTTP 401)
- H2: Related
+## providers/longcat.md
+
+- Route: /providers/longcat
+- Headings:
+ - H2: Install plugin
+ - H2: Getting started
+ - H3: Non-interactive setup
+ - H2: Reasoning behavior
+ - H2: Pricing
+ - H2: Self-hosted LongCat-2.0
+ - H2: Troubleshooting
+ - H2: Related
+
## providers/minimax.md
- Route: /providers/minimax
diff --git a/docs/plugins/plugin-inventory.md b/docs/plugins/plugin-inventory.md
index 7380f8da729..bd9352fd2f0 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
-60 plugins
+61 plugins
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
@@ -105,6 +105,8 @@ Each entry lists the package, distribution route, and description.
- **[lmstudio](/plugins/reference/lmstudio)** (`@openclaw/lmstudio-provider`) - included in OpenClaw. Adds LM Studio model provider support to OpenClaw.
+- **[logbook](/plugins/reference/logbook)** (`@openclaw/logbook`) - included in OpenClaw. Automatic work journal: captures periodic screen snapshots from a paired node and turns them into a reviewable timeline of your day.
+
- **[memory-core](/plugins/reference/memory-core)** (`@openclaw/memory-core`) - included in OpenClaw. Adds agent-callable tools.
- **[memory-wiki](/plugins/reference/memory-wiki)** (`@openclaw/memory-wiki`) - included in OpenClaw. Persistent wiki compiler and Obsidian-friendly knowledge vault for OpenClaw.
@@ -175,7 +177,7 @@ Each entry lists the package, distribution route, and description.
## Official external packages
-68 plugins
+69 plugins
- **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management.
@@ -247,6 +249,8 @@ Each entry lists the package, distribution route, and description.
- **[lobster](/plugins/reference/lobster)** (`@openclaw/lobster`) - npm; ClawHub. Lobster workflow tool plugin for typed pipelines and resumable approvals.
+- **[longcat](/plugins/reference/longcat)** (`@openclaw/longcat-provider`) - npm; ClawHub: `clawhub:@openclaw/longcat-provider`. OpenClaw LongCat provider plugin.
+
- **[matrix](/plugins/reference/matrix)** (`@openclaw/matrix`) - ClawHub: `clawhub:@openclaw/matrix`; npm. OpenClaw Matrix channel plugin for rooms and direct messages.
- **[mattermost](/plugins/reference/mattermost)** (`@openclaw/mattermost`) - npm; ClawHub: `clawhub:@openclaw/mattermost`. Adds the Mattermost channel surface for sending and receiving OpenClaw messages.
diff --git a/docs/plugins/reference.md b/docs/plugins/reference.md
index 18e50dba55c..2a587a3c919 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 130
+Use [Plugin inventory](/plugins/plugin-inventory) to browse all 132
generated plugin reference pages by distribution, package, and description.
diff --git a/docs/plugins/reference/logbook.md b/docs/plugins/reference/logbook.md
new file mode 100644
index 00000000000..6d3e3ce4474
--- /dev/null
+++ b/docs/plugins/reference/logbook.md
@@ -0,0 +1,23 @@
+---
+summary: "Automatic work journal: captures periodic screen snapshots from a paired node and turns them into a reviewable timeline of your day."
+read_when:
+ - You are installing, configuring, or auditing the logbook plugin
+title: "Logbook plugin"
+---
+
+# Logbook plugin
+
+Automatic work journal: captures periodic screen snapshots from a paired node and turns them into a reviewable timeline of your day.
+
+## Distribution
+
+- Package: `@openclaw/logbook`
+- Install route: included in OpenClaw
+
+## Surface
+
+plugin
+
+## Related docs
+
+- [logbook](/plugins/logbook)
diff --git a/docs/plugins/reference/longcat.md b/docs/plugins/reference/longcat.md
new file mode 100644
index 00000000000..fe8a0c06fd3
--- /dev/null
+++ b/docs/plugins/reference/longcat.md
@@ -0,0 +1,23 @@
+---
+summary: "OpenClaw LongCat provider plugin."
+read_when:
+ - You are installing, configuring, or auditing the longcat plugin
+title: "LongCat plugin"
+---
+
+# LongCat plugin
+
+OpenClaw LongCat provider plugin.
+
+## Distribution
+
+- Package: `@openclaw/longcat-provider`
+- Install route: npm; ClawHub: `clawhub:@openclaw/longcat-provider`
+
+## Surface
+
+providers: longcat
+
+## Related docs
+
+- [longcat](/providers/longcat)
diff --git a/docs/providers/index.md b/docs/providers/index.md
index 01b676b095b..9fc1e247387 100644
--- a/docs/providers/index.md
+++ b/docs/providers/index.md
@@ -52,6 +52,7 @@ Looking for chat channel docs (WhatsApp/Telegram/Discord/Slack/Mattermost (plugi
- [Kilocode](/providers/kilocode)
- [LiteLLM (unified gateway)](/providers/litellm)
- [LM Studio (local models)](/providers/lmstudio)
+- [LongCat](/providers/longcat)
- [MiniMax](/providers/minimax)
- [Mistral](/providers/mistral)
- [Moonshot AI (Kimi + Kimi Coding)](/providers/moonshot)
diff --git a/docs/providers/longcat.md b/docs/providers/longcat.md
new file mode 100644
index 00000000000..d15b2f823dd
--- /dev/null
+++ b/docs/providers/longcat.md
@@ -0,0 +1,129 @@
+---
+summary: "LongCat API setup for LongCat-2.0"
+title: "LongCat"
+read_when:
+ - You want to use LongCat-2.0 with OpenClaw
+ - You need the LongCat API key or model limits
+---
+
+[LongCat](https://longcat.ai) provides a hosted API for LongCat-2.0, a
+reasoning model built for coding and agentic workloads. OpenClaw provides the
+official `longcat` plugin for LongCat's OpenAI-compatible endpoint.
+
+| Property | Value |
+| ---------- | ---------------------------------- |
+| Provider | `longcat` |
+| Auth | `LONGCAT_API_KEY` |
+| API | OpenAI-compatible Chat Completions |
+| Base URL | `https://api.longcat.chat/openai` |
+| Model | `longcat/LongCat-2.0` |
+| Context | 1,048,576 tokens |
+| Max output | 131,072 tokens |
+| Input | Text |
+
+## Install plugin
+
+Install the official package, then restart Gateway:
+
+```bash
+openclaw plugins install @openclaw/longcat-provider
+openclaw gateway restart
+```
+
+## Getting started
+
+
+
+ Sign in to the [LongCat API Platform](https://longcat.chat/platform/) and
+ create a key on the [API Keys](https://longcat.chat/platform/api_keys)
+ page.
+
+
+ ```bash
+ openclaw onboard --auth-choice longcat-api-key
+ ```
+
+
+ ```bash
+ openclaw models list --provider longcat
+ ```
+
+
+
+Onboarding adds the hosted catalog and selects `longcat/LongCat-2.0` when no
+primary model is already configured.
+
+### Non-interactive setup
+
+```bash
+openclaw onboard --non-interactive \
+ --mode local \
+ --auth-choice longcat-api-key \
+ --longcat-api-key "$LONGCAT_API_KEY"
+```
+
+## Reasoning behavior
+
+LongCat exposes binary thinking control. OpenClaw maps enabled thinking levels
+to `thinking: { type: "enabled" }` and `/think off` to
+`thinking: { type: "disabled" }`. LongCat does not currently document
+`reasoning_effort`, so OpenClaw does not send it.
+
+LongCat returns reasoning in `reasoning_content`. OpenClaw preserves that field
+when replaying assistant tool-call turns so multi-turn agent sessions retain
+the provider's expected message shape.
+
+## Pricing
+
+The built-in catalog uses LongCat's pay-as-you-go list prices in USD per million
+tokens: $0.75 uncached input, $0.015 cached input, and $2.95 output. LongCat may
+offer temporary discounts; the [pricing page](https://longcat.chat/platform/docs/Pricing/LongCat-2.0.html)
+and your billing records are authoritative.
+
+## Self-hosted LongCat-2.0
+
+The `longcat` provider targets LongCat's hosted API. For the open weights on
+[Hugging Face](https://huggingface.co/meituan-longcat/LongCat-2.0), serve the
+model through an OpenAI-compatible runtime and use OpenClaw's existing
+[vLLM](/providers/vllm) or [SGLang](/providers/sglang) provider instead.
+
+Keep the runtime's exact model identifier in the self-hosted provider catalog;
+do not route a local deployment through `longcat/LongCat-2.0`.
+
+## Troubleshooting
+
+
+
+ Daemon-managed Gateway processes do not inherit every interactive shell
+ variable. Put `LONGCAT_API_KEY` in `~/.openclaw/.env`, configure it through
+ onboarding, or use an approved secret reference.
+
+
+
+ `402` means the account has insufficient token quota. `429` means the API
+ key hit a rate limit. Check [LongCat usage](https://longcat.chat/platform/usage)
+ and retry rate-limited requests after the provider's backoff window.
+
+
+
+ Run `openclaw plugins list` and confirm the `longcat` plugin is
+ enabled, then run `openclaw models list --provider longcat`.
+
+
+
+## Related
+
+
+
+ Provider configuration, model refs, and failover behavior.
+
+
+ Hosted API endpoints, authentication, limits, and examples.
+
+
+ Architecture, deployment guidance, and model details.
+
+
+ Store provider credentials without embedding plaintext in config.
+
+
diff --git a/extensions/longcat/README.md b/extensions/longcat/README.md
new file mode 100644
index 00000000000..4ff5ad656d3
--- /dev/null
+++ b/extensions/longcat/README.md
@@ -0,0 +1,13 @@
+# OpenClaw LongCat Provider
+
+Official OpenClaw provider plugin for LongCat-2.0 through LongCat's hosted
+OpenAI-compatible API.
+
+Install from OpenClaw:
+
+```bash
+openclaw plugins install @openclaw/longcat-provider
+openclaw gateway restart
+```
+
+Configure `LONGCAT_API_KEY`, then select `longcat/LongCat-2.0`.
diff --git a/extensions/longcat/api.ts b/extensions/longcat/api.ts
new file mode 100644
index 00000000000..2ebcccc6c56
--- /dev/null
+++ b/extensions/longcat/api.ts
@@ -0,0 +1,10 @@
+// LongCat API module exposes the plugin public contract.
+export {
+ LONGCAT_BASE_URL,
+ LONGCAT_DEFAULT_MODEL_ID,
+ LONGCAT_DEFAULT_MODEL_REF,
+ LONGCAT_MODEL_CATALOG,
+} from "./models.js";
+export { applyLongCatConfig } from "./onboard.js";
+export { buildLongCatProvider } from "./provider-catalog.js";
+export { createLongCatThinkingWrapper } from "./stream.js";
diff --git a/extensions/longcat/index.test.ts b/extensions/longcat/index.test.ts
new file mode 100644
index 00000000000..6565317a5fc
--- /dev/null
+++ b/extensions/longcat/index.test.ts
@@ -0,0 +1,183 @@
+// LongCat tests cover provider registration, onboarding, and wire compatibility.
+import { readFileSync } from "node:fs";
+import type { StreamFn } from "openclaw/plugin-sdk/agent-core";
+import {
+ createAssistantMessageEventStream,
+ type Context,
+ type Model,
+} from "openclaw/plugin-sdk/llm";
+import { registerSingleProviderPlugin } from "openclaw/plugin-sdk/plugin-test-runtime";
+import { resolveAgentModelPrimaryValue } from "openclaw/plugin-sdk/provider-onboard";
+import { buildOpenAICompletionsParams } from "openclaw/plugin-sdk/provider-transport-runtime";
+import { describe, expect, it } from "vitest";
+import plugin from "./index.js";
+import { LONGCAT_DEFAULT_MODEL_REF } from "./models.js";
+import { applyLongCatConfig } from "./onboard.js";
+import { buildLongCatProvider } from "./provider-catalog.js";
+import { createLongCatThinkingWrapper } from "./stream.js";
+
+function readManifest() {
+ return JSON.parse(readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf8")) as {
+ providerAuthChoices?: Array<{ choiceId?: string; optionKey?: string; cliFlag?: string }>;
+ setup?: { providers?: Array<{ id?: string; envVars?: string[] }> };
+ };
+}
+
+function requireLongCatModel(): Model<"openai-completions"> {
+ const model = buildLongCatProvider().models?.[0];
+ if (!model) {
+ throw new Error("LongCat catalog did not provide a model");
+ }
+ return {
+ ...model,
+ api: "openai-completions",
+ baseUrl: "https://api.longcat.chat/openai",
+ provider: "longcat",
+ input: ["text"],
+ cost: { ...model.cost },
+ } as Model<"openai-completions">;
+}
+
+describe("LongCat provider plugin", () => {
+ it("registers the manifest-owned API key onboarding flow", async () => {
+ const provider = await registerSingleProviderPlugin(plugin);
+
+ expect(provider).toMatchObject({
+ id: "longcat",
+ aliases: ["meituan-longcat"],
+ envVars: ["LONGCAT_API_KEY"],
+ });
+ expect(provider.auth[0]).toMatchObject({
+ id: "api-key",
+ kind: "api_key",
+ wizard: { choiceId: "longcat-api-key" },
+ });
+ expect(readManifest().providerAuthChoices).toEqual([
+ expect.objectContaining({
+ choiceId: "longcat-api-key",
+ optionKey: "longcatApiKey",
+ cliFlag: "--longcat-api-key",
+ }),
+ ]);
+ expect(readManifest().setup?.providers).toEqual([
+ { id: "longcat", envVars: ["LONGCAT_API_KEY"] },
+ ]);
+ });
+
+ it("exposes the hosted LongCat-2.0 catalog", () => {
+ expect(buildLongCatProvider()).toMatchObject({
+ baseUrl: "https://api.longcat.chat/openai",
+ api: "openai-completions",
+ models: [
+ expect.objectContaining({
+ id: "LongCat-2.0",
+ reasoning: true,
+ contextWindow: 1_048_576,
+ maxTokens: 131_072,
+ compat: {
+ supportsStore: false,
+ supportsDeveloperRole: false,
+ supportsReasoningEffort: false,
+ supportsUsageInStreaming: false,
+ supportsStrictMode: false,
+ maxTokensField: "max_tokens",
+ requiresReasoningContentOnAssistantMessages: true,
+ thinkingFormat: "deepseek",
+ },
+ }),
+ ],
+ });
+ });
+
+ it("applies the LongCat catalog without replacing an existing primary model", () => {
+ const result = applyLongCatConfig({
+ agents: { defaults: { model: { primary: "openai/gpt-5.5" } } },
+ });
+
+ expect(resolveAgentModelPrimaryValue(result.agents?.defaults?.model)).toBe("openai/gpt-5.5");
+ expect(result.agents?.defaults?.models?.[LONGCAT_DEFAULT_MODEL_REF]).toEqual({
+ alias: "LongCat 2.0",
+ });
+ });
+
+ it("uses LongCat thinking and replay fields without reasoning_effort", () => {
+ const model = requireLongCatModel();
+ const context = {
+ systemPrompt: "system",
+ messages: [
+ { role: "user", content: "read it", timestamp: 1 },
+ {
+ role: "assistant",
+ api: "openai-completions",
+ provider: "longcat",
+ model: "LongCat-2.0",
+ content: [
+ {
+ type: "thinking",
+ thinking: "use the read tool",
+ thinkingSignature: "reasoning_content",
+ },
+ { type: "toolCall", id: "call_1", name: "read", arguments: {} },
+ ],
+ usage: {
+ input: 0,
+ output: 0,
+ cacheRead: 0,
+ cacheWrite: 0,
+ totalTokens: 0,
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
+ },
+ stopReason: "toolUse",
+ timestamp: 2,
+ },
+ ],
+ tools: [
+ {
+ name: "read",
+ description: "Read data",
+ parameters: { type: "object", properties: {} },
+ },
+ ],
+ } as Context;
+ let payload: Record | undefined;
+ const baseStreamFn: StreamFn = (streamModel, streamContext, options) => {
+ const params = buildOpenAICompletionsParams(
+ streamModel as Model<"openai-completions">,
+ streamContext,
+ { maxTokens: 2048, reasoning: "high" } as never,
+ ) as Record;
+ options?.onPayload?.(params, streamModel);
+ const stream = createAssistantMessageEventStream();
+ queueMicrotask(() => stream.end());
+ return stream;
+ };
+ const wrappedStreamFn = createLongCatThinkingWrapper(baseStreamFn, "high");
+
+ void wrappedStreamFn(model, context, {
+ onPayload: (nextPayload) => {
+ payload = nextPayload as Record;
+ },
+ });
+ if (!payload) {
+ throw new Error("LongCat payload was not captured");
+ }
+
+ expect(payload).toMatchObject({
+ max_tokens: 2048,
+ thinking: { type: "enabled" },
+ });
+ expect(payload).not.toHaveProperty("max_completion_tokens");
+ expect(payload).not.toHaveProperty("reasoning_effort");
+ expect(payload).not.toHaveProperty("store");
+ expect(payload).not.toHaveProperty("stream_options");
+ expect(payload.messages).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({ role: "system", content: "system" }),
+ expect.objectContaining({
+ role: "assistant",
+ reasoning_content: "use the read tool",
+ }),
+ ]),
+ );
+ });
+});
diff --git a/extensions/longcat/index.ts b/extensions/longcat/index.ts
new file mode 100644
index 00000000000..6ea3b288ce5
--- /dev/null
+++ b/extensions/longcat/index.ts
@@ -0,0 +1,53 @@
+// LongCat plugin entrypoint registers its OpenClaw integration.
+import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
+import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared";
+import { buildProviderToolCompatFamilyHooks } from "openclaw/plugin-sdk/provider-tools";
+import { LONGCAT_DEFAULT_MODEL_REF } from "./models.js";
+import { applyLongCatConfig } from "./onboard.js";
+import { buildLongCatProvider } from "./provider-catalog.js";
+import { createLongCatThinkingWrapper } from "./stream.js";
+
+const PROVIDER_ID = "longcat";
+
+export default defineSingleProviderPluginEntry({
+ id: PROVIDER_ID,
+ name: "LongCat Provider",
+ description: "Official LongCat provider plugin",
+ provider: {
+ label: "LongCat",
+ docsPath: "/providers/longcat",
+ aliases: ["meituan-longcat"],
+ envVars: ["LONGCAT_API_KEY"],
+ auth: [
+ {
+ methodId: "api-key",
+ label: "LongCat API key",
+ hint: "API key",
+ optionKey: "longcatApiKey",
+ flagName: "--longcat-api-key",
+ envVar: "LONGCAT_API_KEY",
+ promptMessage: "Enter LongCat API key",
+ defaultModel: LONGCAT_DEFAULT_MODEL_REF,
+ applyConfig: (cfg) => applyLongCatConfig(cfg),
+ noteTitle: "LongCat",
+ noteMessage: "Manage API keys at https://longcat.chat/platform/api_keys",
+ wizard: {
+ choiceId: "longcat-api-key",
+ choiceLabel: "LongCat API key",
+ groupId: "longcat",
+ groupLabel: "LongCat",
+ groupHint: "API key",
+ },
+ },
+ ],
+ catalog: {
+ buildProvider: buildLongCatProvider,
+ },
+ ...buildProviderReplayFamilyHooks({
+ family: "openai-compatible",
+ dropReasoningFromHistory: false,
+ }),
+ ...buildProviderToolCompatFamilyHooks("openai"),
+ wrapStreamFn: (ctx) => createLongCatThinkingWrapper(ctx.streamFn, ctx.thinkingLevel),
+ },
+});
diff --git a/extensions/longcat/models.ts b/extensions/longcat/models.ts
new file mode 100644
index 00000000000..ba078199b71
--- /dev/null
+++ b/extensions/longcat/models.ts
@@ -0,0 +1,14 @@
+// LongCat plugin module implements models behavior.
+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 LONGCAT_MANIFEST_PROVIDER = buildManifestModelProviderConfig({
+ providerId: "longcat",
+ catalog: manifest.modelCatalog.providers.longcat,
+});
+
+export const LONGCAT_BASE_URL = LONGCAT_MANIFEST_PROVIDER.baseUrl;
+export const LONGCAT_MODEL_CATALOG: ModelDefinitionConfig[] = LONGCAT_MANIFEST_PROVIDER.models;
+export const LONGCAT_DEFAULT_MODEL_ID = "LongCat-2.0";
+export const LONGCAT_DEFAULT_MODEL_REF = `longcat/${LONGCAT_DEFAULT_MODEL_ID}`;
diff --git a/extensions/longcat/npm-shrinkwrap.json b/extensions/longcat/npm-shrinkwrap.json
new file mode 100644
index 00000000000..b870e52704e
--- /dev/null
+++ b/extensions/longcat/npm-shrinkwrap.json
@@ -0,0 +1,12 @@
+{
+ "name": "@openclaw/longcat-provider",
+ "version": "2026.6.11",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@openclaw/longcat-provider",
+ "version": "2026.6.11"
+ }
+ }
+}
diff --git a/extensions/longcat/onboard.ts b/extensions/longcat/onboard.ts
new file mode 100644
index 00000000000..efc5434d034
--- /dev/null
+++ b/extensions/longcat/onboard.ts
@@ -0,0 +1,21 @@
+// LongCat setup module handles plugin onboarding behavior.
+import {
+ createModelCatalogPresetAppliers,
+ type OpenClawConfig,
+} from "openclaw/plugin-sdk/provider-onboard";
+import { LONGCAT_BASE_URL, LONGCAT_DEFAULT_MODEL_REF, LONGCAT_MODEL_CATALOG } from "./models.js";
+
+const longCatPresetAppliers = createModelCatalogPresetAppliers({
+ primaryModelRef: LONGCAT_DEFAULT_MODEL_REF,
+ resolveParams: (_cfg: OpenClawConfig) => ({
+ providerId: "longcat",
+ api: "openai-completions",
+ baseUrl: LONGCAT_BASE_URL,
+ catalogModels: LONGCAT_MODEL_CATALOG,
+ aliases: [{ modelRef: LONGCAT_DEFAULT_MODEL_REF, alias: "LongCat 2.0" }],
+ }),
+});
+
+export function applyLongCatConfig(cfg: OpenClawConfig): OpenClawConfig {
+ return longCatPresetAppliers.applyConfig(cfg);
+}
diff --git a/extensions/longcat/openclaw.plugin.json b/extensions/longcat/openclaw.plugin.json
new file mode 100644
index 00000000000..0bd7f1d439f
--- /dev/null
+++ b/extensions/longcat/openclaw.plugin.json
@@ -0,0 +1,82 @@
+{
+ "id": "longcat",
+ "name": "LongCat",
+ "description": "OpenClaw LongCat provider plugin.",
+ "activation": {
+ "onStartup": false
+ },
+ "enabledByDefault": true,
+ "providers": ["longcat"],
+ "providerRequest": {
+ "providers": {
+ "longcat": {
+ "family": "longcat"
+ }
+ }
+ },
+ "modelCatalog": {
+ "providers": {
+ "longcat": {
+ "baseUrl": "https://api.longcat.chat/openai",
+ "api": "openai-completions",
+ "models": [
+ {
+ "id": "LongCat-2.0",
+ "name": "LongCat 2.0",
+ "reasoning": true,
+ "input": ["text"],
+ "contextWindow": 1048576,
+ "maxTokens": 131072,
+ "cost": {
+ "input": 0.75,
+ "output": 2.95,
+ "cacheRead": 0.015,
+ "cacheWrite": 0.75
+ },
+ "compat": {
+ "supportsStore": false,
+ "supportsDeveloperRole": false,
+ "supportsReasoningEffort": false,
+ "supportsUsageInStreaming": false,
+ "supportsStrictMode": false,
+ "maxTokensField": "max_tokens",
+ "requiresReasoningContentOnAssistantMessages": true,
+ "thinkingFormat": "deepseek"
+ }
+ }
+ ]
+ }
+ },
+ "discovery": {
+ "longcat": "static"
+ }
+ },
+ "setup": {
+ "providers": [
+ {
+ "id": "longcat",
+ "envVars": ["LONGCAT_API_KEY"]
+ }
+ ]
+ },
+ "providerAuthChoices": [
+ {
+ "provider": "longcat",
+ "method": "api-key",
+ "choiceId": "longcat-api-key",
+ "choiceLabel": "LongCat API key",
+ "groupId": "longcat",
+ "groupLabel": "LongCat",
+ "groupHint": "API key",
+ "optionKey": "longcatApiKey",
+ "cliFlag": "--longcat-api-key",
+ "cliOption": "--longcat-api-key ",
+ "cliDescription": "LongCat API key"
+ }
+ ],
+ "configSchema": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {}
+ }
+}
diff --git a/extensions/longcat/package.json b/extensions/longcat/package.json
new file mode 100644
index 00000000000..be5fa7c84de
--- /dev/null
+++ b/extensions/longcat/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "@openclaw/longcat-provider",
+ "version": "2026.6.11",
+ "description": "OpenClaw LongCat 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/longcat-provider",
+ "npmSpec": "@openclaw/longcat-provider",
+ "defaultChoice": "npm",
+ "minHostVersion": ">=2026.6.8"
+ },
+ "compat": {
+ "pluginApi": ">=2026.6.11"
+ },
+ "build": {
+ "openclawVersion": "2026.6.11",
+ "bundledDist": false
+ },
+ "release": {
+ "publishToClawHub": true,
+ "publishToNpm": true
+ }
+ }
+}
diff --git a/extensions/longcat/provider-catalog.ts b/extensions/longcat/provider-catalog.ts
new file mode 100644
index 00000000000..ccc5b192afd
--- /dev/null
+++ b/extensions/longcat/provider-catalog.ts
@@ -0,0 +1,11 @@
+// LongCat provider module implements model/runtime integration.
+import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
+import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared";
+import manifest from "./openclaw.plugin.json" with { type: "json" };
+
+export function buildLongCatProvider(): ModelProviderConfig {
+ return buildManifestModelProviderConfig({
+ providerId: "longcat",
+ catalog: manifest.modelCatalog.providers.longcat,
+ });
+}
diff --git a/extensions/longcat/stream.ts b/extensions/longcat/stream.ts
new file mode 100644
index 00000000000..f782727a297
--- /dev/null
+++ b/extensions/longcat/stream.ts
@@ -0,0 +1,20 @@
+// LongCat stream helpers apply the provider's binary thinking control.
+import type { ProviderWrapStreamFnContext } from "openclaw/plugin-sdk/plugin-entry";
+import { createPayloadPatchStreamWrapper } from "openclaw/plugin-sdk/provider-stream-shared";
+
+export function createLongCatThinkingWrapper(
+ baseStreamFn: ProviderWrapStreamFnContext["streamFn"],
+ thinkingLevel: ProviderWrapStreamFnContext["thinkingLevel"],
+): NonNullable {
+ return createPayloadPatchStreamWrapper(
+ baseStreamFn,
+ ({ payload }) => {
+ payload.thinking = { type: thinkingLevel === "off" ? "disabled" : "enabled" };
+ delete payload.reasoning_effort;
+ },
+ {
+ shouldPatch: ({ model }) =>
+ model.api === "openai-completions" && model.provider === "longcat",
+ },
+ );
+}
diff --git a/extensions/longcat/tsconfig.json b/extensions/longcat/tsconfig.json
new file mode 100644
index 00000000000..b8a85a99ac3
--- /dev/null
+++ b/extensions/longcat/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "extends": "../tsconfig.package-boundary.base.json",
+ "compilerOptions": {
+ "rootDir": "."
+ },
+ "include": ["./*.ts", "./src/**/*.ts"],
+ "exclude": [
+ "./**/*.test.ts",
+ "./dist/**",
+ "./node_modules/**",
+ "./src/test-support/**",
+ "./src/**/*test-helpers.ts",
+ "./src/**/*test-harness.ts",
+ "./src/**/*test-support.ts"
+ ]
+}
diff --git a/package.json b/package.json
index fdf898e12c9..20749f7b1cb 100644
--- a/package.json
+++ b/package.json
@@ -112,6 +112,7 @@
"!dist/extensions/line/**",
"!dist/extensions/llama-cpp/**",
"!dist/extensions/lobster/**",
+ "!dist/extensions/longcat/**",
"!dist/extensions/mattermost/**",
"!dist/extensions/memory-lancedb/**",
"!dist/extensions/matrix/**",
diff --git a/packages/ai/src/providers/openai-completions.test.ts b/packages/ai/src/providers/openai-completions.test.ts
index 5f25403bc46..60f73e4874b 100644
--- a/packages/ai/src/providers/openai-completions.test.ts
+++ b/packages/ai/src/providers/openai-completions.test.ts
@@ -24,8 +24,9 @@ const mockChunksRef: {
chunks: OpenAICompatibleChatCompletionChunk[];
stream?: AsyncIterable;
} = { chunks: [] };
-const mockOpenAIOptionsRef: { options: unknown[]; requests: unknown[] } = {
+const mockOpenAIOptionsRef: { options: unknown[]; payloads: unknown[]; requests: unknown[] } = {
options: [],
+ payloads: [],
requests: [],
};
@@ -37,7 +38,8 @@ vi.mock("openai", () => {
chat = {
completions: {
- create: (_params: unknown, requestOptions: unknown) => {
+ create: (params: unknown, requestOptions: unknown) => {
+ mockOpenAIOptionsRef.payloads.push(params);
mockOpenAIOptionsRef.requests.push(requestOptions);
return {
withResponse: async () => {
@@ -70,6 +72,7 @@ import { streamOpenAICompletions, streamSimpleOpenAICompletions } from "./openai
beforeEach(() => {
mockChunksRef.chunks = [];
mockChunksRef.stream = undefined;
+ mockOpenAIOptionsRef.payloads = [];
mockOpenAIOptionsRef.requests = [];
});
@@ -161,6 +164,30 @@ function createNeverYieldingStream(): AsyncIterable {
+ it("omits reasoning_effort when deepseek-format compatibility disables it", async () => {
+ mockChunksRef.chunks = [makeTextChunk("ok"), makeFinishChunk("stop")];
+ const compatibleModel = {
+ ...reasoningModel,
+ provider: "longcat",
+ baseUrl: "https://api.longcat.chat/openai",
+ compat: {
+ thinkingFormat: "deepseek" as const,
+ supportsReasoningEffort: false,
+ },
+ } satisfies Model<"openai-completions">;
+
+ const stream = streamOpenAICompletions(compatibleModel, context, {
+ apiKey: "sk-test",
+ reasoningEffort: "high",
+ });
+ await stream.result();
+
+ expect(mockOpenAIOptionsRef.payloads[0]).toMatchObject({
+ thinking: { type: "enabled" },
+ });
+ expect(mockOpenAIOptionsRef.payloads[0]).not.toHaveProperty("reasoning_effort");
+ });
+
it("configures the OpenAI SDK client with the host-built model fetch", async () => {
mockOpenAIOptionsRef.options = [];
mockChunksRef.chunks = [makeTextChunk("ok"), makeFinishChunk("stop")];
diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts
index 4f19ba0236e..6a3c58c4a25 100644
--- a/packages/ai/src/providers/openai-completions.ts
+++ b/packages/ai/src/providers/openai-completions.ts
@@ -755,7 +755,7 @@ function buildParams(
};
} else if (compat.thinkingFormat === "deepseek" && model.reasoning) {
params.thinking = { type: options?.reasoningEffort ? "enabled" : "disabled" };
- if (options?.reasoningEffort) {
+ if (options?.reasoningEffort && compat.supportsReasoningEffort) {
params.reasoning_effort =
model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;
}
diff --git a/packages/model-catalog-core/src/model-catalog-normalize.test.ts b/packages/model-catalog-core/src/model-catalog-normalize.test.ts
index 1ee6bcaece2..5c6247055b1 100644
--- a/packages/model-catalog-core/src/model-catalog-normalize.test.ts
+++ b/packages/model-catalog-core/src/model-catalog-normalize.test.ts
@@ -67,6 +67,7 @@ describe("model catalog normalization", () => {
sendSessionIdHeader: false,
supportsEagerToolInputStreaming: false,
supportsLongCacheRetention: true,
+ requiresReasoningContentOnAssistantMessages: true,
supportsStore: "yes",
thinkingFormat: "together",
unknownFlag: true,
@@ -163,6 +164,7 @@ describe("model catalog normalization", () => {
sendSessionIdHeader: false,
supportsEagerToolInputStreaming: false,
supportsLongCacheRetention: true,
+ requiresReasoningContentOnAssistantMessages: true,
thinkingFormat: "together",
},
status: "preview",
diff --git a/packages/model-catalog-core/src/model-catalog-normalize.ts b/packages/model-catalog-core/src/model-catalog-normalize.ts
index b2051413650..d4dbc29dd15 100644
--- a/packages/model-catalog-core/src/model-catalog-normalize.ts
+++ b/packages/model-catalog-core/src/model-catalog-normalize.ts
@@ -383,6 +383,7 @@ function normalizeModelCatalogCompat(value: unknown): ModelCatalogCompatConfig |
"requiresToolResultName",
"requiresAssistantAfterToolResult",
"requiresThinkingAsText",
+ "requiresReasoningContentOnAssistantMessages",
"zaiToolStream",
"sendSessionAffinityHeaders",
"sendSessionIdHeader",
diff --git a/packages/model-catalog-core/src/model-catalog-types.ts b/packages/model-catalog-core/src/model-catalog-types.ts
index b185d4e468d..c5e008d57a7 100644
--- a/packages/model-catalog-core/src/model-catalog-types.ts
+++ b/packages/model-catalog-core/src/model-catalog-types.ts
@@ -47,6 +47,7 @@ export type ModelCatalogCompatConfig = {
requiresToolResultName?: boolean;
requiresAssistantAfterToolResult?: boolean;
requiresThinkingAsText?: boolean;
+ requiresReasoningContentOnAssistantMessages?: boolean;
openRouterRouting?: ModelCatalogOpenRouterRouting;
vercelGatewayRouting?: ModelCatalogVercelGatewayRouting;
zaiToolStream?: boolean;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a7e2d19dba3..f9a140f8fec 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -969,6 +969,12 @@ importers:
extensions/lmstudio: {}
+ extensions/longcat:
+ devDependencies:
+ '@openclaw/plugin-sdk':
+ specifier: workspace:*
+ version: link:../../packages/plugin-sdk
+
extensions/lobster:
dependencies:
'@clawdbot/lobster':
diff --git a/scripts/generate-plugin-inventory-doc.mjs b/scripts/generate-plugin-inventory-doc.mjs
index 0e83ef0579c..7eb212f8d8b 100644
--- a/scripts/generate-plugin-inventory-doc.mjs
+++ b/scripts/generate-plugin-inventory-doc.mjs
@@ -131,6 +131,7 @@ function humanizeId(value) {
["litellm", "LiteLLM"],
["llm", "LLM"],
["lmstudio", "LM Studio"],
+ ["longcat", "LongCat"],
["mdns", "mDNS"],
["minimax", "MiniMax"],
["modelstudio", "Model Studio"],
diff --git a/scripts/lib/official-external-provider-catalog.json b/scripts/lib/official-external-provider-catalog.json
index db5dfacc879..50aa25ad6b8 100644
--- a/scripts/lib/official-external-provider-catalog.json
+++ b/scripts/lib/official-external-provider-catalog.json
@@ -589,6 +589,49 @@
}
}
},
+ {
+ "name": "@openclaw/longcat-provider",
+ "description": "OpenClaw LongCat provider plugin",
+ "source": "official",
+ "kind": "provider",
+ "openclaw": {
+ "plugin": {
+ "id": "longcat",
+ "label": "LongCat"
+ },
+ "providers": [
+ {
+ "id": "longcat",
+ "aliases": ["meituan-longcat"],
+ "name": "LongCat",
+ "docs": "/providers/longcat",
+ "categories": ["cloud", "llm"],
+ "envVars": ["LONGCAT_API_KEY"],
+ "authChoices": [
+ {
+ "method": "api-key",
+ "choiceId": "longcat-api-key",
+ "choiceLabel": "LongCat API key",
+ "groupId": "longcat",
+ "groupLabel": "LongCat",
+ "groupHint": "OpenAI-compatible LongCat API",
+ "optionKey": "longcatApiKey",
+ "cliFlag": "--longcat-api-key",
+ "cliOption": "--longcat-api-key ",
+ "cliDescription": "LongCat API key",
+ "onboardingScopes": ["text-inference"]
+ }
+ ]
+ }
+ ],
+ "install": {
+ "clawhubSpec": "clawhub:@openclaw/longcat-provider",
+ "npmSpec": "@openclaw/longcat-provider",
+ "defaultChoice": "npm",
+ "minHostVersion": ">=2026.6.8"
+ }
+ }
+ },
{
"name": "@openclaw/groq-provider",
"description": "OpenClaw Groq media-understanding provider.",
diff --git a/src/plugins/official-external-plugin-catalog.test.ts b/src/plugins/official-external-plugin-catalog.test.ts
index 3ffd7856823..00819f43de7 100644
--- a/src/plugins/official-external-plugin-catalog.test.ts
+++ b/src/plugins/official-external-plugin-catalog.test.ts
@@ -1632,6 +1632,7 @@ describe("official external plugin catalog", () => {
["deepinfra", "@openclaw/deepinfra-provider"],
["deepseek", "@openclaw/deepseek-provider"],
["groq", "@openclaw/groq-provider"],
+ ["longcat", "@openclaw/longcat-provider"],
["kilocode", "@openclaw/kilocode-provider"],
["kimi", "@openclaw/kimi-provider"],
["qianfan", "@openclaw/qianfan-provider"],
@@ -1752,6 +1753,19 @@ describe("official external plugin catalog", () => {
});
});
+ it("lists LongCat as an official external provider", () => {
+ const longcat = expectCatalogEntry("longcat");
+
+ expect(resolveOfficialExternalPluginId(longcat)).toBe("longcat");
+ expect(getOfficialExternalPluginCatalogEntry("meituan-longcat")).toBe(longcat);
+ expect(resolveOfficialExternalPluginInstall(longcat)).toEqual({
+ clawhubSpec: "clawhub:@openclaw/longcat-provider",
+ npmSpec: "@openclaw/longcat-provider",
+ defaultChoice: "npm",
+ minHostVersion: ">=2026.6.8",
+ });
+ });
+
it("resolves external provider aliases beyond the primary provider id", () => {
const qwen = expectCatalogEntry("qwen");
@@ -1814,6 +1828,7 @@ describe("official external plugin catalog", () => {
DEEPINFRA_API_KEY: "deepinfra-key",
DEEPSEEK_API_KEY: "deepseek-key",
GROQ_API_KEY: "groq-key",
+ LONGCAT_API_KEY: "longcat-key",
KILOCODE_API_KEY: "kilocode-key",
KIMICODE_API_KEY: "kimi-key",
KIMI_API_KEY: "moonshot-kimi-key",
@@ -1839,6 +1854,7 @@ describe("official external plugin catalog", () => {
"groq",
"kilocode",
"kimi",
+ "longcat",
"moonshot",
"qianfan",
"qwen",
@@ -1849,6 +1865,7 @@ describe("official external plugin catalog", () => {
"zai",
]);
expect(resolveOfficialExternalProviderPluginIdsForEnv({ GROQ_API_KEY: " " })).toEqual([]);
+ expect(resolveOfficialExternalProviderPluginIdsForEnv({ LONGCAT_API_KEY: " " })).toEqual([]);
});
it("keeps Tencent auth choices available through the cold-install auth catalog", () => {