Major changes: - Add HandList.tsx component for left sidebar - Add HandTaskPanel.tsx for middle content area - Restructure Sidebar tabs: 分身/HANDS/Workflow - Remove Hands tab from RightPanel - Localize all UI text to Chinese - Archive legacy OpenClaw documentation - Add Hands integration lessons document - Update feature checklist with new components UI improvements: - Left sidebar now shows Hands list with status icons - Middle area shows selected Hand's tasks and results - Consistent styling with Tailwind CSS - Chinese status labels and buttons Documentation: - Create docs/archive/openclaw-legacy/ for old docs - Add docs/knowledge-base/hands-integration-lessons.md - Update docs/knowledge-base/feature-checklist.md - Update docs/knowledge-base/README.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
352 lines
8.8 KiB
TypeScript
352 lines
8.8 KiB
TypeScript
/**
|
|
* ZCLAW Chinese Models Plugin
|
|
*
|
|
* Registers Chinese AI model providers for OpenClaw Gateway:
|
|
* - Zhipu GLM (智谱)
|
|
* - Qwen (通义千问)
|
|
* - Kimi (月之暗面)
|
|
* - MiniMax
|
|
* - DeepSeek
|
|
* - Baidu ERNIE (文心一言)
|
|
* - iFlytek Spark (讯飞星火)
|
|
*
|
|
* All providers use OpenAI-compatible API format.
|
|
*/
|
|
|
|
interface PluginAPI {
|
|
config: Record<string, any>;
|
|
registerProvider(provider: ProviderDefinition): void;
|
|
registerHook(event: string, handler: (...args: any[]) => any, meta?: Record<string, any>): void;
|
|
}
|
|
|
|
interface ProviderDefinition {
|
|
id: string;
|
|
name: string;
|
|
baseUrl: string;
|
|
apiKeyEnvVar?: string;
|
|
models: ProviderModel[];
|
|
headers?: (apiKey: string) => Record<string, string>;
|
|
}
|
|
|
|
interface ProviderModel {
|
|
id: string;
|
|
alias?: string;
|
|
contextWindow?: number;
|
|
maxOutputTokens?: number;
|
|
supportsVision?: boolean;
|
|
supportsStreaming?: boolean;
|
|
}
|
|
|
|
// 智谱 GLM Provider
|
|
const zhipuProvider: ProviderDefinition = {
|
|
id: 'zhipu',
|
|
name: 'Zhipu AI (智谱)',
|
|
baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
|
|
apiKeyEnvVar: 'ZHIPU_API_KEY',
|
|
models: [
|
|
{
|
|
id: 'glm-4-plus',
|
|
alias: 'GLM-4-Plus',
|
|
contextWindow: 128000,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'glm-4-flash',
|
|
alias: 'GLM-4-Flash',
|
|
contextWindow: 128000,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'glm-4v-plus',
|
|
alias: 'GLM-4V-Plus (视觉)',
|
|
contextWindow: 128000,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: true,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'glm-z1-airx',
|
|
alias: 'GLM-Z1-AirX (推理)',
|
|
contextWindow: 128000,
|
|
maxOutputTokens: 16384,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
],
|
|
headers: (apiKey: string) => ({
|
|
'Authorization': `Bearer ${apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
}),
|
|
};
|
|
|
|
// 通义千问 Provider (OpenAI-compatible via DashScope)
|
|
const qwenProvider: ProviderDefinition = {
|
|
id: 'qwen',
|
|
name: 'Qwen (通义千问)',
|
|
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
apiKeyEnvVar: 'QWEN_API_KEY',
|
|
models: [
|
|
{
|
|
id: 'qwen-max',
|
|
alias: 'Qwen-Max',
|
|
contextWindow: 32768,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'qwen-plus',
|
|
alias: 'Qwen-Plus',
|
|
contextWindow: 128000,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'qwen-turbo',
|
|
alias: 'Qwen-Turbo',
|
|
contextWindow: 128000,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'qwen-vl-max',
|
|
alias: 'Qwen-VL-Max (视觉)',
|
|
contextWindow: 32768,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: true,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'qwen-long',
|
|
alias: 'Qwen-Long (长上下文)',
|
|
contextWindow: 1000000,
|
|
maxOutputTokens: 10000,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
],
|
|
headers: (apiKey: string) => ({
|
|
'Authorization': `Bearer ${apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
}),
|
|
};
|
|
|
|
// Kimi (月之暗面) Provider
|
|
const kimiProvider: ProviderDefinition = {
|
|
id: 'kimi',
|
|
name: 'Kimi (月之暗面)',
|
|
baseUrl: 'https://api.moonshot.cn/v1',
|
|
apiKeyEnvVar: 'KIMI_API_KEY',
|
|
models: [
|
|
{
|
|
id: 'moonshot-v1-8k',
|
|
alias: 'Kimi (8K)',
|
|
contextWindow: 8192,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'moonshot-v1-32k',
|
|
alias: 'Kimi (32K)',
|
|
contextWindow: 32768,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'moonshot-v1-128k',
|
|
alias: 'Kimi (128K)',
|
|
contextWindow: 131072,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
],
|
|
headers: (apiKey: string) => ({
|
|
'Authorization': `Bearer ${apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
}),
|
|
};
|
|
|
|
// MiniMax Provider
|
|
const minimaxProvider: ProviderDefinition = {
|
|
id: 'minimax',
|
|
name: 'MiniMax',
|
|
baseUrl: 'https://api.minimax.chat/v1',
|
|
apiKeyEnvVar: 'MINIMAX_API_KEY',
|
|
models: [
|
|
{
|
|
id: 'abab6.5s-chat',
|
|
alias: 'MiniMax-6.5s',
|
|
contextWindow: 245000,
|
|
maxOutputTokens: 16384,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'abab6.5g-chat',
|
|
alias: 'MiniMax-6.5g',
|
|
contextWindow: 128000,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'abab5.5-chat',
|
|
alias: 'MiniMax-5.5',
|
|
contextWindow: 16384,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
],
|
|
headers: (apiKey: string) => ({
|
|
'Authorization': `Bearer ${apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
}),
|
|
};
|
|
|
|
// DeepSeek Provider
|
|
const deepseekProvider: ProviderDefinition = {
|
|
id: 'deepseek',
|
|
name: 'DeepSeek',
|
|
baseUrl: 'https://api.deepseek.com/v1',
|
|
apiKeyEnvVar: 'DEEPSEEK_API_KEY',
|
|
models: [
|
|
{
|
|
id: 'deepseek-chat',
|
|
alias: 'DeepSeek Chat',
|
|
contextWindow: 64000,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'deepseek-reasoner',
|
|
alias: 'DeepSeek Reasoner (R1)',
|
|
contextWindow: 64000,
|
|
maxOutputTokens: 8192,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
],
|
|
headers: (apiKey: string) => ({
|
|
'Authorization': `Bearer ${apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
}),
|
|
};
|
|
|
|
// 百度文心一言 Provider (OpenAI-compatible endpoint)
|
|
const baiduProvider: ProviderDefinition = {
|
|
id: 'baidu',
|
|
name: 'Baidu ERNIE (文心一言)',
|
|
baseUrl: 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat',
|
|
apiKeyEnvVar: 'BAIDU_API_KEY',
|
|
models: [
|
|
{
|
|
id: 'ernie-4.0-8k',
|
|
alias: 'ERNIE-4.0 (8K)',
|
|
contextWindow: 8192,
|
|
maxOutputTokens: 2048,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'ernie-3.5-8k',
|
|
alias: 'ERNIE-3.5 (8K)',
|
|
contextWindow: 8192,
|
|
maxOutputTokens: 2048,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
],
|
|
headers: (apiKey: string) => ({
|
|
'Authorization': `Bearer ${apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
}),
|
|
};
|
|
|
|
// 讯飞星火 Provider (OpenAI-compatible endpoint)
|
|
const sparkProvider: ProviderDefinition = {
|
|
id: 'spark',
|
|
name: 'iFlytek Spark (讯飞星火)',
|
|
baseUrl: 'https://spark-api-open.xf-yun.com/v1',
|
|
apiKeyEnvVar: 'SPARK_API_KEY',
|
|
models: [
|
|
{
|
|
id: 'generalv3.5',
|
|
alias: '星火 3.5',
|
|
contextWindow: 8192,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
{
|
|
id: 'generalv4.0',
|
|
alias: '星火 4.0',
|
|
contextWindow: 8192,
|
|
maxOutputTokens: 4096,
|
|
supportsVision: false,
|
|
supportsStreaming: true,
|
|
},
|
|
],
|
|
headers: (apiKey: string) => ({
|
|
'Authorization': `Bearer ${apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
}),
|
|
};
|
|
|
|
/**
|
|
* Plugin entry point - registers all Chinese model providers
|
|
*/
|
|
export default function register(api: PluginAPI) {
|
|
const pluginConfig = api.config?.plugins?.entries?.['zclaw-chinese-models']?.config ?? {};
|
|
|
|
// Register Zhipu GLM
|
|
const zhipu = { ...zhipuProvider };
|
|
if (pluginConfig.zhipuBaseUrl) zhipu.baseUrl = pluginConfig.zhipuBaseUrl;
|
|
api.registerProvider(zhipu);
|
|
|
|
// Register Qwen
|
|
const qwen = { ...qwenProvider };
|
|
if (pluginConfig.qwenBaseUrl) qwen.baseUrl = pluginConfig.qwenBaseUrl;
|
|
api.registerProvider(qwen);
|
|
|
|
// Register Kimi
|
|
const kimi = { ...kimiProvider };
|
|
if (pluginConfig.kimiBaseUrl) kimi.baseUrl = pluginConfig.kimiBaseUrl;
|
|
api.registerProvider(kimi);
|
|
|
|
// Register MiniMax
|
|
const minimax = { ...minimaxProvider };
|
|
if (pluginConfig.minimaxBaseUrl) minimax.baseUrl = pluginConfig.minimaxBaseUrl;
|
|
api.registerProvider(minimax);
|
|
|
|
// Register DeepSeek
|
|
const deepseek = { ...deepseekProvider };
|
|
if (pluginConfig.deepseekBaseUrl) deepseek.baseUrl = pluginConfig.deepseekBaseUrl;
|
|
api.registerProvider(deepseek);
|
|
|
|
// Register Baidu ERNIE
|
|
const baidu = { ...baiduProvider };
|
|
if (pluginConfig.baiduBaseUrl) baidu.baseUrl = pluginConfig.baiduBaseUrl;
|
|
api.registerProvider(baidu);
|
|
|
|
// Register iFlytek Spark
|
|
const spark = { ...sparkProvider };
|
|
if (pluginConfig.sparkBaseUrl) spark.baseUrl = pluginConfig.sparkBaseUrl;
|
|
api.registerProvider(spark);
|
|
|
|
// Log registration
|
|
api.registerHook('gateway:startup', async () => {
|
|
console.log('[ZCLAW] Chinese model providers registered: zhipu, qwen, kimi, minimax, deepseek, baidu, spark');
|
|
}, { name: 'zclaw-chinese-models.startup', description: 'Log provider registration on startup' });
|
|
}
|