重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。

同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。

Made-with: Cursor
This commit is contained in:
oliver 2026-04-26 08:34:33 +08:00
parent 4a23b715a2
commit dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions

View file

@ -0,0 +1,6 @@
export {
buildDeepSeekModelDefinition,
DEEPSEEK_BASE_URL,
DEEPSEEK_MODEL_CATALOG,
} from "./models.js";
export { buildDeepSeekProvider } from "./provider-catalog.js";

View file

@ -0,0 +1,88 @@
import { describe, expect, it } from "vitest";
import { resolveProviderPluginChoice } from "../../src/plugins/provider-auth-choice.runtime.js";
import { registerSingleProviderPlugin } from "../../test/helpers/plugins/plugin-registration.js";
import deepseekPlugin from "./index.js";
describe("deepseek provider plugin", () => {
it("registers DeepSeek with api-key auth wizard metadata", async () => {
const provider = await registerSingleProviderPlugin(deepseekPlugin);
const resolved = resolveProviderPluginChoice({
providers: [provider],
choice: "deepseek-api-key",
});
expect(provider.id).toBe("deepseek");
expect(provider.label).toBe("DeepSeek");
expect(provider.envVars).toEqual(["DEEPSEEK_API_KEY"]);
expect(provider.auth).toHaveLength(1);
expect(resolved).not.toBeNull();
expect(resolved?.provider.id).toBe("deepseek");
expect(resolved?.method.id).toBe("api-key");
});
it("builds the static DeepSeek model catalog", async () => {
const provider = await registerSingleProviderPlugin(deepseekPlugin);
expect(provider.catalog).toBeDefined();
const catalog = await provider.catalog!.run({
config: {},
env: {},
resolveProviderApiKey: () => ({ apiKey: "test-key" }),
resolveProviderAuth: () => ({
apiKey: "test-key",
mode: "api_key",
source: "env",
}),
} as never);
expect(catalog && "provider" in catalog).toBe(true);
if (!catalog || !("provider" in catalog)) {
throw new Error("expected single-provider catalog");
}
expect(catalog.provider.api).toBe("openai-completions");
expect(catalog.provider.baseUrl).toBe("https://api.deepseek.com");
expect(catalog.provider.models?.map((model) => model.id)).toEqual([
"deepseek-chat",
"deepseek-reasoner",
]);
expect(
catalog.provider.models?.find((model) => model.id === "deepseek-reasoner")?.reasoning,
).toBe(true);
});
it("publishes configured DeepSeek models through plugin-owned catalog augmentation", async () => {
const provider = await registerSingleProviderPlugin(deepseekPlugin);
expect(
provider.augmentModelCatalog?.({
config: {
models: {
providers: {
deepseek: {
models: [
{
id: "deepseek-chat",
name: "DeepSeek Chat",
input: ["text"],
reasoning: false,
contextWindow: 65536,
},
],
},
},
},
},
} as never),
).toEqual([
{
provider: "deepseek",
id: "deepseek-chat",
name: "DeepSeek Chat",
input: ["text"],
reasoning: false,
contextWindow: 65536,
},
]);
});
});

View file

@ -0,0 +1,46 @@
import { readConfiguredProviderCatalogEntries } from "openclaw/plugin-sdk/provider-catalog-shared";
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
import { applyDeepSeekConfig, DEEPSEEK_DEFAULT_MODEL_REF } from "./onboard.js";
import { buildDeepSeekProvider } from "./provider-catalog.js";
const PROVIDER_ID = "deepseek";
export default defineSingleProviderPluginEntry({
id: PROVIDER_ID,
name: "DeepSeek Provider",
description: "Bundled DeepSeek provider plugin",
provider: {
label: "DeepSeek",
docsPath: "/providers/deepseek",
auth: [
{
methodId: "api-key",
label: "DeepSeek API key",
hint: "API key",
optionKey: "deepseekApiKey",
flagName: "--deepseek-api-key",
envVar: "DEEPSEEK_API_KEY",
promptMessage: "Enter DeepSeek API key",
defaultModel: DEEPSEEK_DEFAULT_MODEL_REF,
applyConfig: (cfg) => applyDeepSeekConfig(cfg),
wizard: {
choiceId: "deepseek-api-key",
choiceLabel: "DeepSeek API key",
groupId: "deepseek",
groupLabel: "DeepSeek",
groupHint: "API key",
},
},
],
catalog: {
buildProvider: buildDeepSeekProvider,
},
augmentModelCatalog: ({ config }) =>
readConfiguredProviderCatalogEntries({
config,
providerId: PROVIDER_ID,
}),
matchesContextOverflowError: ({ errorMessage }) =>
/\bdeepseek\b.*(?:input.*too long|context.*exceed)/i.test(errorMessage),
},
});

