dsh-memory-tiers 0.5.1 → 0.8.2

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/silicon.mjs CHANGED
@@ -43,8 +43,9 @@ import { readFileSync } from 'node:fs'
43
43
  const DEFAULTS = {
44
44
  apiKey: '',
45
45
  base: DEFAULT_BASE,
46
- embedModel: 'Qwen/Qwen3-Embedding-0.6B',
47
- rerankModel: 'Qwen/Qwen3-Reranker-0.6B',
46
+ // 默认就是硅基流动上那两个免费的:中文够用,换 embed 记得跑一次 reindex
47
+ embedModel: 'BAAI/bge-m3',
48
+ rerankModel: 'BAAI/bge-reranker-v2-m3',
48
49
  chatModel: 'inclusionAI/Ling-mini-2.0', // 高频轻任务
49
50
  summaryModel: 'deepseek-ai/DeepSeek-V4.1-Flash', // 低频重任务
50
51
  timeoutMs: 20000,
@@ -334,19 +335,31 @@ export function createSilicon(options = {}) {
334
335
  const base = String(over.base || cfg.base || '').replace(/\/+$/, '')
335
336
  const apiKey = over.apiKey || cfg.apiKey || ''
336
337
  const model = over.model || cfg[name + 'Model'] || ''
338
+ // source: 'session' = 走 dsh 当前会话模型(不用我们的 key);'api' = 走 HTTP
339
+ const source = sessionStages.has(name) ? 'session' : 'api'
337
340
  return {
338
341
  base,
339
342
  apiKey,
340
343
  model,
344
+ source,
345
+ sessionModel: source === 'session' ? (session?.model || null) : null,
341
346
  chat: base + '/chat/completions',
342
347
  embed: base + '/embeddings',
343
348
  rerank: base + '/rerank',
344
349
  }
345
350
  }
346
351
 
347
- // 只要任意一个阶段拿到了 key 就能跑;全部为空才认为没配(由调用方降级到本地哈希向量)
352
+ // 只要任意一个阶段拿到了 key 就能跑;全部为空才认为没配(由调用方降级到关键词检索)
348
353
  const anyKey = cfg.apiKey || STAGES.some((s) => cfg.models?.[s]?.apiKey)
349
- if (!anyKey) throw new Error('[silicon] 缺少 apiKey(顶层或某个阶段的 models[s].apiKey)')
354
+
355
+ // 会话模型通道:这些阶段的请求改走 dsh 当前会话模型,不用我们的 key。
356
+ // 传法:{ session: { call, stages: ['chat','summary'] } }
357
+ // 没传、或调用失败,都安静回落 HTTP。
358
+ const session = options.session && typeof options.session.call === 'function' ? options.session : null
359
+ const sessionStages = new Set(Array.isArray(session?.stages) ? session.stages : [])
360
+ const log = typeof options.onFallback === 'function' ? options.onFallback : null
361
+
362
+ if (!anyKey && !session) throw new Error('[silicon] 缺少 apiKey(顶层或某个阶段的 models[s].apiKey),且没有会话模型通道')
350
363
 
351
364
  const chatUrl = `${cfg.base.replace(/\/+$/, '')}/chat/completions`
352
365
  const embedUrl = `${cfg.base.replace(/\/+$/, '')}/embeddings`
@@ -434,19 +447,46 @@ export function createSilicon(options = {}) {
434
447
  stage: stageName = 'chat',
435
448
  model,
436
449
  timeout = cfg.timeoutMs,
437
- thinking = false,
450
+ thinking,
438
451
  } = opts
439
452
 
440
453
  const st = stage(stageName)
441
454
  const useModel = model || st.model
442
455
 
456
+ // 关思考:调用方没明说时按 cfg.noThink[stage],默认 chat 关(判关系只要一个词)、
457
+ // summary 默认不关(要它想清楚再压)。
458
+ const noThink = thinking === undefined ? cfg.noThink?.[stageName] !== false : thinking === false
459
+
460
+ // ★ 该阶段配置成"走会话模型"时,改用 dsh 自己的模型通道(不用我们的 key)。
461
+ // 失败(没拿到服务 / 流式报错 / 空输出)一律安静回落 HTTP,不影响主流程。
462
+ if (session?.call && sessionStages.has(stageName)) {
463
+ try {
464
+ const out = await session.call({
465
+ system,
466
+ user,
467
+ maxTokens,
468
+ temperature,
469
+ disableThinking: noThink,
470
+ timeoutMs: timeout,
471
+ })
472
+ const text = (typeof out === 'string' ? out : out?.text || '').trim()
473
+ if (text) {
474
+ note(stageName, 0, `session:${out?.model || useModel}`)
475
+ return text
476
+ }
477
+ log?.('会话模型返回空,回落 HTTP:%s', stageName)
478
+ } catch (err) {
479
+ log?.('会话模型调用失败,回落 HTTP(%s):%s', stageName, err?.message ?? err)
480
+ }
481
+ }
482
+
443
483
  const body = {
444
484
  model: useModel,
445
485
  messages: [{ role: 'system', content: system }, { role: 'user', content: user }],
446
486
  max_tokens: maxTokens,
447
487
  temperature,
448
488
  }
449
- if (thinking === false) body.enable_thinking = false
489
+ if (noThink) body.enable_thinking = false
450
490
 
451
491
  // ★ 用该阶段自己的 url / key:摘要可以挂到另一家 provider 上
452
492
  const d = await post(st.chat, st.apiKey, body, timeout, cfg.retries, cfg.maxConcurrent, cfg.rateLimitRetries, cfg.rateLimitBaseMs, guard)
@@ -673,7 +713,7 @@ export function createSilicon(options = {}) {
673
713
  ' + 不用写摘要 —— 有信息量、值得留着以后查的(约定、数字、人名、时间地点)。',
674
714
  '',
675
715
  '★ 应该是少数,大部分值得写摘要的用 · 就行。',
676
- '**+ 也是少数(约二三成)**:只有真有信息量的才标,进了缓冲层比流水账留得久。',
716
+ '**+ 要少(约一到两成,宁少勿多)**:只有真有信息量的才标,进了缓冲层比流水账留得久。',
677
717
  '打招呼、语气词、闲聊碎语、当下状态这些不重要的**不要标 +**,它们落进流水账、',
678
718
  '很快忘掉是正常的,别什么都往缓冲层塞。',
679
719
  '《》里填这条摘要依据了原文的哪几个编号,逗号分隔,连续的可以写成 1-3。',
@@ -872,6 +912,7 @@ export function createSilicon(options = {}) {
872
912
  '你判断两条记忆的关系,只输出一个词。',
873
913
  '',
874
914
  'duplicate 同一件事,只是措辞不同。「别发表情」和「不要发表情包」',
915
+ ' 同一条规则被重复强调也算 duplicate(哪怕措辞、语气、补充细节不同)',
875
916
  'contradiction 后一条推翻了前一条。「别发表情」和「多发表情」',
876
917
  'update 后一条是前一条的进展或补充,不冲突。',
877
918
  ' 「Dice 0.86」和「Dice 涨到 0.88」不是矛盾,是进展。',
@@ -924,7 +965,14 @@ export function createSilicon(options = {}) {
924
965
  /** 给设置页/诊断用:某阶段最终解析成什么 */
925
966
  resolveStage: (name) => {
926
967
  const st = stage(name)
927
- return { base: st.base, model: st.model, hasKey: !!st.apiKey }
968
+ return {
969
+ base: st.base,
970
+ model: st.model,
971
+ hasKey: !!st.apiKey,
972
+ // 'session' = 走 dsh 当前会话模型(不用我们的 key);'api' = 走 HTTP
973
+ source: st.source,
974
+ sessionModel: st.sessionModel,
975
+ }
928
976
  },
929
977
  stages: () => STAGES,
930
978
  }