@miphamai/cli 0.39.0 → 0.40.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.
@@ -22,6 +22,7 @@ import type { DaemonDatabase } from './database'
22
22
  import type { QueryEngine } from '../core/engine'
23
23
  import type { ContextManager } from '../core/context'
24
24
  import type { ProviderRegistry } from '../providers/registry'
25
+ import { logger } from './logger'
25
26
 
26
27
  export class WorkerPool {
27
28
  private workers: Map<string, SessionWorker>
@@ -149,7 +150,7 @@ export class WorkerPool {
149
150
  this.stopWorker(sessionId).catch((err) => {
150
151
  // Log but never crash — this runs in a Timer callback outside
151
152
  // any request context
152
- console.error(`WorkerPool: error auto-stopping idle worker for session ${sessionId}:`, err)
153
+ logger.error('error auto-stopping idle worker', { sessionId, error: err })
153
154
  })
154
155
  }, this.idleTimeoutMs)
155
156
 
package/src/index.tsx CHANGED
@@ -193,8 +193,9 @@ function SetupGate(props: SetupGateProps) {
193
193
  }
194
194
 
195
195
  export async function runApp(options: RunOptions): Promise<void> {
196
- // Metrics: count CLI invocation
196
+ // Metrics: count CLI invocation + active session
197
197
  getMetrics().cliInvocations.inc()
198
+ getMetrics().activeSessions.inc()
198
199
 
199
200
  // ── Workspace Trust Check ──
200
201
  await checkWorkspaceTrust()
@@ -591,6 +592,14 @@ export async function runApp(options: RunOptions): Promise<void> {
591
592
  })
592
593
  }
593
594
  }
595
+ // Flush CRSI effectiveness — evaluate rules and apply auto-degrade/disable.
596
+ // Best-effort: the self-improvement flush must never block session exit.
597
+ try {
598
+ engine.getAutoMemory().flushEffectiveness()
599
+ } catch {
600
+ // ignore — CRSI flush is non-critical
601
+ }
602
+ getMetrics().activeSessions.dec()
594
603
  process.exit(0)
595
604
  }
596
605
 
@@ -1,5 +1,6 @@
1
1
  import type { ProviderConfig, ModelInfo, Message, StreamChunk } from '../shared/index.ts'
2
2
  import type { Llm } from './llm'
3
+ import { getMetrics } from '../core/metrics'
3
4
 
