@bolloon/bolloon-agent 0.1.29 → 0.1.32

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/dist/index.js CHANGED
@@ -1310,6 +1310,10 @@ function printHelp() {
1310
1310
 
1311
1311
  环境变量:
1312
1312
  MINIMAX_API_KEY MiniMax API 密钥
1313
+ DEEPSEEK_API_KEY DeepSeek API 密钥
1314
+ KIMI_API_KEY / MOONSHOT_API_KEY Kimi/Moonshot API 密钥
1315
+ GLM_API_KEY / ZHIPU_API_KEY 智谱 GLM API 密钥
1316
+ QWEN_API_KEY / DASHSCOPE_API_KEY 通义千问 API 密钥
1313
1317
  OPENAI_API_KEY OpenAI API 密钥(Pi SDK)
1314
1318
  ANTHROPIC_API_KEY Anthropic API 密钥(Pi SDK)
1315
1319
  PORT Web 服务端口(默认 54188)
@@ -1365,6 +1369,10 @@ async function main() {
1365
1369
  const hasOpenAI = !!process.env.OPENAI_API_KEY;
1366
1370
  const hasAnthropic = !!process.env.ANTHROPIC_API_KEY;
1367
1371
  const hasMinimax = !!process.env.MINIMAX_API_KEY;
1372
+ const hasDeepSeek = !!process.env.DEEPSEEK_API_KEY;
1373
+ const hasKimi = !!(process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY);
1374
+ const hasGlm = !!(process.env.GLM_API_KEY || process.env.ZHIPU_API_KEY);
1375
+ const hasQwen = !!(process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY);
1368
1376
  const hasOpenRouter = !!process.env.OPENROUTER_API_KEY;
1369
1377
  const hasGemini = !!process.env.GEMINI_API_KEY;
1370
1378
  const hasOllama = !!process.env.OLLAMA_BASE_URL;
@@ -1373,7 +1381,11 @@ async function main() {
1373
1381
  hasOpenRouter ? 'OpenRouter' :
1374
1382
  hasGemini ? 'Gemini' :
1375
1383
  hasOllama ? 'Ollama' :
1376
- hasMinimax ? 'MiniMax' : null;
1384
+ hasMinimax ? 'MiniMax' :
1385
+ hasDeepSeek ? 'DeepSeek' :
1386
+ hasKimi ? 'Kimi' :
1387
+ hasGlm ? 'GLM' :
1388
+ hasQwen ? 'Qwen' : null;
1377
1389
  if (llmProvider) {
1378
1390
  s.step(0, 4, `LLM: ${llmProvider}`, 'ok');
1379
1391
  initMinimax({ provider: llmProvider.toLowerCase() });
@@ -61,6 +61,42 @@ export const DEFAULT_PROVIDER_CONFIGS = {
61
61
  maxTokens: 4096,
62
62
  requiresApiKey: true
63
63
  },
64
+ deepseek: {
65
+ enabled: false,
66
+ apiKey: '',
67
+ baseUrl: 'https://api.deepseek.com/v1',
68
+ model: 'deepseek-chat',
69
+ temperature: 0.7,
70
+ maxTokens: 4096,
71
+ requiresApiKey: true
72
+ },
73
+ kimi: {
74
+ enabled: false,
75
+ apiKey: '',
76
+ baseUrl: 'https://api.moonshot.cn/v1',
77
+ model: 'moonshot-v1-8k',
78
+ temperature: 0.7,
79
+ maxTokens: 4096,
80
+ requiresApiKey: true
81
+ },
82
+ glm: {
83
+ enabled: false,
84
+ apiKey: '',
85
+ baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
86
+ model: 'glm-4-flash',
87
+ temperature: 0.7,
88
+ maxTokens: 4096,
89
+ requiresApiKey: true
90
+ },
91
+ qwen: {
92
+ enabled: false,
93
+ apiKey: '',
94
+ baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
95
+ model: 'qwen-plus',
96
+ temperature: 0.7,
97
+ maxTokens: 4096,
98
+ requiresApiKey: true
99
+ },
64
100
  local: {
65
101
  enabled: false,
66
102
  apiKey: '',
@@ -78,6 +114,10 @@ export const PROVIDER_INFO = {
78
114
  gemini: { name: 'Google Gemini', description: 'Gemini 系列模型', requiresApiKey: true },
79
115
  ollama: { name: 'Ollama', description: '本地 LLM 运行框架', requiresApiKey: false },
80
116
  minimax: { name: 'MiniMax', description: '国产大模型服务', requiresApiKey: true },
117
+ deepseek: { name: 'DeepSeek', description: '深度求索大模型', requiresApiKey: true },
118
+ kimi: { name: 'Kimi (月之暗面)', description: 'Moonshot 长上下文模型', requiresApiKey: true },
119
+ glm: { name: 'GLM (智谱)', description: '智谱 ChatGLM 系列模型', requiresApiKey: true },
120
+ qwen: { name: 'Qwen (通义千问)', description: '阿里云通义千问系列', requiresApiKey: true },
81
121
  local: { name: '本地模型', description: '本地部署的模型服务', requiresApiKey: false }
82
122
  };
83
123
  function getDefaultConfig() {
@@ -97,6 +137,18 @@ function getDefaultConfig() {
97
137
  if (process.env.MINIMAX_API_KEY) {
98
138
  envConfigs.minimax = { ...DEFAULT_PROVIDER_CONFIGS.minimax, enabled: true, apiKey: process.env.MINIMAX_API_KEY };
99
139
  }
140
+ if (process.env.DEEPSEEK_API_KEY) {
141
+ envConfigs.deepseek = { ...DEFAULT_PROVIDER_CONFIGS.deepseek, enabled: true, apiKey: process.env.DEEPSEEK_API_KEY };
142
+ }
143
+ if (process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY) {
144
+ envConfigs.kimi = { ...DEFAULT_PROVIDER_CONFIGS.kimi, enabled: true, apiKey: process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY || '' };
145
+ }
146
+ if (process.env.GLM_API_KEY || process.env.ZHIPU_API_KEY) {
147
+ envConfigs.glm = { ...DEFAULT_PROVIDER_CONFIGS.glm, enabled: true, apiKey: process.env.GLM_API_KEY || process.env.ZHIPU_API_KEY || '' };
148
+ }
149
+ if (process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY) {
150
+ envConfigs.qwen = { ...DEFAULT_PROVIDER_CONFIGS.qwen, enabled: true, apiKey: process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY || '' };
151
+ }
100
152
  if (process.env.OLLAMA_BASE_URL) {
101
153
  envConfigs.ollama = { ...DEFAULT_PROVIDER_CONFIGS.ollama, enabled: true, baseUrl: process.env.OLLAMA_BASE_URL };
102
154
  }
@@ -111,6 +163,14 @@ function getDefaultConfig() {
111
163
  activeProvider = 'gemini';
112
164
  else if (process.env.MINIMAX_API_KEY)
113
165
  activeProvider = 'minimax';
166
+ else if (process.env.DEEPSEEK_API_KEY)
167
+ activeProvider = 'deepseek';
168
+ else if (process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY)
169
+ activeProvider = 'kimi';
170
+ else if (process.env.GLM_API_KEY || process.env.ZHIPU_API_KEY)
171
+ activeProvider = 'glm';
172
+ else if (process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY)
173
+ activeProvider = 'qwen';
114
174
  else if (process.env.OLLAMA_BASE_URL)
115
175
  activeProvider = 'ollama';
116
176
  const providers = { ...DEFAULT_PROVIDER_CONFIGS };
@@ -237,6 +297,10 @@ class LLMConfigStore {
237
297
  case 'openai':
238
298
  case 'openrouter':
239
299
  case 'minimax':
300
+ case 'deepseek':
301
+ case 'kimi':
302
+ case 'glm':
303
+ case 'qwen':
240
304
  if (config.apiKey)
241
305
  headers['Authorization'] = `Bearer ${config.apiKey}`;
242
306
  break;
package/dist/llm/pi-ai.js CHANGED
@@ -68,6 +68,10 @@ export class PiAIModel {
68
68
  switch (this.provider) {
69
69
  case 'openai':
70
70
  case 'minimax':
71
+ case 'deepseek':
72
+ case 'kimi':
73
+ case 'glm':
74
+ case 'qwen':
71
75
  return this.callOpenAI(messages, temperature, maxTokens);
72
76
  case 'anthropic':
73
77
  return this.callAnthropic(messages, temperature, maxTokens);
@@ -94,6 +98,10 @@ export class PiAIModel {
94
98
  openrouter: process.env.OPENROUTER_API_KEY || '',
95
99
  gemini: process.env.GEMINI_API_KEY || '',
96
100
  minimax: process.env.MINIMAX_API_KEY || '',
101
+ deepseek: process.env.DEEPSEEK_API_KEY || '',
102
+ kimi: process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY || '',
103
+ glm: process.env.GLM_API_KEY || process.env.ZHIPU_API_KEY || '',
104
+ qwen: process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY || '',
97
105
  local: ''
98
106
  };
99
107
  return envVars[this.provider] || '';
@@ -110,6 +118,10 @@ export class PiAIModel {
110
118
  openrouter: process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1',
111
119
  gemini: 'https://generativelanguage.googleapis.com/v1beta',
112
120
  minimax: process.env.MINIMAX_BASE_URL || 'https://api.minimaxi.com/v1',
121
+ deepseek: process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com/v1',
122
+ kimi: process.env.KIMI_BASE_URL || process.env.MOONSHOT_BASE_URL || 'https://api.moonshot.cn/v1',
123
+ glm: process.env.GLM_BASE_URL || process.env.ZHIPU_BASE_URL || 'https://open.bigmodel.cn/api/paas/v4',
124
+ qwen: process.env.QWEN_BASE_URL || process.env.DASHSCOPE_BASE_URL || 'https://dashscope.aliyuncs.com/compatible-mode/v1',
113
125
  local: 'http://localhost:11434'
114
126
  };
115
127
  return baseUrls[this.provider];
@@ -122,6 +134,10 @@ export class PiAIModel {
122
134
  openrouter: this.config.model || 'anthropic/claude-3.5-sonnet',
123
135
  gemini: this.config.model || 'gemini-2.0-flash',
124
136
  minimax: this.config.model || process.env.MINIMAX_MODEL || 'MiniMax-M2.7',
137
+ deepseek: this.config.model || process.env.DEEPSEEK_MODEL || 'deepseek-chat',
138
+ kimi: this.config.model || process.env.KIMI_MODEL || process.env.MOONSHOT_MODEL || 'moonshot-v1-8k',
139
+ glm: this.config.model || process.env.GLM_MODEL || process.env.ZHIPU_MODEL || 'glm-4-flash',
140
+ qwen: this.config.model || process.env.QWEN_MODEL || process.env.DASHSCOPE_MODEL || 'qwen-plus',
125
141
  local: this.config.model || 'llama3.2'
126
142
  };
127
143
  return modelMap[this.provider];
@@ -368,6 +384,14 @@ function detectProvider() {
368
384
  return 'ollama';
369
385
  if (process.env.MINIMAX_API_KEY)
370
386
  return 'minimax';
387
+ if (process.env.DEEPSEEK_API_KEY)
388
+ return 'deepseek';
389
+ if (process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY)
390
+ return 'kimi';
391
+ if (process.env.GLM_API_KEY || process.env.ZHIPU_API_KEY)
392
+ return 'glm';
393
+ if (process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY)
394
+ return 'qwen';
371
395
  return 'openai';
372
396
  }
373
397
  function detectModel(provider) {
@@ -378,6 +402,10 @@ function detectModel(provider) {
378
402
  openrouter: 'anthropic/claude-3.5-sonnet',
379
403
  gemini: 'gemini-2.0-flash',
380
404
  minimax: 'MiniMax-M2.7',
405
+ deepseek: 'deepseek-chat',
406
+ kimi: 'moonshot-v1-8k',
407
+ glm: 'glm-4-flash',
408
+ qwen: 'qwen-plus',
381
409
  local: 'llama3.2'
382
410
  };
383
411
  return defaults[provider];
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Video Generation API Configuration Store
3
+ *
4
+ * 视频生成模型配置(与 LLM 完全独立)。当前内置 Seedance(火山引擎 ARK)。
5
+ * Seedance 任务流: POST /contents/generations/tasks → 轮询 GET /contents/generations/tasks/{id}
6
+ */
7
+ import * as fs from 'fs/promises';
8
+ import * as path from 'path';
9
+ const CONFIG_DIR = path.join(process.env.HOME || '/tmp', '.bolloon');
10
+ const CONFIG_PATH = path.join(CONFIG_DIR, 'video-config.json');
11
+ export const DEFAULT_VIDEO_PROVIDER_CONFIGS = {
12
+ seedance: {
13
+ enabled: false,
14
+ apiKey: '',
15
+ baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
16
+ // 文生视频 lite 版(也支持图生视频,加 --resolution 等参数)
17
+ model: 'doubao-seedance-1-0-lite-t2v-250428',
18
+ resolution: '720p',
19
+ duration: 5,
20
+ ratio: '16:9',
21
+ requiresApiKey: true
22
+ }
23
+ };
24
+ export const VIDEO_PROVIDER_INFO = {
25
+ seedance: {
26
+ name: 'Seedance (火山方舟)',
27
+ description: '字节跳动文生视频 / 图生视频模型',
28
+ requiresApiKey: true,
29
+ docs: 'https://www.volcengine.com/docs/82379'
30
+ }
31
+ };
32
+ function getDefaultConfig() {
33
+ const envConfigs = {};
34
+ if (process.env.SEEDANCE_API_KEY || process.env.ARK_API_KEY) {
35
+ envConfigs.seedance = {
36
+ ...DEFAULT_VIDEO_PROVIDER_CONFIGS.seedance,
37
+ enabled: true,
38
+ apiKey: process.env.SEEDANCE_API_KEY || process.env.ARK_API_KEY || ''
39
+ };
40
+ }
41
+ const activeProvider = 'seedance';
42
+ const providers = { ...DEFAULT_VIDEO_PROVIDER_CONFIGS };
43
+ for (const [provider, config] of Object.entries(envConfigs)) {
44
+ if (config) {
45
+ providers[provider] = config;
46
+ }
47
+ }
48
+ return {
49
+ activeProvider,
50
+ providers,
51
+ updatedAt: new Date().toISOString()
52
+ };
53
+ }
54
+ class VideoConfigStore {
55
+ config = null;
56
+ initialized = false;
57
+ async initialize() {
58
+ if (this.initialized)
59
+ return;
60
+ try {
61
+ await fs.mkdir(CONFIG_DIR, { recursive: true });
62
+ const data = await fs.readFile(CONFIG_PATH, 'utf-8');
63
+ const loadedConfig = JSON.parse(data);
64
+ // 确保加载的配置包含所有默认供应商
65
+ const defaultProviders = Object.keys(DEFAULT_VIDEO_PROVIDER_CONFIGS);
66
+ for (const provider of defaultProviders) {
67
+ if (!loadedConfig.providers[provider]) {
68
+ loadedConfig.providers[provider] = { ...DEFAULT_VIDEO_PROVIDER_CONFIGS[provider] };
69
+ }
70
+ }
71
+ const activeProvider = loadedConfig.activeProvider;
72
+ if (!activeProvider || !DEFAULT_VIDEO_PROVIDER_CONFIGS[activeProvider]) {
73
+ loadedConfig.activeProvider = 'seedance';
74
+ }
75
+ this.config = loadedConfig;
76
+ }
77
+ catch {
78
+ this.config = getDefaultConfig();
79
+ await this.save();
80
+ }
81
+ this.initialized = true;
82
+ }
83
+ async save() {
84
+ if (!this.config)
85
+ return;
86
+ this.config.updatedAt = new Date().toISOString();
87
+ await fs.writeFile(CONFIG_PATH, JSON.stringify(this.config, null, 2));
88
+ }
89
+ async getConfig() {
90
+ await this.initialize();
91
+ return { ...this.config };
92
+ }
93
+ async getProvider(provider) {
94
+ await this.initialize();
95
+ return this.config?.providers[provider] || null;
96
+ }
97
+ async getActiveProvider() {
98
+ await this.initialize();
99
+ return this.config?.activeProvider || 'seedance';
100
+ }
101
+ async getActiveProviderConfig() {
102
+ await this.initialize();
103
+ const provider = this.config?.activeProvider;
104
+ if (!provider)
105
+ return null;
106
+ return this.config?.providers[provider] || null;
107
+ }
108
+ async setActiveProvider(provider) {
109
+ await this.initialize();
110
+ if (!this.config?.providers[provider]) {
111
+ throw new Error(`Unknown video provider: ${provider}`);
112
+ }
113
+ this.config.activeProvider = provider;
114
+ await this.save();
115
+ }
116
+ async updateProvider(provider, updates) {
117
+ await this.initialize();
118
+ if (!this.config?.providers[provider]) {
119
+ throw new Error(`Unknown video provider: ${provider}`);
120
+ }
121
+ this.config.providers[provider] = {
122
+ ...this.config.providers[provider],
123
+ ...updates
124
+ };
125
+ await this.save();
126
+ }
127
+ /**
128
+ * 测试连接:只校验 API key 是否能被 ARK 接受(创建任务失败不算连接失败,
129
+ * 返回 401/403 才算失败)。
130
+ */
131
+ async testProvider(provider) {
132
+ await this.initialize();
133
+ const config = this.config?.providers[provider];
134
+ if (!config) {
135
+ return { success: false, error: 'Provider not configured' };
136
+ }
137
+ if (!config.enabled) {
138
+ return { success: false, error: 'Provider is not enabled' };
139
+ }
140
+ if (config.requiresApiKey && !config.apiKey) {
141
+ return { success: false, error: 'API key is required' };
142
+ }
143
+ const startTime = Date.now();
144
+ try {
145
+ // 列出可用模型(轻量级健康检查)。ARK 端点:GET /models
146
+ const response = await fetch(`${config.baseUrl.replace(/\/$/, '')}/models`, {
147
+ method: 'GET',
148
+ headers: { 'Authorization': `Bearer ${config.apiKey}` }
149
+ });
150
+ const latency = Date.now() - startTime;
151
+ if (response.ok) {
152
+ return { success: true, latency };
153
+ }
154
+ else {
155
+ const errorText = await response.text().catch(() => 'Unknown error');
156
+ return {
157
+ success: false,
158
+ error: `HTTP ${response.status}: ${errorText.substring(0, 200)}`,
159
+ latency
160
+ };
161
+ }
162
+ }
163
+ catch (error) {
164
+ return { success: false, error: error.message || 'Connection failed', latency: Date.now() - startTime };
165
+ }
166
+ }
167
+ getAllProviderInfo() {
168
+ return VIDEO_PROVIDER_INFO;
169
+ }
170
+ }
171
+ export const videoConfigStore = new VideoConfigStore();