@furongjun1999/dsh-memory 0.7.4 → 0.7.5
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/README.md +631 -630
- package/codebuddy/CODEBUDDY.md +5 -5
- package/docs/discipline/templates/zcode-user.md.tmpl +4 -1
- package/docs/eval//345/217/221/345/270/20312_/344/270/226/347/225/214/346/250/241/345/236/213/345/212/237/350/203/275/347/253/257_v1.0.md +1 -1
- package/docs/eval//345/217/221/345/270/20313_/344/270/212/344/270/213/346/226/207/350/207/252/347/256/241/347/220/206/346/234/272/345/210/266_v1.0.md +114 -0
- package/docs/mdcg//347/235/241/347/234/240/345/221/250/346/234/237_/350/277/220/347/273/264/345/211/215/346/217/220/344/270/216/347/273/264/346/212/244/346/214/207/345/215/227_v1.0.md +80 -1
- package/docs/plans//347/201/265/346/236/242/350/272/253/344/275/223/303/227/350/204/221_/344/270/226/347/225/214/346/250/241/345/236/213/345/257/271/346/216/245/350/256/276/350/256/241_v0.1.md +76 -0
- package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +461 -461
- package/docs//350/256/260/345/277/206/347/263/273/347/273/237/345/215/263/347/231/275/347/256/261/345/214/226/346/231/272/350/203/275_/346/236/266/346/236/204/345/257/271/347/205/247_v0.2.md +121 -0
- package/docs//350/256/260/345/277/206/347/263/273/347/273/237/345/215/263/347/231/275/347/256/261/345/214/226/346/231/272/350/203/275_/346/236/266/346/236/204/345/257/271/347/205/247_v0.3.md +117 -0
- package/lib/hooks.d.ts +34 -0
- package/lib/hooks.js +165 -0
- package/lib/index.js +22 -1
- package/lib/lib/mdcg_client.d.ts +37 -0
- package/lib/lib/mdcg_client.js +44 -0
- package/md_cg/audit.py +7 -1
- package/md_cg/bench_governance.py +4 -1
- package/md_cg/bench_locomo_zh.py +12 -2
- package/md_cg/bench_zh_mad.py +12 -2
- package/md_cg/interop.py +25 -9
- package/md_cg/sleep.py +223 -103
- package/md_cg/sustain.py +150 -4
- package/md_cg/test_sustain_bounded.py +624 -0
- package/md_cg/units.py +4 -1
- package/package.json +1 -1
- package/skills/plugin.json +1 -1
- package/src/hooks.ts +177 -0
- package/src/index.ts +22 -1
- package/src/lib/mdcg_client.ts +48 -0
- package/zcode/AGENTS.md +5 -5
package/lib/lib/mdcg_client.js
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
* 外部裁决回填 → MdcgClient.verify() → MCP cg(op=verify)
|
|
20
20
|
* 最近记忆时间线 → MdcgClient.timeline() → MCP stg(op=timeline)
|
|
21
21
|
* 近期事件窗口 → MdcgClient.recent() → MCP cg(op=recent)
|
|
22
|
+
* 窗口追加事件 → MdcgClient.recentAdd() → MCP cg(op=recent, action=add)
|
|
23
|
+
* 会话续接包 → MdcgClient.sessionRecall() → MCP cg(op=session, action=recall)
|
|
22
24
|
* 身份读取 → MdcgClient.identity() → MCP cg(op=identity)
|
|
23
25
|
* 白箱能力验证 → MdcgClient.whitebox() → MCP cg(op=whitebox)
|
|
24
26
|
* 服务信息 → MdcgClient.serviceInfo()→ MCP cg(op=info)
|
|
@@ -215,6 +217,48 @@ export class MdcgClient {
|
|
|
215
217
|
recent(limit = 20) {
|
|
216
218
|
return this.cg({ op: 'recent', limit });
|
|
217
219
|
}
|
|
220
|
+
/** 追加一条**近期事件窗口**记录(`cg(op=recent, action=add)` →
|
|
221
|
+
* `md_cg` 的 `remember_event(role, text, tags, meta, window)`)。
|
|
222
|
+
*
|
|
223
|
+
* 这是「滑动窗口」写侧:事件落 `_recent.jsonl`(**运行态面**),按窗口滚动
|
|
224
|
+
* 淘汰(服务端缺省 200 条,`mdcg.py:91 DEFAULT_RECENT_WINDOW`)——它**不是
|
|
225
|
+
* 知识节点**:不占 knowledge 层、不进检索正排,与 `remember()` 的知识面沉淀
|
|
226
|
+
* 是两条独立的轨道(见 src/hooks.ts 文件头的 contextWindow 头注)。
|
|
227
|
+
*
|
|
228
|
+
* ⚠️ **不注入 as_unit**(与 `write()` 同款理由的反面):本调用不写任何层的
|
|
229
|
+
* 节点(服务端 `remember_event` 不做层白名单校验),收窄单元无收益且可能压低
|
|
230
|
+
* 事件密级(缺省 internal);`meta.session` 由调用方显式给出(沿本文件
|
|
231
|
+
* `remember()` 的 sessionTag 口径)。
|
|
232
|
+
*
|
|
233
|
+
* ⚠️ 服务端对 `meta` 做 `setdefault`(tenant/session/harness/unit,见
|
|
234
|
+
* `mdcos.py:5057 remember_event`):调用方已写的键**不被覆盖**。 */
|
|
235
|
+
recentAdd(role, text, meta = {}, tags = []) {
|
|
236
|
+
return this.cg({ op: 'recent', action: 'add', role, text, meta, tags });
|
|
237
|
+
}
|
|
238
|
+
/** **会话续接包**(`cg(op=session, action=recall)` → `md_cg` 的
|
|
239
|
+
* `session_recall`):一次取回 notes / goals / tasks / **recent 事件窗口** /
|
|
240
|
+
* unresolved / self_state,按 `budget_tokens` 整包裁剪(服务端
|
|
241
|
+
* `mdcos.py:3351-3362`:交替丢 recent / notes 尾部)。
|
|
242
|
+
*
|
|
243
|
+
* 本插件消费其中的 `recent` 段——滑动窗口的**注入面**(见 src/hooks.ts)。
|
|
244
|
+
* `recent_limit` 语义 = 近期事件**条数**(非「轮数」);服务端读取时会按
|
|
245
|
+
* `max(1, recent_limit or 10)` 归一(`mdcos.py:3309`)。
|
|
246
|
+
*
|
|
247
|
+
* ⚠️ 两条服务端事实(决定注入侧的可达性,勿据本方法名臆测):
|
|
248
|
+
* ① `recent` 段取 `recent_events(limit=recent_limit)` —— **不按 session
|
|
249
|
+
* 过滤**(近期事件是运行态滚动窗口,会话归属只写在每条事件的 meta 里);
|
|
250
|
+
* ② budget 是**整包**预算:库内 notes/tasks/self_state 占位越多,同样
|
|
251
|
+
* budget 下 recent 段被裁得越短(实测:空库 + 10 条窗口条目,
|
|
252
|
+
* budget_tokens=600 → recent 8 条;1200 → 10 条)。
|
|
253
|
+
*
|
|
254
|
+
* 只读调用,不注入 as_unit(同其它读路径:读无副作用,收窄只会压低 owner
|
|
255
|
+
* 的 private 读能力)。 */
|
|
256
|
+
sessionRecall(session, recentLimit, budgetTokens) {
|
|
257
|
+
return this.cg({
|
|
258
|
+
op: 'session', action: 'recall',
|
|
259
|
+
session, recent_limit: recentLimit, budget_tokens: budgetTokens,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
218
262
|
/** 最近记忆**时间线**(AEIS `timeline` 的对应物):`stg(op=timeline)` →
|
|
219
263
|
* `{count, limit, items:[{id, layer, start, end, preview}]}`,按时间倒序。
|
|
220
264
|
*
|
package/md_cg/audit.py
CHANGED
|
@@ -456,11 +456,17 @@ def _verify_code(payload, ctx):
|
|
|
456
456
|
# 被测命令只要输出非 gbk 字节,读取线程就抛 UnicodeDecodeError →
|
|
457
457
|
# p.stdout/p.stderr 可能为空 → 下一行的失败证据丢失,
|
|
458
458
|
# 「实测失败」会退化成一句没有依据的 REJECT(对齐 whitebox.py 的写法)。
|
|
459
|
+
# stdin=subprocess.DEVNULL(issue #63 同批加固):不指定 stdin 时子进程
|
|
460
|
+
# 继承父进程 stdin(常驻宿主下是 JSON-RPC 活管道),读 stdin 的测试
|
|
461
|
+
# 命令会悬挂到 timeout 才被 kill——形态对齐 `md_cg/run_tests.py:105`。
|
|
459
462
|
p = subprocess.run(argv, cwd=ctx.get("cwd"), capture_output=True,
|
|
460
463
|
text=True, encoding="utf-8", errors="replace",
|
|
461
|
-
shell=False,
|
|
464
|
+
shell=False, stdin=subprocess.DEVNULL,
|
|
462
465
|
timeout=int(os.environ.get("MDCG_CODE_TEST_TIMEOUT", "60")))
|
|
463
466
|
except (OSError, subprocess.SubprocessError) as exc:
|
|
467
|
+
# TimeoutExpired(SubprocessError 子类)也走这里:DEFER + 文案带异常
|
|
468
|
+
# 名与原文(如 "TimeoutExpired: Command '…' timed out after 60 seconds")
|
|
469
|
+
# ——超时**不吞**(issue #63)。
|
|
464
470
|
return _verdict(DEFER, "code", f"测试无法执行:{type(exc).__name__}: {exc}")
|
|
465
471
|
if p.returncode == 0:
|
|
466
472
|
return _verdict(ACCEPT, "code", f"实测通过:{cmd}")
|
|
@@ -315,9 +315,12 @@ def run(root=None, keep=False):
|
|
|
315
315
|
|
|
316
316
|
def _git_head():
|
|
317
317
|
try:
|
|
318
|
+
# timeout=10 既有;stdin=subprocess.DEVNULL 为 issue #63 同批加固——
|
|
319
|
+
# 不指定 stdin 时子进程继承父进程 stdin(常驻宿主下是 JSON-RPC 活管道)。
|
|
318
320
|
out = subprocess.run(["git", "rev-parse", "--short", "HEAD"],
|
|
319
321
|
capture_output=True, text=True, encoding="utf-8",
|
|
320
|
-
errors="replace", shell=False, timeout=10
|
|
322
|
+
errors="replace", shell=False, timeout=10,
|
|
323
|
+
stdin=subprocess.DEVNULL)
|
|
321
324
|
return (out.stdout or "").strip() or "unknown"
|
|
322
325
|
except Exception: # noqa: BLE001
|
|
323
326
|
return "unknown"
|
package/md_cg/bench_locomo_zh.py
CHANGED
|
@@ -303,6 +303,9 @@ ROW_RE = re.compile(
|
|
|
303
303
|
r"([\d.]+)%\s+([\d.]+)%\s+([\d.]+)\s*$", re.M)
|
|
304
304
|
GATE_RE = re.compile(r"拒答率:([\d.]+)%")
|
|
305
305
|
LINE_RE = re.compile(r"拒答线(正例 hit@1 题 Top-1 分 p10):([\d.]+)")
|
|
306
|
+
#: 单臂评测子进程的超时(秒)——issue #63 同批加固:评测跑批比 git 长,按
|
|
307
|
+
#: 「一臂为分钟级」给 1800s(30min)为安全上界;超时即 kill(不再是无限等待)。
|
|
308
|
+
_EVAL_TIMEOUT_S = 1800
|
|
306
309
|
|
|
307
310
|
|
|
308
311
|
# 生效条件:RUST_BIN 经 os.path.exists 为假时抛 SystemExit;否则以 argv 列表 [RUST_BIN, "--dataset", "lc", "--tag", name, "--lib", lib, "--qfile", qfile](extra 为真值时追加其元素)执行 subprocess.run,返回码非 0 或 stdout 未匹配 ROW_RE 时抛 SystemExit,成功时返回 (got, neg, line),其中 GATE_RE/LINE_RE 未命中时对应值为 None。
|
|
@@ -320,8 +323,15 @@ def run_one(name, lib, qfile, extra=None):
|
|
|
320
323
|
if extra:
|
|
321
324
|
argv += list(extra)
|
|
322
325
|
env = dict(os.environ, PYTHONUTF8="1")
|
|
323
|
-
|
|
324
|
-
|
|
326
|
+
try:
|
|
327
|
+
# timeout + stdin=DEVNULL(issue #63 同批加固):评测跑批有界化,
|
|
328
|
+
# 且不继承父进程 stdin(常驻宿主下是 JSON-RPC 活管道)。
|
|
329
|
+
p = subprocess.run(argv, capture_output=True, text=True,
|
|
330
|
+
encoding="utf-8", errors="replace", env=env, cwd=HERE,
|
|
331
|
+
timeout=_EVAL_TIMEOUT_S,
|
|
332
|
+
stdin=subprocess.DEVNULL)
|
|
333
|
+
except subprocess.TimeoutExpired:
|
|
334
|
+
raise SystemExit(f"[失败] {name}:评测超时(>{_EVAL_TIMEOUT_S}s)已被 kill")
|
|
325
335
|
if p.returncode != 0:
|
|
326
336
|
raise SystemExit(f"[失败] {name}:{(p.stderr or '')[-900:]}")
|
|
327
337
|
got = {}
|
package/md_cg/bench_zh_mad.py
CHANGED
|
@@ -481,6 +481,9 @@ ROW_RE = re.compile(
|
|
|
481
481
|
r"^\s*(precise|temporal|interference|reference)\s+(\d+)\s+"
|
|
482
482
|
r"([\d.]+)%\s+([\d.]+)%\s+([\d.]+)\s*$", re.M)
|
|
483
483
|
GROUPS = ["precise", "temporal", "interference", "reference"]
|
|
484
|
+
#: 单臂评测子进程的超时(秒)——issue #63 同批加固:评测跑批比 git 长,按
|
|
485
|
+
#: 「一臂为分钟级」给 1800s(30min)为安全上界;超时即 kill(不再是无限等待)。
|
|
486
|
+
_EVAL_TIMEOUT_S = 1800
|
|
484
487
|
|
|
485
488
|
|
|
486
489
|
# 生效条件:os.path.exists(RUST_BIN) 为真时以 argv=[RUST_BIN,"--dataset","mad","--tag",name,"--lib",lib](extra 为真值时追加 list(extra))执行 subprocess,返回码非 0 或 ROW_RE 在 stdout 未匹配到任何组时 raise SystemExit,否则返回 {组:(n,hit@1,hit@5,MRR)}。
|
|
@@ -498,8 +501,15 @@ def run_one(name, lib, extra=None):
|
|
|
498
501
|
if extra:
|
|
499
502
|
argv += list(extra)
|
|
500
503
|
env = dict(os.environ, PYTHONUTF8="1")
|
|
501
|
-
|
|
502
|
-
|
|
504
|
+
try:
|
|
505
|
+
# timeout + stdin=DEVNULL(issue #63 同批加固):评测跑批有界化,
|
|
506
|
+
# 且不继承父进程 stdin(常驻宿主下是 JSON-RPC 活管道)。
|
|
507
|
+
p = subprocess.run(argv, capture_output=True, text=True,
|
|
508
|
+
encoding="utf-8", errors="replace", env=env, cwd=HERE,
|
|
509
|
+
timeout=_EVAL_TIMEOUT_S,
|
|
510
|
+
stdin=subprocess.DEVNULL)
|
|
511
|
+
except subprocess.TimeoutExpired:
|
|
512
|
+
raise SystemExit(f"[失败] {name}:评测超时(>{_EVAL_TIMEOUT_S}s)已被 kill")
|
|
503
513
|
if p.returncode != 0:
|
|
504
514
|
raise SystemExit(f"[失败] {name}:{(p.stderr or '')[-900:]}")
|
|
505
515
|
got = {}
|
package/md_cg/interop.py
CHANGED
|
@@ -47,6 +47,11 @@ _FORBIDDEN_RES = [
|
|
|
47
47
|
]
|
|
48
48
|
_FORBIDDEN_KEYS = {"prompt", "content", "spec", "api_key", "base", "model",
|
|
49
49
|
"system_prompt", "user_prompt", "content_head"}
|
|
50
|
+
#: git add/commit 子进程的超时(秒)——issue #63 同批加固:本机 git 为秒级
|
|
51
|
+
#: 操作,120s 为安全上界;超时即 kill。**stdin=subprocess.DEVNULL 同加**:
|
|
52
|
+
#: 不指定 stdin 时子进程继承父进程 stdin(常驻宿主下是 JSON-RPC 活管道),
|
|
53
|
+
#: 读 stdin 的子进程会悬挂(先例形态 `md_cg/run_tests.py:105`)。
|
|
54
|
+
_GIT_TIMEOUT_S = 120
|
|
50
55
|
|
|
51
56
|
|
|
52
57
|
class InteropSanityError(ValueError):
|
|
@@ -323,15 +328,26 @@ def write_verdict_to_repo(verdict: dict, repo: str = HERE,
|
|
|
323
328
|
out = {"ok": True, "path": fp}
|
|
324
329
|
if do_commit:
|
|
325
330
|
import subprocess
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
331
|
+
try:
|
|
332
|
+
r1 = subprocess.run(["git", "add", os.path.relpath(fp, repo)],
|
|
333
|
+
cwd=repo, capture_output=True, text=True,
|
|
334
|
+
encoding="utf-8", errors="replace",
|
|
335
|
+
timeout=_GIT_TIMEOUT_S,
|
|
336
|
+
stdin=subprocess.DEVNULL)
|
|
337
|
+
r2 = subprocess.run(
|
|
338
|
+
["git", "commit", "-q", "-m",
|
|
339
|
+
f"interop(verifier): iter={it} verdict={verdict.get('verdict')} "
|
|
340
|
+
f"passed={verdict.get('passed')} failed={verdict.get('failed')}"],
|
|
341
|
+
cwd=repo, capture_output=True, text=True,
|
|
342
|
+
encoding="utf-8", errors="replace",
|
|
343
|
+
timeout=_GIT_TIMEOUT_S, stdin=subprocess.DEVNULL)
|
|
344
|
+
except subprocess.TimeoutExpired:
|
|
345
|
+
# 超时**不吞**:如实记进既有错误面(与 rc≠0 同一条 commit_err),
|
|
346
|
+
# 不假装提交成功(issue #63)。
|
|
347
|
+
out["committed"] = False
|
|
348
|
+
out["commit_err"] = ("git 超时(%ss)已被 kill:%s" %
|
|
349
|
+
(_GIT_TIMEOUT_S, out_dir))
|
|
350
|
+
return out
|
|
335
351
|
out["committed"] = r2.returncode == 0
|
|
336
352
|
if r2.returncode != 0:
|
|
337
353
|
out["commit_err"] = (r2.stderr or r1.stderr)[:200]
|