memory-eternal 0.10.48 → 0.10.50

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.
@@ -0,0 +1,72 @@
1
+ // 「模型不守 JSON」的记忆(issue #47)。
2
+ //
3
+ // 现场:stepfun / step-api 这类模型会把蒸馏请求当聊天回(「已读取并理解以下技能约束…」),
4
+ // 解析失败 → 轮换下一个 provider。问题是不记录,于是**每轮对话都要先白烧一次调用**。
5
+ // 这里把「哪个 provider/model 最近连续不守格式」记下来,选路时把它们排到候选末尾
6
+ // (不删除:万一全都命中过,仍按原顺序兜底,绝不把自己饿死)。
7
+ import fs from 'node:fs'
8
+ import { configFilePath } from './capture-run.js'
9
+
10
+ /** 打击记录文件:与共享配置同目录(<config>.llm-strikes.json)。 */
11
+ export function strikesPath(env = process.env) {
12
+ return String(configFilePath(env)).replace(/\.json$/i, '.llm-strikes.json')
13
+ }
14
+
15
+ /** 路由键:provider|model。 */
16
+ export function routeKey(route) {
17
+ return String((route && route.provider) || '') + '|' + String((route && route.model) || '')
18
+ }
19
+
20
+ function readAll(env) {
21
+ try {
22
+ const d = JSON.parse(fs.readFileSync(strikesPath(env), 'utf8'))
23
+ return d && typeof d === 'object' && d.strikes && typeof d.strikes === 'object' ? d.strikes : {}
24
+ } catch { return {} }
25
+ }
26
+
27
+ /** 记一次「不守 JSON」。只保留最近 50 个路由,避免文件无限增长。 */
28
+ export function recordModelStrike(env, route, code = 'MODEL_NOT_JSON', now = Date.now()) {
29
+ const key = routeKey(route)
30
+ if (!key || key === '|') return null
31
+ const all = readAll(env)
32
+ const prev = all[key] && typeof all[key] === 'object' ? all[key] : { count: 0, at: 0 }
33
+ all[key] = { count: (Number(prev.count) || 0) + 1, at: Number(now) || Date.now(), code: String(code || '') }
34
+ const keys = Object.keys(all)
35
+ if (keys.length > 50) {
36
+ keys.sort((a, b) => (Number(all[a].at) || 0) - (Number(all[b].at) || 0))
37
+ for (const k of keys.slice(0, keys.length - 50)) delete all[k]
38
+ }
39
+ try {
40
+ fs.mkdirSync(String(strikesPath(env)).replace(/[\\/][^\\/]+$/, ''), { recursive: true })
41
+ fs.writeFileSync(strikesPath(env), JSON.stringify({ version: 1, strikes: all }, null, 2), 'utf8')
42
+ return all[key]
43
+ } catch { return null }
44
+ }
45
+
46
+ /** 最近 window 内的打击次数(默认 24h)。 */
47
+ export function recentModelStrikes(env, { hours = 24, now = Date.now() } = {}) {
48
+ const all = readAll(env)
49
+ const cut = Number(now) - Math.max(1, Number(hours) || 24) * 3600 * 1000
50
+ const out = {}
51
+ for (const [key, v] of Object.entries(all)) {
52
+ const at = Number(v && v.at) || 0
53
+ if (at < cut) continue
54
+ const count = Number(v && v.count) || 0
55
+ if (count > 0) out[key] = count
56
+ }
57
+ return out
58
+ }
59
+
60
+ /**
61
+ * 纯函数:把「近期不守格式」的路由排到后面(稳定排序,阈值默认 2 次)。
62
+ * 全部命中过时保持原顺序(宁可慢一点,也不能没有候选)。
63
+ */
64
+ export function rankRoutesByStrikes(routes = [], strikes = {}, { threshold = 2 } = {}) {
65
+ const list = Array.isArray(routes) ? routes : []
66
+ const th = Math.max(1, Number(threshold) || 2)
67
+ const isBad = (r) => (Number(strikes[routeKey(r)]) || 0) >= th
68
+ const clean = list.filter((r) => !isBad(r))
69
+ const bad = list.filter(isBad)
70
+ if (!clean.length) return list.slice() // 全都命中过 → 原顺序兜底
71
+ return [...clean, ...bad]
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.10.48",
3
+ "version": "0.10.50",
4
4
  "description": "记忆核心(Memory Eternal):自研的 DeepSeek Harness 记忆插件,不移植任何既有记忆框架——对话结束后自动沉淀知识卡到本地 Markdown Vault(自研去重、自研 CJK 检索、可 git 管理),设置页提供图形化知识库(统计 / 搜索 / 知识图谱 + 侧边栏一键弹窗),Agent 通过 memory_recall 工具按需召回历史上下文。零人工干预。",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -65,7 +65,7 @@
65
65
  "release": "node scripts/release.mjs",
66
66
  "release:dry": "node scripts/release.mjs --dry-run",
67
67
  "panel-check": "node scripts/panel-check.mjs",
68
- "test": "node build.mjs && node tests/vault.test.mjs && node tests/capture.test.mjs && node tests/capture-route.test.mjs && node tests/stall.test.mjs && node tests/vault-path.test.mjs && node tests/vault-resolve.test.mjs && node tests/minhash.test.mjs && node tests/settings-save.test.mjs && node tests/config-coverage.test.mjs && node tests/config-sync.test.mjs && node tests/config-merge.test.mjs && node tests/sse.test.mjs && node tests/api.test.mjs && node tests/import-roundtrip.test.mjs && node tests/graph-perf.test.mjs && node tests/settings-compat.test.mjs && node tests/node-bin.test.mjs && node tests/watchdog-lock.test.mjs && node tests/markdown.test.mjs && node tests/feedback.test.mjs && node tests/graph-lod.test.mjs && node tests/ssr.test.mjs && node tests/web-assets.test.mjs && node tests/manifests.test.mjs && node tests/two-store.test.mjs && node tests/noise-gate.test.mjs && node tests/e2e-recall.test.mjs && node tests/issue-fixes.test.mjs && node tests/issue-fixes-2.test.mjs && node tests/issue-fixes-3.test.mjs && node tests/watchdog-orphans.test.mjs && node tests/watchdog-restart.test.mjs && node tests/readme-i18n.test.mjs && node tests/issue-fixes-4.test.mjs && node tests/host-drain.test.mjs && node tests/e2e-host-drain.mjs && node tests/issue-fixes-5.test.mjs && node tests/issue-fixes-6.test.mjs && node tests/capture-json-repair.test.mjs && node tests/csrf-origin.test.mjs && node tests/watchdog-orphan-web.test.mjs && node tests/config-validate.test.mjs && node tests/issue-fixes-8.test.mjs && node tests/issue-fixes-9.test.mjs && node tests/release-verify.test.mjs && node tests/refine.test.mjs && node tests/db-restore.test.mjs && node tests/align.test.mjs && node tests/tags-normalize.test.mjs && node tests/resident-state.test.mjs && node tests/llm-route.test.mjs && node tests/host-managed.test.mjs && node tests/replace-claim.test.mjs && node tests/version-check-self.test.mjs && node tests/setup-codex.test.mjs && node tests/listener-netstat.test.mjs && node tests/issue-46-overlay.test.mjs && node tests/graph-initial-zoom.test.mjs && node tests/card-head-actions.test.mjs && node tests/card-reader-ux.test.mjs && node tests/tag-filter.test.mjs && node tests/ui-overflow.test.mjs && node tests/version-card-state.test.mjs"
68
+ "test": "node build.mjs && node tests/vault.test.mjs && node tests/capture.test.mjs && node tests/capture-route.test.mjs && node tests/stall.test.mjs && node tests/vault-path.test.mjs && node tests/vault-resolve.test.mjs && node tests/minhash.test.mjs && node tests/settings-save.test.mjs && node tests/config-coverage.test.mjs && node tests/config-sync.test.mjs && node tests/config-merge.test.mjs && node tests/sse.test.mjs && node tests/api.test.mjs && node tests/import-roundtrip.test.mjs && node tests/graph-perf.test.mjs && node tests/settings-compat.test.mjs && node tests/node-bin.test.mjs && node tests/watchdog-lock.test.mjs && node tests/markdown.test.mjs && node tests/feedback.test.mjs && node tests/graph-lod.test.mjs && node tests/ssr.test.mjs && node tests/web-assets.test.mjs && node tests/manifests.test.mjs && node tests/two-store.test.mjs && node tests/noise-gate.test.mjs && node tests/e2e-recall.test.mjs && node tests/issue-fixes.test.mjs && node tests/issue-fixes-2.test.mjs && node tests/issue-fixes-3.test.mjs && node tests/watchdog-orphans.test.mjs && node tests/watchdog-restart.test.mjs && node tests/readme-i18n.test.mjs && node tests/issue-fixes-4.test.mjs && node tests/host-drain.test.mjs && node tests/e2e-host-drain.mjs && node tests/issue-fixes-5.test.mjs && node tests/issue-fixes-6.test.mjs && node tests/capture-json-repair.test.mjs && node tests/csrf-origin.test.mjs && node tests/watchdog-orphan-web.test.mjs && node tests/config-validate.test.mjs && node tests/issue-fixes-8.test.mjs && node tests/issue-fixes-9.test.mjs && node tests/release-verify.test.mjs && node tests/refine.test.mjs && node tests/db-restore.test.mjs && node tests/align.test.mjs && node tests/tags-normalize.test.mjs && node tests/resident-state.test.mjs && node tests/llm-route.test.mjs && node tests/host-managed.test.mjs && node tests/replace-claim.test.mjs && node tests/version-check-self.test.mjs && node tests/setup-codex.test.mjs && node tests/listener-netstat.test.mjs && node tests/issue-46-overlay.test.mjs && node tests/graph-initial-zoom.test.mjs && node tests/card-head-actions.test.mjs && node tests/card-reader-ux.test.mjs && node tests/tag-filter.test.mjs && node tests/ui-overflow.test.mjs && node tests/version-card-state.test.mjs && node tests/llm-routes-proxy.test.mjs && node tests/model-strikes.test.mjs"
69
69
  },
70
70
  "dependencies": {
71
71
  "@deepseek-ai/schemastery": "^3.18.1"