4
5
  export interface ProviderInstance {
5
6
  config: ProviderConfig
@@ -115,6 +116,23 @@ export class ProviderRegistry implements Llm {
115
116
 
116
117
  async *chat(req: ChatRequest): AsyncGenerator<StreamChunk> {
117
118
  const provider = this.getActive()
118
- yield* provider.chat({ ...req, model: req.model || this.activeModelId })
119
+ const providerId = this.activeProviderId
120
+ const modelId = req.model || this.activeModelId
121
+ const metrics = getMetrics()
122
+ const start = Date.now()
123
+ metrics.modelRequests.inc({ provider: providerId, model: modelId })
124
+ try {
125
+ for await (const chunk of provider.chat({ ...req, model: modelId })) {
126
+ if (chunk.type === 'error') {
127
+ metrics.modelRequestErrors.inc({ provider: providerId, error_type: 'api_error' })
128
+ }
129
+ yield chunk
130
+ }
131
+ } catch (err) {
132
+ metrics.modelRequestErrors.inc({ provider: providerId, error_type: 'exception' })
133
+ throw err
134
+ } finally {
135
+ metrics.modelRequestDurationMs.observe(Date.now() - start, { provider: providerId })
136
+ }
119
137
  }
120
138
  }
@@ -1,4 +1,472 @@
1
- // ── 常量唯一真源:@mipham/shared/constants ──
2
- // DEFAULT_PROVIDERS / PROTOCOL_LABELS / TOOL_CATEGORIES / OLLAMA_PRESET_MODELS
3
- // 及路径(.mipham/memory)/Artifact 常量均在此包,CLI 直接 re-export。
4
- export * from '@mipham/shared/constants'
1
+ import type { ProviderConfig, ModelInfo } from './types'
2
+ import miphamModelsSnapshot from './mipham-models.json' with { type: 'json' }
3
+
4
+ // Build MiphamAI provider from synced model definitions.
5
+ // Source of truth: Engine GET /v1/mipham-models → packages/shared/src/mipham-models.json
6
+ // Run `bun run scripts/sync-mipham-models.ts` to update from Engine.
7
+ const MIPHAM_MODELS: ModelInfo[] = miphamModelsSnapshot.models.map((m) => ({
8
+ id: m.id,
9
+ name: m.name,
10
+ providerId: m.providerId,
11
+ contextWindow: m.contextWindow,
12
+ maxOutput: m.maxOutput,
13
+ vision: m.vision,
14
+ status: m.status as 'active' | 'upcoming' | 'deprecated',
15
+ }))
16
+
17
+ const MIPHAM_PROVIDER: ProviderConfig = {
18
+ id: miphamModelsSnapshot.provider.id,
19
+ name: miphamModelsSnapshot.provider.name,
20
+ protocol: miphamModelsSnapshot.provider.protocol as 'openai-compatible',
21
+ baseUrl: miphamModelsSnapshot.provider.baseUrl,
22
+ apiKey: miphamModelsSnapshot.provider.apiKey,
23
+ models: MIPHAM_MODELS,
24
+ status: miphamModelsSnapshot.provider.status as 'active' | 'upcoming',
25
+ }
26
+
27
+ // Providers: alphabetical by id. Models: Lite/Flash → Text → Vision → Code → Pro/Think
28
+ export const DEFAULT_PROVIDERS: ProviderConfig[] = [
29
+ {
30
+ id: 'anthropic',
31
+ name: 'Anthropic Claude',
32
+ protocol: 'anthropic',
33
+ apiKey: '${ANTHROPIC_API_KEY}',
34
+ models: [
35
+ {
36
+ id: 'claude-haiku-4-5-20251001',
37
+ name: 'Claude Haiku 4.5',
38
+ providerId: 'anthropic',
39
+ contextWindow: 200_000,
40
+ maxOutput: 32_000,
41
+ vision: true,
42
+ status: 'active',
43
+ },
44
+ {
45
+ id: 'claude-sonnet-4-6',
46
+ name: 'Claude Sonnet 4.6',
47
+ providerId: 'anthropic',
48
+ contextWindow: 1_000_000,
49
+ maxOutput: 128_000,
50
+ vision: true,
51
+ status: 'active',
52
+ },
53
+ {
54
+ id: 'claude-opus-4-8',
55
+ name: 'Claude Opus 4.8',
56
+ providerId: 'anthropic',
57
+ contextWindow: 1_000_000,
58
+ maxOutput: 128_000,
59
+ vision: true,
60
+ status: 'active',
61
+ },
62
+ {
63
+ id: 'claude-fable-5',
64
+ name: 'Claude Fable 5',
65
+ providerId: 'anthropic',
66
+ contextWindow: 1_000_000,
67
+ maxOutput: 128_000,
68
+ vision: true,
69
+ status: 'active',
70
+ },
71
+ {
72
+ id: 'claude-sonnet-5',
73
+ name: 'Claude Sonnet 5',
74
+ providerId: 'anthropic',
75
+ contextWindow: 1_000_000,
76
+ maxOutput: 128_000,
77
+ vision: true,
78
+ status: 'active',
79
+ },
80
+ {
81
+ id: 'claude-opus-5',
82
+ name: 'Claude Opus 5',
83
+ providerId: 'anthropic',
84
+ contextWindow: 1_000_000,
85
+ maxOutput: 128_000,
86
+ vision: true,
87
+ status: 'active',
88
+ },
89
+ ],
90
+ },
91
+ {
92
+ id: 'deepseek',
93
+ name: 'DeepSeek',
94
+ protocol: 'openai-compatible',
95
+ baseUrl: 'https://api.deepseek.com/v1',
96
+ apiKey: '${DEEPSEEK_API_KEY}',
97
+ models: [
98
+ {
99
+ id: 'deepseek-v4-flash',
100
+ name: 'DeepSeek V4 Flash',
101
+ providerId: 'deepseek',
102
+ contextWindow: 1_000_000,
103
+ maxOutput: 384_000,
104
+ vision: false,
105
+ status: 'active',
106
+ },
107
+ {
108
+ id: 'deepseek-v4-pro',
109
+ name: 'DeepSeek V4 Pro',
110
+ providerId: 'deepseek',
111
+ contextWindow: 1_000_000,
112
+ maxOutput: 384_000,
113
+ vision: false,
114
+ status: 'active',
115
+ },
116
+ ],
117
+ },
118
+ {
119
+ id: 'google',
120
+ name: 'Google Gemini',
121
+ protocol: 'openai-compatible',
122
+ baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai',
123
+ apiKey: '${GEMINI_API_KEY}',
124
+ models: [
125
+ {
126
+ id: 'gemini-3.0-flash',
127
+ name: 'Gemini 3.0 Flash',
128
+ providerId: 'google',
129
+ contextWindow: 1_000_000,
130
+ maxOutput: 64_000,
131
+ vision: true,
132
+ status: 'active',
133
+ },
134
+ {
135
+ id: 'gemini-3.0-pro',
136
+ name: 'Gemini 3.0 Pro',
137
+ providerId: 'google',
138
+ contextWindow: 1_000_000,
139
+ maxOutput: 128_000,
140
+ vision: true,
141
+ status: 'active',
142
+ },
143
+ {
144
+ id: 'gemini-2.5-pro',
145
+ name: 'Gemini 2.5 Pro',
146
+ providerId: 'google',
147
+ contextWindow: 1_000_000,
148
+ maxOutput: 64_000,
149
+ vision: true,
150
+ status: 'active',
151
+ },
152
+ ],
153
+ },
154
+ {
155
+ id: 'doubao',
156
+ name: '豆包 (字节跳动)',
157
+ protocol: 'openai-compatible',
158
+ baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
159
+ apiKey: '${DOUBAO_API_KEY}',
160
+ models: [
161
+ {
162
+ id: 'doubao-seed-1.6-flash',
163
+ name: '豆包 Seed 1.6 Flash',
164
+ providerId: 'doubao',
165
+ contextWindow: 256_000,
166
+ maxOutput: 128_000,
167
+ vision: true,
168
+ status: 'active',
169
+ },
170
+ {
171
+ id: 'doubao-seed-2.0-mini',
172
+ name: '豆包 Seed 2.0 Mini',
173
+ providerId: 'doubao',
174
+ contextWindow: 256_000,
175
+ maxOutput: 128_000,
176
+ vision: true,
177
+ status: 'active',
178
+ },
179
+ {
180
+ id: 'doubao-seed-2.0-lite',
181
+ name: '豆包 Seed 2.0 Lite',
182
+ providerId: 'doubao',
183
+ contextWindow: 256_000,
184
+ maxOutput: 128_000,
185
+ vision: true,
186
+ status: 'active',
187
+ },
188
+ {
189
+ id: 'doubao-seed-1.6',
190
+ name: '豆包 Seed 1.6',
191
+ providerId: 'doubao',
192
+ contextWindow: 256_000,
193
+ maxOutput: 128_000,
194
+ vision: true,
195
+ status: 'active',
196
+ },
197
+ {
198
+ id: 'doubao-seed-2.0-pro',
199
+ name: '豆包 Seed 2.0 Pro',
200
+ providerId: 'doubao',
201
+ contextWindow: 256_000,
202
+ maxOutput: 128_000,
203
+ vision: true,
204
+ status: 'active',
205
+ },
206
+ {
207
+ id: 'doubao-seed-2.0-code',
208
+ name: '豆包 Seed 2.0 Code',
209
+ providerId: 'doubao',
210
+ contextWindow: 256_000,
211
+ maxOutput: 128_000,
212
+ vision: true,
213
+ status: 'active',
214
+ },
215
+ ],
216
+ },
217
+ {
218
+ id: 'hunyuan',
219
+ name: '腾讯混元',
220
+ protocol: 'openai-compatible',
221
+ baseUrl: 'https://api.hunyuan.cloud.tencent.com/v1',
222
+ apiKey: '${HUNYUAN_API_KEY}',
223
+ models: [
224
+ {
225
+ id: 'hunyuan-lite',
226
+ name: '混元 Lite (免费)',
227
+ providerId: 'hunyuan',
228
+ contextWindow: 256_000,
229
+ maxOutput: 6_000,
230
+ vision: false,
231
+ status: 'active',
232
+ },
233
+ {
234
+ id: 'hunyuan-turbos-latest',
235
+ name: '混元 TurboS',
236
+ providerId: 'hunyuan',
237
+ contextWindow: 32_000,
238
+ maxOutput: 16_000,
239
+ vision: false,
240
+ status: 'active',
241
+ },
242
+ {
243
+ id: 'hunyuan-2.0-instruct-20251111',
244
+ name: '混元 2.0 Instruct',
245
+ providerId: 'hunyuan',
246
+ contextWindow: 144_000,
247
+ maxOutput: 16_000,
248
+ vision: false,
249
+ status: 'active',
250
+ },
251
+ {
252
+ id: 'hunyuan-t1-vision-20250916',
253
+ name: '混元 T1 Vision',
254
+ providerId: 'hunyuan',
255
+ contextWindow: 32_000,
256
+ maxOutput: 64_000,
257
+ vision: true,
258
+ status: 'active',
259
+ },
260
+ {
261
+ id: 'hunyuan-a13b',
262
+ name: '混元 A13B',
263
+ providerId: 'hunyuan',
264
+ contextWindow: 224_000,
265
+ maxOutput: 32_000,
266
+ vision: false,
267
+ status: 'active',
268
+ },
269
+ {
270
+ id: 'hunyuan-2.0-thinking-20251109',
271
+ name: '混元 2.0 Think',
272
+ providerId: 'hunyuan',
273
+ contextWindow: 192_000,
274
+ maxOutput: 64_000,
275
+ vision: false,
276
+ status: 'active',
277
+ },
278
+ {
279
+ id: 'hunyuan-t1-latest',
280
+ name: '混元 T1 (推理)',
281
+ providerId: 'hunyuan',
282
+ contextWindow: 32_000,
283
+ maxOutput: 64_000,
284
+ vision: false,
285
+ status: 'active',
286
+ },
287
+ {
288
+ id: 'hy3-preview',
289
+ name: '混元 Hy3 Preview',
290
+ providerId: 'hunyuan',
291
+ contextWindow: 256_000,
292
+ maxOutput: 128_000,
293
+ vision: false,
294
+ status: 'active',
295
+ },
296
+ ],
297
+ },
298
+ {
299
+ id: 'kimi',
300
+ name: 'Kimi (月之暗面)',
301
+ protocol: 'openai-compatible',
302
+ baseUrl: 'https://api.moonshot.cn/v1',
303
+ apiKey: '${KIMI_API_KEY}',
304
+ models: [
305
+ {
306
+ id: 'kimi-latest',
307
+ name: 'Kimi Latest',
308
+ providerId: 'kimi',
309
+ contextWindow: 128_000,
310
+ maxOutput: 16_000,
311
+ vision: true,
312
+ status: 'active',
313
+ },
314
+ {
315
+ id: 'kimi-k3',
316
+ name: 'Kimi K3',
317
+ providerId: 'kimi',
318
+ contextWindow: 1_000_000,
319
+ maxOutput: 128_000,
320
+ vision: true,
321
+ status: 'active',
322
+ },
323
+ {
324
+ id: 'moonshot-v1-8k',
325
+ name: 'Moonshot v1 8K',
326
+ providerId: 'kimi',
327
+ contextWindow: 8_000,
328
+ maxOutput: 4_000,
329
+ vision: false,
330
+ status: 'active',
331
+ },
332
+ {
333
+ id: 'moonshot-v1-32k',
334
+ name: 'Moonshot v1 32K',
335
+ providerId: 'kimi',
336
+ contextWindow: 32_000,
337
+ maxOutput: 4_000,
338
+ vision: false,
339
+ status: 'active',
340
+ },
341
+ {
342
+ id: 'moonshot-v1-128k',
343
+ name: 'Moonshot v1 128K',
344
+ providerId: 'kimi',
345
+ contextWindow: 128_000,
346
+ maxOutput: 4_000,
347
+ vision: false,
348
+ status: 'active',
349
+ },
350
+ ],
351
+ },
352
+ MIPHAM_PROVIDER,
353
+ {
354
+ id: 'ollama',
355
+ name: 'Ollama (本地)',
356
+ protocol: 'openai-compatible',
357
+ baseUrl: 'http://localhost:11434/v1',
358
+ apiKey: 'ollama-local',
359
+ models: [], // 动态发现,初值为空
360
+ },
361
+ {
362
+ id: 'openai',
363
+ name: 'OpenAI',
364
+ protocol: 'openai-compatible',
365
+ baseUrl: 'https://api.openai.com/v1',
366
+ apiKey: '${OPENAI_API_KEY}',
367
+ models: [
368
+ {
369
+ id: 'gpt-5.4-mini',
370
+ name: 'GPT-5.4 Mini',
371
+ providerId: 'openai',
372
+ contextWindow: 400_000,
373
+ maxOutput: 32_000,
374
+ vision: true,
375
+ status: 'active',
376
+ },
377
+ {
378
+ id: 'gpt-5.4',
379
+ name: 'GPT-5.4',
380
+ providerId: 'openai',
381
+ contextWindow: 1_050_000,
382
+ maxOutput: 128_000,
383
+ vision: true,
384
+ status: 'active',
385
+ },
386
+ {
387
+ id: 'gpt-5.5',
388
+ name: 'GPT-5.5',
389
+ providerId: 'openai',
390
+ contextWindow: 1_050_000,
391
+ maxOutput: 128_000,
392
+ vision: true,
393
+ status: 'active',
394
+ },
395
+ {
396
+ id: 'gpt-5.3-codex',
397
+ name: 'GPT-5.3 Codex',
398
+ providerId: 'openai',
399
+ contextWindow: 400_000,
400
+ maxOutput: 64_000,
401
+ vision: false,
402
+ status: 'active',
403
+ },
404
+ ],
405
+ },
406
+ {
407
+ id: 'qwen',
408
+ name: '通义千问',
409
+ protocol: 'openai-compatible',
410
+ baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
411
+ apiKey: '${QWEN_API_KEY}',
412
+ models: [
413
+ {
414
+ id: 'qwen-plus',
415
+ name: 'Qwen Plus',
416
+ providerId: 'qwen',
417
+ contextWindow: 128_000,
418
+ maxOutput: 32_000,
419
+ vision: true,
420
+ status: 'active',
421
+ },
422
+ {
423
+ id: 'qwen-max',
424
+ name: 'Qwen Max',
425
+ providerId: 'qwen',
426
+ contextWindow: 128_000,
427
+ maxOutput: 32_000,
428
+ vision: true,
429
+ status: 'active',
430
+ },
431
+ ],
432
+ },
433
+ ]
434
+
435
+ export const PROTOCOL_LABELS: Record<string, string> = {
436
+ 'openai-compatible': 'OpenAI Compatible',
437
+ anthropic: 'Anthropic',
438
+ custom: 'Custom Protocol',
439
+ }
440
+
441
+ export const TOOL_CATEGORIES = [
442
+ 'file',
443
+ 'exec',
444
+ 'agent',
445
+ 'network',
446
+ 'system',
447
+ 'artifact',
448
+ 'scheduling',
449
+ ] as const
450
+ export const CONFIG_FILE_NAME = 'config.yml'
451
+ export const MIPHAM_DIR = '.mipham'
452
+ export const USER_CONFIG_DIR = '.mipham'
453
+ export const MEMORY_DIR = 'memory'
454
+
455
+ /** 预置 Ollama 模型 — 与 ollama list 结果合并去重后展示 */
456
+ export const OLLAMA_PRESET_MODELS = [
457
+ { id: 'om-v5-flash', source: 'MiphamAI' },
458
+ { id: 'om-v5-pro', source: 'MiphamAI' },
459
+ { id: 'om-v5-visual', source: 'MiphamAI' },
460
+ { id: 'om-v5-apex', source: 'MiphamAI' },
461
+ { id: 'deepseek-r1:70b', source: '热门' },
462
+ { id: 'deepseek-v3', source: '热门' },
463
+ { id: 'qwen2.5:72b', source: '热门' },
464
+ { id: 'qwen3', source: '热门' },
465
+ ] as const
466
+
467
+ // ── Artifact Constants ──
468
+ export const ARTIFACTS_DIR = 'artifacts'
469
+ export const ARTIFACT_PORT = 9876
470
+ export const ARTIFACT_MAX_PORT_TRIES = 10
471
+ export const ARTIFACT_MAX_SIZE = 5 * 1024 * 1024 // 5MB
472
+ export const ARTIFACT_ALLOWED_EXTENSIONS = ['.html', '.svg']
@@ -0,0 +1,50 @@
1
+ {
2
+ "_comment": "Mipham model definitions — synced from Engine GET /v1/mipham-models. Run 'bun run scripts/sync-mipham-models.ts' to update.",
3
+ "provider": {
4
+ "id": "mipham",
5
+ "name": "MiphamAI",
6
+ "protocol": "openai-compatible",
7
+ "baseUrl": "https://api.onemipham.com/v1",
8
+ "apiKey": "${MIPHAM_API_KEY}",
9
+ "status": "active"
10
+ },
11
+ "models": [
12
+ {
13
+ "id": "om-v5-flash",
14
+ "name": "OM V5 Flash",
15
+ "providerId": "mipham",
16
+ "contextWindow": 16384,
17
+ "maxOutput": 4096,
18
+ "vision": false,
19
+ "status": "active"
20
+ },
21
+ {
22
+ "id": "om-v5-pro",
23
+ "name": "OM V5 Pro",
24
+ "providerId": "mipham",
25
+ "contextWindow": 131072,
26
+ "maxOutput": 16384,
27
+ "vision": false,
28
+ "status": "active"
29
+ },
30
+ {
31
+ "id": "om-v5-visual",
32
+ "name": "OM V5 Visual",
33
+ "providerId": "mipham",
34
+ "contextWindow": 65536,
35
+ "maxOutput": 4096,
36
+ "vision": true,
37
+ "status": "active"
38
+ },
39
+ {
40
+ "id": "om-v5-apex",
41
+ "name": "OM V5 Apex",
42
+ "providerId": "mipham",
43
+ "contextWindow": 200000,
44
+ "maxOutput": 32768,
45
+ "vision": false,
46
+ "status": "active"
47
+ }
48
+ ],
49
+ "synced_at": "2026-08-04T00:00:00Z"
50
+ }
@@ -1,22 +1,15 @@
1
1
  /**
2
2
  * Mipham Code — package metadata (bundled version)
3
3
  *
4
- * Reads directly from the CLI's own package.json at runtime
5
- * so npm consumers don't need the @mipham/shared workspace package.
4
+ * Compile-time constants (bundled into the compiled binary — no runtime
5
+ * package.json read). Version is synced by scripts/bump-version.sh.
6
6
  */
7
7
 
8
- import { readFileSync } from 'node:fs'
9
- import path from 'node:path'
10
-
11
- // resolve package.json relative to this source file
12
- const PKG_PATH = path.join(import.meta.dirname!, '..', '..', 'package.json')
13
- const pkg = JSON.parse(readFileSync(PKG_PATH, 'utf-8'))
14
-
15
8
  /** npm 包全名(含 scope) */
16
- export const PACKAGE_NAME: string = pkg.name
9
+ export const PACKAGE_NAME = '@miphamai/cli' as const
17
10
 
18
11
  /** 当前发布版本 */
19
- export const PACKAGE_VERSION: string = pkg.version
12
+ export const PACKAGE_VERSION = '0.40.0' as const
20
13
 
21
14
  /** npm install 全局安装命令 */
22
15
  export const NPM_INSTALL_COMMAND = `npm install -g ${PACKAGE_NAME}` as const