@a9i5k4/dsh-auto-memory 2.1.6 → 2.1.8

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/lib/client.js CHANGED
@@ -147,7 +147,7 @@ window.__ModuleLoader__.load({
147
147
  storageScanHint: '语料健康 = 逐源比对索引(sidecar)与正文的 digest。手动改动记忆文件后索引会失配,该记忆会退出检索直到重建索引。',
148
148
  storageDeleteHint: '删除记忆 = 正文原子删除 + 在途唤起包清理 + 派生事实撤销(三联动)。已产生的 seen 证据不改写。',
149
149
  secSemantic: '自动记忆引擎', semMode: '检索模式', semAuto: '自动(推荐)', semLexOnly: '仅词法', semJs: '内置语义', semPy: '高级 Python',
150
- pyWizTitle: 'Python 引擎一键安装', pyWizStep1: '① 检测 Python 环境', pyWizStep2: '② 创建独立虚拟环境(~/.dsh/python-engine/.venv,不污染系统)', pyWizStep3: '③ 安装引擎依赖(fastembed + onnxruntime)', pyWizStep4: '④ 下载 BGE-M3 int8 模型(~539MB,断点续传,失败自动换源)',
150
+ pyWizTitle: 'Python 引擎一键安装', pyWizStep1: '① 检测 Python 环境', pyWizStep2: '② 创建独立虚拟环境(~/.dsh/python-engine/.venv,不污染系统)', pyWizStep3: '③ 安装引擎依赖(transformers + onnxruntime + torch)', pyWizStep4: '④ 下载 BGE-M3 int8 模型(~539MB,断点续传,失败自动换源)',
151
151
  pyWizDetect: '开始检测', pyWizRedetect: '重新检测', pyWizCreate: '创建虚拟环境', pyWizInstall: '安装依赖', pyWizDownload: '开始下载', pyWizCancel: '取消下载', pyWizDone: '全部就绪 ✓ — 回上方启用即可', pyWizOk: 'ok', pyWizMissing: '未找到', pyWizTooOld: '版本不兼容(需 3.9-3.12)', pyWizVenvRec: '推荐', pyWizEta: '剩余', pyWizSec: '秒', pyWizModelHint: '模型与虚拟环境安装在 ~/.dsh/python-engine/(用户目录),升级/重装插件不受影响。',
152
152
  semModeHint: '自动=内置语义就绪即用,否则词法保底;高级 Python 需另行安装。',
153
153
  fAssocEngine: '启用自动记忆引擎', fAssocEngineHint: '总开关。开启后自动观测上下文、语义检索并适时唤起记忆注入(消费少量 token)。关闭则整个引擎不运行——不检索、不判定、不注入、不生成唤起记录。介意 token 消耗或担心动作跑偏的用户可关闭。默认关。',
@@ -286,7 +286,7 @@ window.__ModuleLoader__.load({
286
286
  storageScanHint: 'Corpus health = compare each source\'s index (sidecar) against its body digest. After you hand-edit a memory file the index no longer matches, and that memory drops out of retrieval until the index is rebuilt.',
287
287
  storageDeleteHint: 'Delete = atomic body removal + in-flight activation purge + derived-fact revocation (cascading). Evidence already recorded (seen) is never rewritten.',
288
288
  secSemantic: 'Semantic engine', semMode: 'Retrieval mode', semAuto: 'Auto (recommended)', semLexOnly: 'Lexical only', semJs: 'Built-in semantic', semPy: 'Advanced Python',
289
- pyWizTitle: 'One-click Python engine setup', pyWizStep1: '1. Detect Python environment', pyWizStep2: '2. Create isolated venv (~/.dsh/python-engine/.venv, system untouched)', pyWizStep3: '3. Install engine deps (fastembed + onnxruntime)', pyWizStep4: '4. Download BGE-M3 int8 model (~539MB, resumable, auto mirror failover)',
289
+ pyWizTitle: 'One-click Python engine setup', pyWizStep1: '1. Detect Python environment', pyWizStep2: '2. Create isolated venv (~/.dsh/python-engine/.venv, system untouched)', pyWizStep3: '3. Install engine deps (transformers + onnxruntime + torch)', pyWizStep4: '4. Download BGE-M3 int8 model (~539MB, resumable, auto mirror failover)',
290
290
  pyWizDetect: 'Detect', pyWizRedetect: 'Re-detect', pyWizCreate: 'Create venv', pyWizInstall: 'Install deps', pyWizDownload: 'Start download', pyWizCancel: 'Cancel download', pyWizDone: 'All ready - enable it above', pyWizOk: 'ok', pyWizMissing: 'not found', pyWizTooOld: 'incompatible (need 3.9-3.12)', pyWizVenvRec: 'recommended', pyWizEta: 'eta', pyWizSec: 's', pyWizModelHint: 'Model and venv live in ~/.dsh/python-engine/ (user dir) - plugin upgrades never touch them.',
291
291
  fAssocEngine: 'Enable automatic memory engine', fAssocEngineHint: 'Master switch. On = auto-observe context, semantic retrieval, and timely memory-activation injection (costs a little token). Off = the whole engine stops — no retrieval, no decide, no injection, no activation records. For users concerned about token cost or off-course actions. Default off.',
292
292
  secMemoryHubHint: 'Memory Hub = the orchestrator for three memory layers (episodic / semantic / procedural). When on, it distills episodes from dialogue, solidifies facts, and turns repeatedly-successful workflows into skills that are auto-recalled in similar contexts.',
@@ -1223,6 +1223,17 @@ window.__ModuleLoader__.load({
1223
1223
  var pollPair = useState(null)
1224
1224
  var poll = pollPair[0]
1225
1225
  var setPoll = pollPair[1]
1226
+ var gpuPair = useState(function () { try { return localStorage.getItem('dsh-auto-memory.pyGpu') === '1' } catch (eG) { return false } })
1227
+ var gpuPref = gpuPair[0]
1228
+ var setGpuPref = function (v) {
1229
+ gpuPair[1](v)
1230
+ try { localStorage.setItem('dsh-auto-memory.pyGpu', v ? '1' : '0') } catch (eG) {}
1231
+ }
1232
+ var actGpu = function () {
1233
+ if (busy) return
1234
+ setBusy(true)
1235
+ apiPost(API.pyDeps, { gpu: gpuPref }).then(function (d) { setData(d); setBusy(false); setPoll(true); var ph = d && d.phase; if (ph === 'ready' || ph === 'error' || ph === 'idle') setPoll(false) }).catch(function () { setBusy(false); setPoll(false) })
1236
+ }
1226
1237
  var refresh = function () { apiGet(API.pyStatus).then(function (d) { if (d) setData(d) }).catch(function () {}) }
1227
1238
  useEffect(function () {
1228
1239
  var alive = true
@@ -1267,7 +1278,11 @@ window.__ModuleLoader__.load({
1267
1278
  stepRow(t('pyWizStep2'), data.venvOk ? true : 'run',
1268
1279
  (!data.venvOk && (data.pythons || []).some(function (p2) { return p2.status === 'ok' && !p2.isVenv })) ? h('button', Object.assign({}, btnCls, { onClick: function () { act(API.pyVenv, true) } }), t('pyWizCreate')) : null),
1269
1280
  stepRow(t('pyWizStep3'), data.depsOk ? true : 'run',
1270
- (data.venvOk && !data.depsOk) ? h('button', Object.assign({}, btnCls, { onClick: function () { act(API.pyDeps, true) } }), t('pyWizInstall')) : null),
1281
+ (data.venvOk && !data.depsOk) ? h('span', { style: { display: 'flex', gap: '8px', alignItems: 'center' } },
1282
+ h('label', { style: { display: 'flex', gap: '4px', alignItems: 'center', fontSize: 'calc(10.5px * var(--dam-scale))' } },
1283
+ h('input', { type: 'checkbox', checked: gpuPref, onChange: function (e) { setGpuPref(e.target.checked) } }),
1284
+ locale === 'zh' ? 'GPU 推理(NVIDIA,需已装 CUDA;否则自动回退 CPU)' : 'GPU inference (NVIDIA + CUDA; auto-falls back to CPU)'),
1285
+ h('button', Object.assign({}, btnCls, { onClick: function () { actGpu() } }), t('pyWizInstall'))) : null),
1271
1286
  stepRow(t('pyWizStep4'), data.modelReady ? true : 'run',
1272
1287
  (!data.modelReady && !dlActive) ? h('button', Object.assign({}, btnCls, { onClick: function () { act(API.pyModel, true) } }), t('pyWizDownload')) : null,
1273
1288
  dlActive ? h('button', { 'data-dam-btn': '', onClick: function () { apiPost(API.pyCancel, {}).then(refresh).catch(function () {}) } }, t('pyWizCancel')) : null),
@@ -3421,7 +3436,7 @@ window.__ModuleLoader__.load({
3421
3436
  h('option', { value: 'auto' }, t('mAuto')),
3422
3437
  h('option', { value: 'cn' }, t('mCn')),
3423
3438
  h('option', { value: 'intl' }, t('mIntl'))) : null,
3424
- ready ? h('button', { 'data-dam-btn': '', onClick: function () { setGuide(''); var n2 = Object.assign({}, cfg); n2.semanticEngineMode = guide; if (guide === 'js') { n2.activationSource = 'js'; n2.contextSinkMode = 'null' } else if (guide === 'python') { n2.activationSource = 'python'; n2.contextSinkMode = 'python' } setCfg(n2); setDirty(true) } }, locale === 'zh' ? '启用并继续' : 'Enable & continue') : null,
3439
+ ready ? h('button', { 'data-dam-btn': '', onClick: function () { setGuide(''); var n2 = Object.assign({}, cfg); n2.semanticEngineMode = guide; if (guide === 'js') { n2.activationSource = 'js'; n2.contextSinkMode = 'null' } else if (guide === 'python') { n2.activationSource = 'python'; n2.contextSinkMode = 'python'; try { var gp = localStorage.getItem('dsh-auto-memory.pyGpu'); if (gp === '1') n2.pythonGpu = true } catch (eL) {} } setCfg(n2); setDirty(true) } }, locale === 'zh' ? '启用并继续' : 'Enable & continue') : null,
3425
3440
  !ready && isJs && !dlActive ? h('button', { 'data-dam-btn': '', onClick: startDl }, (dl.phase === 'error' || dl.phase === 'cancelled') ? t('semDlRetry') : t('semDlStart')) : null,
3426
3441
  !ready && isJs && dlActive ? h('button', { 'data-dam-btn': '', onClick: cancelDl }, t('semDlCancel')) : null,
3427
3442
  h('button', { 'data-dam-btn': '', onClick: function () { setGuide('') } }, t('gotIt'))))
package/lib/index.js CHANGED
@@ -5458,7 +5458,8 @@ export function apply(ctx, config) {
5458
5458
  handler: async (req, res) => {
5459
5459
  if (!isLoopbackRequest(req)) return writeJson(res, 403, { error: 'forbidden: loopback-only' })
5460
5460
  if ((req.method || 'POST') !== 'POST') return writeJson(res, 405, { error: 'method not allowed' })
5461
- try { writeJson(res, 200, await engine._pythonSetup.ensureDeps()) } catch (e) { writeJson(res, 500, { error: String(e && e.message || e) }) }
5461
+ const body = await readJsonBody(req).catch(() => ({}))
5462
+ try { writeJson(res, 200, await engine._pythonSetup.ensureDeps({ gpu: !!(body && body.gpu) })) } catch (e) { writeJson(res, 500, { error: String(e && e.message || e) }) }
5462
5463
  },
5463
5464
  },
5464
5465
  {
@@ -4,7 +4,7 @@
4
4
  * 四步链路(全部走本模块,UI 只管展示状态与点击):
5
5
  * ①detect — 探测系统 Python(≥3.9)/既有 venv/模型本体;全部只读。
6
6
  * ②venv — python -m venv <userDir>/python-engine/.venv(幂等:已存在直接跳过)。
7
- * ③deps — venv 内 pip 安装运行依赖(fastembed/onnxruntime,清华镜像兜底)。
7
+ * ③deps — venv 内 pip 安装运行依赖(transformers/onnxruntime/torch,清华镜像兜底)。
8
8
  * ④model — BGE-M3 int8(~539MB)下载到 <userDir>/python-engine/models/,
9
9
  * cn(hf-mirror)/intl(hf 官方)双通道+SHA256 校验,复用 JS 档下载器的状态机形态。
10
10
  *
@@ -35,8 +35,9 @@ const MODEL_SPEC = {
35
35
  ],
36
36
  }
37
37
 
38
- /** venv 内 pip 依赖(语义引擎最小集;transformers 栈换成 fastembed=纯 onnxruntime,免 torch)。 */
39
- const PIP_DEPS = ['fastembed', 'onnxruntime']
38
+ /** venv 内 pip 依赖:#19 实测(int8 档 encode_ids 全程 numpy+onnxruntime,tokenizer 走 Rust 快速路径)——基础集无 torch,venv 体积 ~400MB。GPU 推理开关追加 onnxruntime-gpu(CUDAExecutionProvider)。池化/精度契约冻结自 R@5 0.925 基线,fastembed 注册表无 BGE-M3 且池化契约不同,不可用。 */
39
+ const PIP_DEPS_CPU = ['transformers', 'onnxruntime']
40
+ const PIP_DEPS_GPU_EXTRA = ['onnxruntime-gpu']
40
41
 
41
42
  export function createPythonSetupPre(opts = {}) {
42
43
  const dshHomeOf = typeof opts.dshHome === 'function' ? opts.dshHome : () => opts.dshHome || path.join(homedir(), '.dsh')
@@ -99,7 +100,7 @@ export function createPythonSetupPre(opts = {}) {
99
100
  }
100
101
  // 既有成果快照
101
102
  st.venvOk = existsSync(venvPython())
102
- st.depsOk = st.venvOk ? (await probe(venvPython(), ['-c', 'import fastembed, onnxruntime; print("deps-ok")'])).ok : false
103
+ st.depsOk = st.venvOk ? (await probe(venvPython(), ['-c', 'import transformers, onnxruntime, torch; print("deps-ok")'])).ok : false
103
104
  st.modelReady = existsSync(modelPath())
104
105
  st.pythons = out
105
106
  st.phase = 'idle'
@@ -110,7 +111,7 @@ export function createPythonSetupPre(opts = {}) {
110
111
  return {
111
112
  phase: st.phase, error: st.error,
112
113
  pythons: st.pythons, chosenPython: st.chosenPython,
113
- venvOk: st.venvOk, depsOk: st.depsOk, modelReady: st.modelReady,
114
+ venvOk: st.venvOk, depsOk: st.depsOk, modelReady: st.modelReady, wantGpu: !!st.wantGpu,
114
115
  modelPath: modelPath(), venvPython: venvPython(),
115
116
  modelBytes: st.modelReady ? statSync(modelPath()).size : 0, modelExpectedBytes: MODEL_SPEC.bytes,
116
117
  dl: { ...st.dl },
@@ -136,14 +137,17 @@ export function createPythonSetupPre(opts = {}) {
136
137
  return snapshot()
137
138
  }
138
139
 
139
- /** ③deps:venv 内 pip 装 fastembed+onnxruntime;官方源失败切清华镜像。 */
140
- async function ensureDeps() {
140
+ /** ③deps:venv 内 pip 装 transformers+onnxruntime(CPU 基础集);opts.gpu=true 追加 onnxruntime-gpu(用户选 GPU 推理时)。官方源失败切清华镜像。 */
141
+ async function ensureDeps(opts2) {
142
+ const wantGpu = !!(opts2 && opts2.gpu)
141
143
  if (!st.venvOk) { st.error = 'venv 未就绪,先执行 venv 步骤'; st.phase = 'error'; return snapshot() }
142
144
  st.phase = 'deps'
145
+ st.wantGpu = wantGpu
146
+ const deps = PIP_DEPS_CPU.concat(wantGpu ? PIP_DEPS_GPU_EXTRA : [])
143
147
  const runPip = async (extra) => {
144
148
  try {
145
- const r = await execFileP(venvPython(), ['-m', 'pip', 'install', '--quiet'].concat(PIP_DEPS).concat(extra || []),
146
- { timeout: 600000, windowsHide: true, maxBuffer: 4 * 1024 * 1024 })
149
+ const r = await execFileP(venvPython(), ['-m', 'pip', 'install', '--quiet'].concat(deps).concat(extra || []),
150
+ { timeout: 900000, windowsHide: true, maxBuffer: 4 * 1024 * 1024 })
147
151
  return { ok: true }
148
152
  } catch (e) { return { ok: false, tail: String((e && (e.stderr || e.message)) || e).slice(-300) } }
149
153
  }
@@ -151,7 +155,18 @@ export function createPythonSetupPre(opts = {}) {
151
155
  if (!r.ok) r = await runPip(['-i', 'https://pypi.tuna.tsinghua.edu.cn/simple'])
152
156
  st.depsOk = !!r.ok
153
157
  if (!r.ok) { st.error = '依赖安装失败: ' + (r.tail || ''); st.phase = 'error'; return snapshot() }
154
- diagOf('python-setup: deps installed into venv')
158
+ // GPU 偏好写入 embedding-config.json(worker 读 config['gpu'] 选 CUDA/CPU provider;read-modify-write 不覆盖既有键)
159
+ try {
160
+ const cfgDir = path.join(dshHomeOf(), 'memory', 'semantic')
161
+ mkdirSync(cfgDir, { recursive: true })
162
+ const cfgPath = path.join(cfgDir, 'embedding-config.json')
163
+ let cfg = {}
164
+ try { cfg = JSON.parse(await readFile(cfgPath, 'utf8')) } catch (_) {}
165
+ if (!cfg || typeof cfg !== 'object') cfg = {}
166
+ cfg.gpu = wantGpu
167
+ await writeFile(cfgPath, JSON.stringify(cfg, null, 2), 'utf8')
168
+ } catch (eCfg) { diagOf('python-setup: gpu pref write failed: ' + String(eCfg && eCfg.message || eCfg)) }
169
+ diagOf('python-setup: deps installed into venv (gpu=' + wantGpu + ')')
155
170
  return snapshot()
156
171
  }
157
172
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@a9i5k4/dsh-auto-memory",
3
3
  "description": "Proactive associative memory for DSH: zero-prompt recall injected before the model speaks, three-layer auto-consolidation, skill crystallization, and Astra-style context management - handoff ledgers, PLAN whiteboard, water-level sensing. Local-first, model-agnostic, zero deps. 主动联想记忆+Astra 式上下文管理:自动唤回/自动沉淀/技能固化/交接账本与白板跨窗口续命/水位感知。",
4
- "version": "2.1.6",
4
+ "version": "2.1.8",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {