flowmind 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README_CN.md +248 -0
- package/bin/flowmind.js +184 -2
- package/config/ai-config.example.json +64 -0
- package/config/claude-mcp-config.example.json +12 -0
- package/core/ai/base-model.js +70 -0
- package/core/ai/index.js +29 -0
- package/core/ai/model-manager.js +320 -0
- package/core/ai/prompts/extraction.js +38 -0
- package/core/ai/prompts/index.js +11 -0
- package/core/ai/prompts/intent.js +43 -0
- package/core/ai/prompts/learning.js +46 -0
- package/core/ai/prompts/selection.js +38 -0
- package/core/ai/prompts/summary.js +35 -0
- package/core/ai/providers/anthropic.js +93 -0
- package/core/ai/providers/deepseek.js +80 -0
- package/core/ai/providers/ernie.js +111 -0
- package/core/ai/providers/glm.js +80 -0
- package/core/ai/providers/mimo.js +80 -0
- package/core/ai/providers/ollama.js +147 -0
- package/core/ai/providers/openai.js +82 -0
- package/core/ai/providers/qwen.js +80 -0
- package/core/index.js +74 -11
- package/core/skill-loader.js +22 -8
- package/mcp/server.js +313 -0
- package/package.json +9 -3
package/README_CN.md
CHANGED
|
@@ -94,7 +94,13 @@ npm install -g flowmind
|
|
|
94
94
|
### 初始化
|
|
95
95
|
|
|
96
96
|
```bash
|
|
97
|
+
# 基础初始化
|
|
97
98
|
flowmind init
|
|
99
|
+
|
|
100
|
+
# 带 AI 模型初始化 (推荐)
|
|
101
|
+
flowmind init --ai openai
|
|
102
|
+
flowmind init --ai anthropic
|
|
103
|
+
flowmind init --ai ollama
|
|
98
104
|
```
|
|
99
105
|
|
|
100
106
|
> 一次配置,永久生效。配置资源连接、学习偏好、输出格式,无需每次重复设置。
|
|
@@ -113,6 +119,248 @@ FlowMind: [自动使用顺序列表格式] ✓
|
|
|
113
119
|
|
|
114
120
|
---
|
|
115
121
|
|
|
122
|
+
## 📖 使用方式
|
|
123
|
+
|
|
124
|
+
FlowMind 支持 4 种使用方式,满足不同场景需求:
|
|
125
|
+
|
|
126
|
+
### 方式1: CLI 独立使用
|
|
127
|
+
|
|
128
|
+
最简单的使用方式,无需 AI 模型,直接通过命令行调用。
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# 单次执行
|
|
132
|
+
flowmind "查询 traceId abc123 的日志"
|
|
133
|
+
flowmind "审查代码质量"
|
|
134
|
+
flowmind "验证订单数据"
|
|
135
|
+
|
|
136
|
+
# 交互模式
|
|
137
|
+
flowmind
|
|
138
|
+
|
|
139
|
+
# 指定技能执行
|
|
140
|
+
flowmind process --skill log-audit "查询最近1小时的错误日志"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**特点:**
|
|
144
|
+
- ✅ 无需 AI 模型
|
|
145
|
+
- ✅ 基于规则引擎匹配
|
|
146
|
+
- ✅ 支持学习和记忆
|
|
147
|
+
- ✅ 离线可用
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### 方式2: AI 模型直接接入
|
|
152
|
+
|
|
153
|
+
FlowMind 内置 AI 模型接入层,可直接调用 OpenAI、Anthropic、Ollama 等模型。
|
|
154
|
+
|
|
155
|
+
#### 配置 AI 模型
|
|
156
|
+
|
|
157
|
+
**方式 A:通过 CLI 初始化(推荐)**
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# 配置 OpenAI
|
|
161
|
+
flowmind init --ai openai
|
|
162
|
+
# 会提示输入 API Key
|
|
163
|
+
|
|
164
|
+
# 配置 Anthropic
|
|
165
|
+
flowmind init --ai anthropic
|
|
166
|
+
|
|
167
|
+
# 配置 Ollama (本地模型)
|
|
168
|
+
flowmind init --ai ollama
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**方式 B:手动配置**
|
|
172
|
+
|
|
173
|
+
创建 `~/.flowmind/ai-config.json`:
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"ai": {
|
|
178
|
+
"enabled": true,
|
|
179
|
+
"defaultProvider": "openai",
|
|
180
|
+
"fallbackToRules": true,
|
|
181
|
+
"providers": {
|
|
182
|
+
"openai": {
|
|
183
|
+
"apiKey": "sk-your-api-key",
|
|
184
|
+
"model": "gpt-4",
|
|
185
|
+
"temperature": 0.3
|
|
186
|
+
},
|
|
187
|
+
"anthropic": {
|
|
188
|
+
"apiKey": "sk-ant-your-api-key",
|
|
189
|
+
"model": "claude-3-sonnet-20240229"
|
|
190
|
+
},
|
|
191
|
+
"ollama": {
|
|
192
|
+
"baseUrl": "http://localhost:11434",
|
|
193
|
+
"model": "llama2"
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"features": {
|
|
197
|
+
"intentUnderstanding": true,
|
|
198
|
+
"parameterExtraction": true,
|
|
199
|
+
"skillSelection": true,
|
|
200
|
+
"resultSummary": true,
|
|
201
|
+
"learningFeedback": true
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**方式 C:环境变量**
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
export OPENAI_API_KEY=sk-your-api-key
|
|
211
|
+
export ANTHROPIC_API_KEY=sk-ant-your-api-key
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### 测试 AI 连接
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# 测试默认 Provider
|
|
218
|
+
flowmind ai --test
|
|
219
|
+
|
|
220
|
+
# 测试指定 Provider
|
|
221
|
+
flowmind ai --test openai
|
|
222
|
+
flowmind ai --test anthropic
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
#### 使用 AI 增强功能
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# AI 会理解意图、提取参数、选择技能、生成摘要
|
|
229
|
+
flowmind "帮我查一下最近1小时用户服务的错误日志"
|
|
230
|
+
|
|
231
|
+
# AI 会分析复杂的多步骤任务
|
|
232
|
+
flowmind "排查线上问题:用户下单失败,需要查看日志、检查数据库、分析原因"
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**特点:**
|
|
236
|
+
- ✅ 自然语言理解
|
|
237
|
+
- ✅ 智能参数提取
|
|
238
|
+
- ✅ 结果摘要生成
|
|
239
|
+
- ✅ 降级到规则引擎
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
### 方式3: Claude Code 集成(MCP Server)
|
|
244
|
+
|
|
245
|
+
让 Claude Code 直接调用 FlowMind 的内部流程。
|
|
246
|
+
|
|
247
|
+
#### 步骤 1:安装 FlowMind
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
npm install -g flowmind
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### 步骤 2:配置 MCP Server
|
|
254
|
+
|
|
255
|
+
在项目根目录创建 `.claude/settings.local.json`:
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"mcpServers": {
|
|
260
|
+
"flowmind": {
|
|
261
|
+
"command": "flowmind-mcp",
|
|
262
|
+
"args": [],
|
|
263
|
+
"env": {
|
|
264
|
+
"OPENAI_API_KEY": "${OPENAI_API_KEY}"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
或者使用完整路径:
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"mcpServers": {
|
|
276
|
+
"flowmind": {
|
|
277
|
+
"command": "node",
|
|
278
|
+
"args": ["/path/to/flowmind/mcp/server.js"]
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### 步骤 3:在 Claude Code 中使用
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
你:帮我查询最近1小时的错误日志
|
|
288
|
+
|
|
289
|
+
Claude:我来调用 FlowMind 帮你查询...
|
|
290
|
+
[调用 flowmind_process 工具]
|
|
291
|
+
|
|
292
|
+
你:审查一下这个项目的代码质量
|
|
293
|
+
|
|
294
|
+
Claude:我来使用 FlowMind 的代码审查技能...
|
|
295
|
+
[调用 flowmind_skill_code-review 工具]
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
#### 可用的 MCP 工具
|
|
299
|
+
|
|
300
|
+
| 工具名称 | 描述 |
|
|
301
|
+
|---------|------|
|
|
302
|
+
| `flowmind_process` | 处理请求的主入口 |
|
|
303
|
+
| `flowmind_list_skills` | 列出所有可用技能 |
|
|
304
|
+
| `flowmind_get_skill` | 获取技能详情 |
|
|
305
|
+
| `flowmind_ai_status` | 查看 AI 状态 |
|
|
306
|
+
| `flowmind_learning_stats` | 查看学习统计 |
|
|
307
|
+
| `flowmind_skill_<name>` | 执行特定技能 |
|
|
308
|
+
|
|
309
|
+
**特点:**
|
|
310
|
+
- ✅ Claude Code 直接调用
|
|
311
|
+
- ✅ 无需额外配置 MCP Server
|
|
312
|
+
- ✅ 保留学习和记忆功能
|
|
313
|
+
- ✅ 支持所有 FlowMind 技能
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
### 方式4: Codex 集成(JSON 输出)
|
|
318
|
+
|
|
319
|
+
通过 JSON 输出与 Codex 集成。
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# 获取技能列表 (JSON 格式)
|
|
323
|
+
flowmind skills --json
|
|
324
|
+
|
|
325
|
+
# 获取技能详情
|
|
326
|
+
flowmind skill log-audit --json
|
|
327
|
+
|
|
328
|
+
# 执行并输出 JSON
|
|
329
|
+
flowmind process --json "查询日志"
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Codex 脚本示例:**
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
import subprocess
|
|
336
|
+
import json
|
|
337
|
+
|
|
338
|
+
def flowmind_query(query):
|
|
339
|
+
result = subprocess.run(
|
|
340
|
+
['flowmind', 'process', '--json', query],
|
|
341
|
+
capture_output=True,
|
|
342
|
+
text=True
|
|
343
|
+
)
|
|
344
|
+
return json.loads(result.stdout)
|
|
345
|
+
|
|
346
|
+
# 使用
|
|
347
|
+
result = flowmind_query("查询 traceId abc123 的日志")
|
|
348
|
+
print(result)
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
### 使用方式对比
|
|
354
|
+
|
|
355
|
+
| 方式 | 适用场景 | 需要 AI | 需要 MCP | 特点 |
|
|
356
|
+
|------|---------|---------|----------|------|
|
|
357
|
+
| CLI 独立使用 | 快速执行、脚本集成 | ❌ | ❌ | 简单直接 |
|
|
358
|
+
| AI 模型接入 | 智能理解、复杂任务 | ✅ | ❌ | 自然语言 |
|
|
359
|
+
| Claude Code | 智能对话、多步骤 | ✅ | ✅ | 深度集成 |
|
|
360
|
+
| Codex 集成 | 自动化、CI/CD | ❌ | ❌ | 程序化调用 |
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
116
364
|
## 🧠 工作原理
|
|
117
365
|
|
|
118
366
|
### 1. 多源代码定位
|
package/bin/flowmind.js
CHANGED
|
@@ -52,7 +52,8 @@ program
|
|
|
52
52
|
program
|
|
53
53
|
.command('init')
|
|
54
54
|
.description('Initialize FlowMind in current directory')
|
|
55
|
-
.
|
|
55
|
+
.option('--ai <provider>', 'Initialize with AI provider (openai/anthropic/glm/mimo/qwen/ernie/deepseek/ollama)')
|
|
56
|
+
.action(async (options) => {
|
|
56
57
|
showBanner();
|
|
57
58
|
|
|
58
59
|
const spinner = ora('Initializing FlowMind...').start();
|
|
@@ -68,7 +69,7 @@ program
|
|
|
68
69
|
const configPath = path.join(configDir, 'config.json');
|
|
69
70
|
if (!await fs.pathExists(configPath)) {
|
|
70
71
|
const defaultConfig = {
|
|
71
|
-
version: '1.
|
|
72
|
+
version: '1.1.0',
|
|
72
73
|
learning: {
|
|
73
74
|
enabled: true,
|
|
74
75
|
autoApply: true,
|
|
@@ -89,17 +90,89 @@ program
|
|
|
89
90
|
await fs.writeJson(configPath, defaultConfig, { spaces: 2 });
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
// Initialize AI if requested
|
|
94
|
+
if (options.ai) {
|
|
95
|
+
spinner.text = 'Configuring AI provider...';
|
|
96
|
+
const aiConfigPath = path.join(configDir, 'ai-config.json');
|
|
97
|
+
|
|
98
|
+
let aiConfig = {};
|
|
99
|
+
if (await fs.pathExists(aiConfigPath)) {
|
|
100
|
+
aiConfig = await fs.readJson(aiConfigPath);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Set default provider
|
|
104
|
+
aiConfig.ai = aiConfig.ai || {};
|
|
105
|
+
aiConfig.ai.defaultProvider = options.ai;
|
|
106
|
+
aiConfig.ai.enabled = true;
|
|
107
|
+
|
|
108
|
+
// Prompt for API key based on provider
|
|
109
|
+
const apiKeyProviders = {
|
|
110
|
+
'openai': { key: 'apiKey', message: 'Enter OpenAI API key:', env: 'OPENAI_API_KEY' },
|
|
111
|
+
'anthropic': { key: 'apiKey', message: 'Enter Anthropic API key:', env: 'ANTHROPIC_API_KEY' },
|
|
112
|
+
'glm': { key: 'apiKey', message: 'Enter Zhipu AI API key:', env: 'ZHIPU_API_KEY' },
|
|
113
|
+
'mimo': { key: 'apiKey', message: 'Enter MiMo API key:', env: 'MIMO_API_KEY' },
|
|
114
|
+
'qwen': { key: 'apiKey', message: 'Enter DashScope API key:', env: 'DASHSCOPE_API_KEY' },
|
|
115
|
+
'ernie': { key: 'apiKey', message: 'Enter Baidu API key:', env: 'BAIDU_API_KEY' },
|
|
116
|
+
'deepseek': { key: 'apiKey', message: 'Enter DeepSeek API key:', env: 'DEEPSEEK_API_KEY' }
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const providerConfig = apiKeyProviders[options.ai];
|
|
120
|
+
if (providerConfig) {
|
|
121
|
+
const { apiKey } = await inquirer.prompt([
|
|
122
|
+
{
|
|
123
|
+
type: 'password',
|
|
124
|
+
name: 'apiKey',
|
|
125
|
+
message: providerConfig.message,
|
|
126
|
+
mask: '*'
|
|
127
|
+
}
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
aiConfig.ai.providers = aiConfig.ai.providers || {};
|
|
131
|
+
aiConfig.ai.providers[options.ai] = {
|
|
132
|
+
...aiConfig.ai.providers[options.ai],
|
|
133
|
+
apiKey: apiKey,
|
|
134
|
+
enabled: true
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// For ERNIE, also prompt for secret key
|
|
138
|
+
if (options.ai === 'ernie') {
|
|
139
|
+
const { secretKey } = await inquirer.prompt([
|
|
140
|
+
{
|
|
141
|
+
type: 'password',
|
|
142
|
+
name: 'secretKey',
|
|
143
|
+
message: 'Enter Baidu Secret key:',
|
|
144
|
+
mask: '*'
|
|
145
|
+
}
|
|
146
|
+
]);
|
|
147
|
+
aiConfig.ai.providers[options.ai].secretKey = secretKey;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
await fs.writeJson(aiConfigPath, aiConfig, { spaces: 2 });
|
|
152
|
+
console.log(chalk.green(`\n✓ AI provider configured: ${options.ai}`));
|
|
153
|
+
}
|
|
154
|
+
|
|
92
155
|
spinner.succeed('FlowMind initialized successfully!');
|
|
93
156
|
|
|
94
157
|
console.log(chalk.green('\n✓ Configuration created at:'), configDir);
|
|
95
158
|
console.log(chalk.green('✓ Learning system ready'));
|
|
96
159
|
console.log(chalk.green('✓ Scene mapping ready'));
|
|
97
160
|
|
|
161
|
+
if (options.ai) {
|
|
162
|
+
console.log(chalk.green(`✓ AI provider configured: ${options.ai}`));
|
|
163
|
+
}
|
|
164
|
+
|
|
98
165
|
console.log(chalk.cyan('\nNext steps:'));
|
|
99
166
|
console.log(' 1. Run', chalk.yellow('flowmind'), 'to start interactive mode');
|
|
100
167
|
console.log(' 2. Or use', chalk.yellow('flowmind "your request"'), 'for single commands');
|
|
101
168
|
console.log(' 3. FlowMind will learn from your corrections automatically');
|
|
102
169
|
|
|
170
|
+
if (!options.ai) {
|
|
171
|
+
console.log(chalk.cyan('\nTo enable AI features:'));
|
|
172
|
+
console.log(' Run', chalk.yellow('flowmind init --ai openai'), 'or', chalk.yellow('flowmind init --ai anthropic'));
|
|
173
|
+
console.log(' Or configure manually:', chalk.yellow('~/.flowmind/ai-config.json'));
|
|
174
|
+
}
|
|
175
|
+
|
|
103
176
|
} catch (error) {
|
|
104
177
|
spinner.fail('Failed to initialize FlowMind');
|
|
105
178
|
console.error(chalk.red(error.message));
|
|
@@ -404,6 +477,82 @@ program
|
|
|
404
477
|
}
|
|
405
478
|
});
|
|
406
479
|
|
|
480
|
+
// AI command
|
|
481
|
+
program
|
|
482
|
+
.command('ai')
|
|
483
|
+
.description('Manage AI model configuration')
|
|
484
|
+
.option('-s, --status', 'Show AI model status')
|
|
485
|
+
.option('-l, --list', 'List available providers')
|
|
486
|
+
.option('-c, --config', 'Show AI configuration')
|
|
487
|
+
.option('-t, --test [provider]', 'Test AI provider connection')
|
|
488
|
+
.option('-j, --json', 'Output as JSON')
|
|
489
|
+
.action(async (options) => {
|
|
490
|
+
try {
|
|
491
|
+
const fm = await initFlowMind();
|
|
492
|
+
|
|
493
|
+
if (options.status) {
|
|
494
|
+
const status = fm.getAIStatus();
|
|
495
|
+
if (options.json) {
|
|
496
|
+
console.log(JSON.stringify(status, null, 2));
|
|
497
|
+
} else {
|
|
498
|
+
displayAIStatus(status);
|
|
499
|
+
}
|
|
500
|
+
} else if (options.list) {
|
|
501
|
+
const status = fm.getAIStatus();
|
|
502
|
+
const providers = Object.entries(status.providers).map(([name, info]) => ({
|
|
503
|
+
name,
|
|
504
|
+
...info
|
|
505
|
+
}));
|
|
506
|
+
if (options.json) {
|
|
507
|
+
console.log(JSON.stringify({ providers }, null, 2));
|
|
508
|
+
} else {
|
|
509
|
+
console.log(chalk.cyan('\nAI Providers:'));
|
|
510
|
+
for (const provider of providers) {
|
|
511
|
+
const status = provider.initialized ? chalk.green('✓') : chalk.red('✗');
|
|
512
|
+
console.log(` ${status} ${provider.name}`);
|
|
513
|
+
if (provider.info?.model) {
|
|
514
|
+
console.log(` Model: ${provider.info.model}`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
} else if (options.config) {
|
|
519
|
+
const config = fm.config.get('ai', {});
|
|
520
|
+
if (options.json) {
|
|
521
|
+
console.log(JSON.stringify({ ai: config }, null, 2));
|
|
522
|
+
} else {
|
|
523
|
+
console.log(chalk.cyan('\nAI Configuration:'));
|
|
524
|
+
console.log(JSON.stringify(config, null, 2));
|
|
525
|
+
}
|
|
526
|
+
} else if (options.test !== undefined) {
|
|
527
|
+
const providerName = options.test || fm.ai.defaultProvider;
|
|
528
|
+
const provider = fm.ai.getProvider(providerName);
|
|
529
|
+
if (!provider) {
|
|
530
|
+
console.error(chalk.red(`Provider not found: ${providerName}`));
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
console.log(chalk.cyan(`\nTesting ${providerName}...`));
|
|
534
|
+
try {
|
|
535
|
+
const result = await provider.complete('Hello, this is a test.', { maxTokens: 50 });
|
|
536
|
+
console.log(chalk.green('✓ Connection successful'));
|
|
537
|
+
console.log(chalk.white('Response:'), result.substring(0, 100) + '...');
|
|
538
|
+
} catch (error) {
|
|
539
|
+
console.log(chalk.red('✗ Connection failed'));
|
|
540
|
+
console.error(chalk.red(error.message));
|
|
541
|
+
}
|
|
542
|
+
} else {
|
|
543
|
+
// Default to status
|
|
544
|
+
const status = fm.getAIStatus();
|
|
545
|
+
if (options.json) {
|
|
546
|
+
console.log(JSON.stringify(status, null, 2));
|
|
547
|
+
} else {
|
|
548
|
+
displayAIStatus(status);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
} catch (error) {
|
|
552
|
+
console.error(chalk.red('Error:'), error.message);
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
|
|
407
556
|
// Interactive mode
|
|
408
557
|
async function runInteractiveMode(fm) {
|
|
409
558
|
showBanner();
|
|
@@ -802,6 +951,39 @@ function displayResourceConfig(config) {
|
|
|
802
951
|
console.log(chalk.cyan('└─────────────────────────────────────────────────────┘'));
|
|
803
952
|
}
|
|
804
953
|
|
|
954
|
+
function displayAIStatus(status) {
|
|
955
|
+
console.log(chalk.cyan('\n┌─────────────────────────────────────────────────────┐'));
|
|
956
|
+
console.log(chalk.cyan('│ AI Model Status │'));
|
|
957
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
958
|
+
|
|
959
|
+
const initialized = status.initialized ? chalk.green('✓') : chalk.red('✗');
|
|
960
|
+
console.log(chalk.cyan(`│ Initialized: ${initialized}`));
|
|
961
|
+
console.log(chalk.cyan(`│ Default Provider: ${status.defaultProvider || 'None'}`));
|
|
962
|
+
|
|
963
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
964
|
+
console.log(chalk.cyan('│ Features:'));
|
|
965
|
+
|
|
966
|
+
const features = status.features || {};
|
|
967
|
+
for (const [feature, enabled] of Object.entries(features)) {
|
|
968
|
+
const statusIcon = enabled ? chalk.green('✓') : chalk.red('✗');
|
|
969
|
+
console.log(chalk.cyan(`│ ${statusIcon} ${feature}`));
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
973
|
+
console.log(chalk.cyan('│ Providers:'));
|
|
974
|
+
|
|
975
|
+
const providers = status.providers || {};
|
|
976
|
+
for (const [name, info] of Object.entries(providers)) {
|
|
977
|
+
const statusIcon = info.initialized ? chalk.green('✓') : chalk.red('✗');
|
|
978
|
+
console.log(chalk.cyan(`│ ${statusIcon} ${name}`));
|
|
979
|
+
if (info.info?.model) {
|
|
980
|
+
console.log(chalk.cyan(`│ Model: ${info.info.model}`));
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
console.log(chalk.cyan('└─────────────────────────────────────────────────────┘'));
|
|
985
|
+
}
|
|
986
|
+
|
|
805
987
|
function formatFileSize(bytes) {
|
|
806
988
|
if (bytes === 0) return '0 B';
|
|
807
989
|
const k = 1024;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ai": {
|
|
3
|
+
"enabled": true,
|
|
4
|
+
"defaultProvider": "glm",
|
|
5
|
+
"fallbackToRules": true,
|
|
6
|
+
"providers": {
|
|
7
|
+
"openai": {
|
|
8
|
+
"apiKey": "${OPENAI_API_KEY}",
|
|
9
|
+
"model": "gpt-4",
|
|
10
|
+
"temperature": 0.3,
|
|
11
|
+
"maxTokens": 2000
|
|
12
|
+
},
|
|
13
|
+
"anthropic": {
|
|
14
|
+
"apiKey": "${ANTHROPIC_API_KEY}",
|
|
15
|
+
"model": "claude-3-sonnet-20240229",
|
|
16
|
+
"maxTokens": 2000,
|
|
17
|
+
"temperature": 0.3
|
|
18
|
+
},
|
|
19
|
+
"glm": {
|
|
20
|
+
"apiKey": "${ZHIPU_API_KEY}",
|
|
21
|
+
"model": "glm-4-flash",
|
|
22
|
+
"temperature": 0.3,
|
|
23
|
+
"maxTokens": 2000
|
|
24
|
+
},
|
|
25
|
+
"mimo": {
|
|
26
|
+
"apiKey": "${MIMO_API_KEY}",
|
|
27
|
+
"model": "mimo-7b",
|
|
28
|
+
"temperature": 0.3,
|
|
29
|
+
"maxTokens": 2000
|
|
30
|
+
},
|
|
31
|
+
"qwen": {
|
|
32
|
+
"apiKey": "${DASHSCOPE_API_KEY}",
|
|
33
|
+
"model": "qwen-turbo",
|
|
34
|
+
"temperature": 0.3,
|
|
35
|
+
"maxTokens": 2000
|
|
36
|
+
},
|
|
37
|
+
"ernie": {
|
|
38
|
+
"apiKey": "${BAIDU_API_KEY}",
|
|
39
|
+
"secretKey": "${BAIDU_SECRET_KEY}",
|
|
40
|
+
"model": "ernie-4.0-turbo-8k",
|
|
41
|
+
"temperature": 0.3,
|
|
42
|
+
"maxTokens": 2000
|
|
43
|
+
},
|
|
44
|
+
"deepseek": {
|
|
45
|
+
"apiKey": "${DEEPSEEK_API_KEY}",
|
|
46
|
+
"model": "deepseek-chat",
|
|
47
|
+
"temperature": 0.3,
|
|
48
|
+
"maxTokens": 2000
|
|
49
|
+
},
|
|
50
|
+
"ollama": {
|
|
51
|
+
"baseUrl": "http://localhost:11434",
|
|
52
|
+
"model": "llama2",
|
|
53
|
+
"temperature": 0.3
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"features": {
|
|
57
|
+
"intentUnderstanding": true,
|
|
58
|
+
"parameterExtraction": true,
|
|
59
|
+
"skillSelection": true,
|
|
60
|
+
"resultSummary": true,
|
|
61
|
+
"learningFeedback": true
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Model - AI 模型抽象基类
|
|
3
|
+
* 所有模型 Provider 必须继承此类并实现抽象方法
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class BaseModel {
|
|
7
|
+
constructor(name, config = {}) {
|
|
8
|
+
this.name = name;
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.initialized = false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 初始化模型
|
|
15
|
+
* @returns {Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
async init() {
|
|
18
|
+
throw new Error('init() must be implemented by subclass');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 发送聊天请求
|
|
23
|
+
* @param {Array} messages - 消息数组 [{role, content}]
|
|
24
|
+
* @param {Object} options - 请求选项
|
|
25
|
+
* @returns {Promise<string>} 模型响应
|
|
26
|
+
*/
|
|
27
|
+
async chat(messages, options = {}) {
|
|
28
|
+
throw new Error('chat() must be implemented by subclass');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 发送补全请求
|
|
33
|
+
* @param {string} prompt - 提示词
|
|
34
|
+
* @param {Object} options - 请求选项
|
|
35
|
+
* @returns {Promise<string>} 模型响应
|
|
36
|
+
*/
|
|
37
|
+
async complete(prompt, options = {}) {
|
|
38
|
+
throw new Error('complete() must be implemented by subclass');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 检查模型是否可用
|
|
43
|
+
* @returns {Promise<boolean>}
|
|
44
|
+
*/
|
|
45
|
+
async isAvailable() {
|
|
46
|
+
throw new Error('isAvailable() must be implemented by subclass');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 获取模型信息
|
|
51
|
+
* @returns {Object}
|
|
52
|
+
*/
|
|
53
|
+
getInfo() {
|
|
54
|
+
return {
|
|
55
|
+
name: this.name,
|
|
56
|
+
provider: this.constructor.name,
|
|
57
|
+
initialized: this.initialized
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 验证配置
|
|
63
|
+
* @returns {boolean}
|
|
64
|
+
*/
|
|
65
|
+
validateConfig() {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = BaseModel;
|
package/core/ai/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Module - AI 模型接入层入口
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const ModelManager = require('./model-manager');
|
|
6
|
+
const BaseModel = require('./base-model');
|
|
7
|
+
const OpenAIProvider = require('./providers/openai');
|
|
8
|
+
const AnthropicProvider = require('./providers/anthropic');
|
|
9
|
+
const OllamaProvider = require('./providers/ollama');
|
|
10
|
+
const GLMProvider = require('./providers/glm');
|
|
11
|
+
const MiMoProvider = require('./providers/mimo');
|
|
12
|
+
const QwenProvider = require('./providers/qwen');
|
|
13
|
+
const ERNIEProvider = require('./providers/ernie');
|
|
14
|
+
const DeepSeekProvider = require('./providers/deepseek');
|
|
15
|
+
const prompts = require('./prompts');
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
ModelManager,
|
|
19
|
+
BaseModel,
|
|
20
|
+
OpenAIProvider,
|
|
21
|
+
AnthropicProvider,
|
|
22
|
+
OllamaProvider,
|
|
23
|
+
GLMProvider,
|
|
24
|
+
MiMoProvider,
|
|
25
|
+
QwenProvider,
|
|
26
|
+
ERNIEProvider,
|
|
27
|
+
DeepSeekProvider,
|
|
28
|
+
prompts
|
|
29
|
+
};
|