View file

@ -0,0 +1,44 @@
import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared";
export const DEEPSEEK_BASE_URL = "https://api.deepseek.com";
// DeepSeek V3.2 API pricing (per 1M tokens)
// https://api-docs.deepseek.com/quick_start/pricing
const DEEPSEEK_V3_2_COST = {
input: 0.28,
output: 0.42,
cacheRead: 0.028,
cacheWrite: 0,
};
export const DEEPSEEK_MODEL_CATALOG: ModelDefinitionConfig[] = [
{
id: "deepseek-chat",
name: "DeepSeek Chat",
reasoning: false,
input: ["text"],
contextWindow: 131072,
maxTokens: 8192,
cost: DEEPSEEK_V3_2_COST,
compat: { supportsUsageInStreaming: true },
},
{
id: "deepseek-reasoner",
name: "DeepSeek Reasoner",
reasoning: true,
input: ["text"],
contextWindow: 131072,
maxTokens: 65536,
cost: DEEPSEEK_V3_2_COST,
compat: { supportsUsageInStreaming: true },
},
];
export function buildDeepSeekModelDefinition(
model: (typeof DEEPSEEK_MODEL_CATALOG)[number],
): ModelDefinitionConfig {
return {
...model,
api: "openai-completions",
};
}

View file

@ -0,0 +1,31 @@
import {
applyAgentDefaultModelPrimary,
applyProviderConfigWithModelCatalog,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
import { buildDeepSeekModelDefinition, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL_CATALOG } from "./api.js";
export const DEEPSEEK_DEFAULT_MODEL_REF = "deepseek/deepseek-chat";
export function applyDeepSeekProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
const models = { ...cfg.agents?.defaults?.models };
models[DEEPSEEK_DEFAULT_MODEL_REF] = {
...models[DEEPSEEK_DEFAULT_MODEL_REF],
alias: models[DEEPSEEK_DEFAULT_MODEL_REF]?.alias ?? "DeepSeek",
};
return applyProviderConfigWithModelCatalog(cfg, {
agentModels: models,
providerId: "deepseek",
api: "openai-completions",
baseUrl: DEEPSEEK_BASE_URL,
catalogModels: DEEPSEEK_MODEL_CATALOG.map(buildDeepSeekModelDefinition),
});
}
export function applyDeepSeekConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyAgentDefaultModelPrimary(
applyDeepSeekProviderConfig(cfg),
DEEPSEEK_DEFAULT_MODEL_REF,
);
}

View file

@ -0,0 +1,28 @@
{
"id": "deepseek",
"enabledByDefault": true,
"providers": ["deepseek"],
"providerAuthEnvVars": {
"deepseek": ["DEEPSEEK_API_KEY"]
},
"providerAuthChoices": [
{
"provider": "deepseek",
"method": "api-key",
"choiceId": "deepseek-api-key",
"choiceLabel": "DeepSeek API key",
"groupId": "deepseek",
"groupLabel": "DeepSeek",
"groupHint": "API key",
"optionKey": "deepseekApiKey",
"cliFlag": "--deepseek-api-key",
"cliOption": "--deepseek-api-key <key>",
"cliDescription": "DeepSeek API key"
}
],
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {}
}
}

View file

@ -0,0 +1,15 @@
{
"name": "@openclaw/deepseek-provider",
"version": "2026.4.20",
"private": true,
"description": "OpenClaw DeepSeek provider plugin",
"type": "module",
"devDependencies": {
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"extensions": [
"./index.ts"
]
}
}

View file

@ -0,0 +1,14 @@
import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared";
import {
buildDeepSeekModelDefinition,
DEEPSEEK_BASE_URL,
DEEPSEEK_MODEL_CATALOG,
} from "./models.js";
export function buildDeepSeekProvider(): ModelProviderConfig {
return {
baseUrl: DEEPSEEK_BASE_URL,
api: "openai-completions",
models: DEEPSEEK_MODEL_CATALOG.map(buildDeepSeekModelDefinition),
};
}

View file

@ -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"
]
}