@furongjun1999/dsh-memory 0.4.7 → 0.4.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/README.md +92 -37
- package/codebuddy/CODEBUDDY.md +195 -185
- package/docs/Pi/345/217/257/345/255/246/344/271/240/344/274/230/347/202/271_/347/201/265/346/236/242/345/244/247/350/204/221/346/224/271/350/277/233/344/272/244/346/216/245_20260915.md +144 -0
- package/docs/README.md +111 -0
- package/docs/discipline/harnesses.yaml +215 -152
- package/docs/discipline/templates/full.md.tmpl +60 -58
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.md +127 -0
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.png +0 -0
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_/347/201/265/346/236/242_vs_dejavu_/347/273/237/344/270/200/350/257/204/345/210/206_v7.md +202 -0
- package/docs/experiments/m4-role-probe/census.py +86 -0
- package/docs/experiments/m4-role-probe/probe.py +89 -0
- package/docs/experiments/mapped_confidence/bench_mapped_conf.py +216 -0
- package/docs/experiments/mapped_confidence/post_check.py +75 -0
- package/docs/experiments/mapped_confidence/repro_thirdparty_tol.py +83 -0
- package/docs/experiments/mapped_confidence/result_mapped_conf.json +215 -0
- package/docs/{ → hive/}/350/234/202/345/267/242/345/267/245/344/275/234/350/256/260/345/277/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +14 -2
- package/docs/{README → mdcg/README}/350/257/246/347/273/206/347/211/210_v0.4.5.md +9 -9
- package/docs/{ → mdcg/}/344/270/273/344/273/243/347/220/206/345/255/220/344/273/243/347/220/206/350/256/260/345/277/206/346/236/266/346/236/204/350/256/276/350/256/241.md +1 -1
- package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +261 -0
- package/docs/{ → mdcg/}/345/215/225/345/205/203/350/207/252/346/210/221/351/224/232/347/202/271_/347/263/273/347/273/237/346/217/220/347/244/272/350/257/215/346/240/207/345/207/206_v0.3.md +1 -1
- package/docs/mdcg//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/206_v0.4.md +148 -0
- package/docs/{ → mdcg/}/346/272/220/347/240/201/347/272/247/346/236/266/346/236/204/345/256/241/350/256/241_GPT/346/211/271/350/257/204/345/257/271/347/205/247_v1.0.md +2 -2
- package/docs/{ → mdcg/}/347/201/265/346/236/242/344/270/211/345/261/202/346/213/206/345/210/206/350/247/204/345/210/222_v0.1.md +181 -181
- package/docs/{ → mdcg/}/347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +2 -2
- package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_G4-G8/347/274/272/345/217/243/350/243/201/345/256/232/345/215/225_v0.1.md +1 -1
- package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +4 -4
- package/docs/{ → mdcg/}/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_MdCGOS/344/270/216MCP/346/216/245/345/205/245_v0.1.md +2 -2
- package/docs/plans/GridWorld/346/234/200/345/260/217/351/227/255/347/216/257/350/247/204/346/240/274_v0.1.md +176 -0
- package/docs/{ → swarm/}/350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +3 -3
- package/docs/swarm//350/234/202/347/276/244/345/220/214/351/224/231/346/243/200/346/265/213/345/256/236/351/252/214/345/215/217/350/256/256_v0.1.md +242 -0
- package/docs/theory//345/215/225/347/272/277/347/250/213/344/270/216/346/263/250/346/204/217/345/212/233/351/233/206/344/270/255_/346/227/240/344/272/211/350/256/256/347/220/206/350/256/272/346/226/207/346/241/243_v1.0.md +129 -0
- package/docs/theory//345/271/266/345/217/221/345/277/205/347/204/266/346/200/247/347/220/206/350/256/272_v0.2.md +134 -0
- package/docs/theory//346/246/202/345/277/265/345/210/206/345/261/202/345/257/271/351/275/220/350/241/250_v0.1.md +145 -0
- package/docs/{ → theory/}/347/220/206/350/256/272_/346/234/272/345/210/266_/344/273/243/347/240/201_/345/256/236/351/252/214_/347/274/272/345/217/243/347/237/251/351/230/265_v0.1.md +3 -3
- package/docs/{ → theory/}/347/220/206/350/256/272/344/273/223/346/213/206/345/210/206/344/270/216/347/231/275/347/256/261/347/237/245/350/257/206/345/272/223/345/206/205/350/277/201_v0.1.md +1 -1
- package/docs/theory//350/256/244/347/237/245/344/273/243/347/220/206/344/270/216/346/224/266/346/225/233/347/273/223/346/236/204_/346/235/241/344/273/266/350/256/272/351/207/215/346/236/204_v0.1.md +221 -0
- package/docs/world_model//344/270/226/347/225/214/346/250/241/345/236/213_/347/245/236/347/273/217/347/275/221/347/273/234/345/272/225/345/261/202/346/236/266/346/236/204_v1.0.md +237 -0
- package/docs//345/255/230/347/256/227/344/270/200/344/275/223/346/236/266/346/236/204/345/255/246/344/271/240_/345/244/226/351/203/250/347/220/206/350/256/272/345/257/271/347/205/247/344/270/216/350/267/257/347/272/277/344/272/244/346/216/245_20260916.md +98 -0
- package/docs//345/255/230/347/256/227/344/270/200/344/275/223/347/245/236/347/273/217/347/275/221/347/273/234/346/236/266/346/236/204_/346/200/273/347/272/262/344/270/216/344/272/244/346/216/245_20260916.md +109 -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 +34 -6
- package/docs//347/231/275/347/256/261/345/214/226/347/272/262/351/242/206_/344/270/211/351/241/271/347/233/256/345/255/246/344/271/240/346/200/273/346/236/266/346/236/204/344/270/216Ghidra/344/272/244/346/216/245_20260916.md +104 -0
- package/docs//350/256/260/345/277/206/350/257/204/345/256/241/347/263/273/347/273/237_/347/253/213/351/241/271/350/256/276/350/256/241/344/270/216/346/226/275/345/267/245/344/272/244/346/216/245_20260915.md +183 -0
- package/dsh/README.md +1 -1
- package/lib/hooks.d.ts +5 -0
- package/lib/hooks.js +10 -1
- package/lib/lib/prompt_safety.d.ts +48 -0
- package/lib/lib/prompt_safety.js +62 -0
- package/md_cg/audit.py +76 -2
- package/md_cg/bench_membench.py +10 -5
- package/md_cg/bench_progressive.py +48 -9
- package/md_cg/branches.py +275 -0
- package/md_cg/ccgc.py +884 -0
- package/md_cg/conformance.py +662 -0
- package/md_cg/consistency.py +1 -1
- package/md_cg/corpus.py +1 -1
- package/md_cg/eval_common.py +6 -5
- package/md_cg/forgetting.py +11 -3
- package/md_cg/fsutil.py +63 -1
- package/md_cg/identity.py +2 -2
- package/md_cg/insight.py +2 -2
- package/md_cg/lifecycle.py +262 -0
- package/md_cg/mcp_server.py +547 -140
- package/md_cg/mdcg.py +206 -18
- package/md_cg/mdcos.py +512 -50
- package/md_cg/metacognition.py +2 -2
- package/md_cg/mreview/__init__.py +25 -0
- package/md_cg/mreview/__main__.py +107 -0
- package/md_cg/mreview/bundle.py +170 -0
- package/md_cg/mreview/candidates.py +253 -0
- package/md_cg/mreview/govern.py +674 -0
- package/md_cg/mreview/locate.py +905 -0
- package/md_cg/mreview/pipeline.py +701 -0
- package/md_cg/mreview/rules/duplication.json +21 -0
- package/md_cg/mreview/rules/field_coverage.json +54 -0
- package/md_cg/mreview/rules/source_license.json +21 -0
- package/md_cg/mreview/rules/template_flow.json +21 -0
- package/md_cg/mreview/ruleset.py +238 -0
- package/md_cg/nodefile.py +38 -0
- package/md_cg/predict.py +24 -6
- package/md_cg/protect.py +4 -4
- package/md_cg/refindex.py +41 -2
- package/md_cg/scrub.py +5 -1
- package/md_cg/self_state.py +1 -1
- package/md_cg/semantic/en_normalizer.py +85 -25
- package/md_cg/sustain.py +18 -0
- package/md_cg/tasks.py +447 -0
- package/md_cg/test_action_derive.py +203 -0
- package/md_cg/test_audit_rotate.py +270 -0
- package/md_cg/test_branches.py +249 -0
- package/md_cg/test_ccg_perturb.py +1 -1
- package/md_cg/test_ccgc.py +423 -0
- package/md_cg/test_conformance.py +343 -0
- package/md_cg/test_en_pipeline.py +24 -0
- package/md_cg/test_health_scale.py +173 -0
- package/md_cg/test_identity_attribution.py +6 -0
- package/md_cg/test_index_durability.py +224 -0
- package/md_cg/test_lifecycle.py +309 -0
- package/md_cg/test_mr_m1.py +679 -0
- package/md_cg/test_mr_m2.py +587 -0
- package/md_cg/test_mr_m3.py +703 -0
- package/md_cg/test_mr_m4.py +485 -0
- package/md_cg/test_p1.py +1 -1
- package/md_cg/test_p11_consistency.py +1 -1
- package/md_cg/test_p12_metacognition.py +2 -2
- package/md_cg/test_p16_self_state.py +1 -1
- package/md_cg/test_p26_refindex.py +1 -1
- package/md_cg/test_p27_docindex.py +22 -2
- package/md_cg/test_p28_refcheck.py +1 -1
- package/md_cg/test_p29_session_ingest_export.py +1 -1
- package/md_cg/test_p2_mcp.py +7 -1
- package/md_cg/test_p38_contextualize.py +1 -1
- package/md_cg/test_p39_vision_evidence.py +1 -1
- package/md_cg/test_p40_refine_worklist.py +1 -1
- package/md_cg/test_p41_evolve_patrol.py +1 -1
- package/md_cg/test_p42_provenance.py +1 -1
- package/md_cg/test_p43_pooling.py +41 -13
- package/md_cg/test_read_clip.py +137 -0
- package/md_cg/test_review_conformance.py +310 -0
- package/md_cg/test_tasks.py +409 -0
- package/md_cg/test_tool_face.py +189 -0
- package/md_cg/test_twophase.py +286 -0
- package/md_cg/test_writepipe.py +210 -0
- package/md_cg/theory.py +1 -1
- package/md_cg/tokens.py +95 -5
- package/md_cg/tool_face.py +250 -0
- package/md_cg/twophase.py +221 -0
- package/md_cg/units.py +546 -0
- package/md_cg/vision_evidence.py +1 -1
- package/md_cg/weights.py +1 -1
- package/md_cg/whitebox.py +1 -1
- package/md_cg/whitebox_kb/data/verify_cache.json +28 -0
- package/md_cg/whitebox_kb/data/verify_savings.jsonl +46 -0
- package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-shm +0 -0
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-wal +0 -0
- package/md_cg/writelimit.py +19 -3
- package/md_cg/writepipe.py +372 -0
- package/package.json +1 -1
- package/src/hooks.ts +10 -1
- package/src/lib/prompt_safety.ts +62 -0
- package/zcode/AGENTS.md +195 -185
- package/docs//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +0 -221
- /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v1.0.md" +0 -0
- /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v2.0.md" +0 -0
- /package/docs/{ → eval/}/345/256/236/351/252/214/346/226/271/346/241/210_/345/255/246/344/271/240/351/227/255/347/216/257AB/344/270/216/346/250/252/350/257/204_v1.0.md" +0 -0
- /package/docs/{ → eval/}/346/250/252/350/257/204_/345/205/255/345/256/266100/351/242/230/344/270/255/350/213/261/345/217/214/346/237/245_v1.0.md" +0 -0
- /package/docs/{guardrail-charter.md → mdcg/guardrail-charter.md} +0 -0
- /package/docs/{lingshu_tutorial.html → mdcg/lingshu_tutorial.html} +0 -0
- /package/docs/{memory-assessment.html → mdcg/memory-assessment.html} +0 -0
- /package/docs/{memory_score.html → mdcg/memory_score.html} +0 -0
- /package/docs/{memory_score.png → mdcg/memory_score.png} +0 -0
- /package/docs/{release_v0.3.0.md → mdcg/release_v0.3.0.md} +0 -0
- /package/docs/{release_v0.4.5.md → mdcg/release_v0.4.5.md} +0 -0
- /package/docs/{tool_table_v0.3.0.md → mdcg/tool_table_v0.3.0.md} +0 -0
- /package/docs/{ → mdcg/}/344/273/244/347/211/214/344/270/216/350/247/222/350/211/262/346/235/203/350/201/214/345/210/206/347/246/273_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/24282/345/267/245/345/205/267_/345/212/237/350/203/275/346/225/264/347/220/206/344/270/216/350/277/201/347/247/273/346/230/240/345/260/204_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/242MCP/345/267/245/345/205/267/346/200/273/350/241/250_v3.4.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/242_/350/207/252/346/210/221/345/261/202/345/256/232/344/271/211.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_MD/347/233/256/345/275/225/346/226/271/346/241/210_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/346/235/241/344/273/266/347/251/272/351/227/264/345/220/210/346/210/220/344/270/216/347/224/237/346/225/210/346/235/241/344/273/266/345/217/243/345/276/204_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276/344/275/234/344/270/272/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_/350/257/204/344/274/260/344/270/216/350/267/257/347/272/277_v0.1.md" +0 -0
- /package/docs/{ → plans/}/345/221/275/345/220/215/346/262/273/347/220/206_/351/241/271/347/233/256/350/256/241/345/210/222.md" +0 -0
- /package/docs/{ → plans/}/347/237/245/350/257/206/345/233/276/350/260/261/351/241/271/347/233/256_/344/272/244/346/216/245/346/226/207/346/241/243_20260914.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/344/275/277/347/224/250/346/212/245/345/221/212_20260913.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/345/212/237/350/203/275/350/257/264/346/230/216_v0.6.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/347/233/262/345/214/272/346/240/207/350/256/260_v1.0.md" +0 -0
- /package/docs/{ → theory/}/344/277/241/346/201/257/345/267/256/344/270/272/344/273/200/344/271/210/345/277/205/347/204/266/345/255/230/345/234/250/344/270/224/350/207/252/347/204/266/346/211/251/345/244/247.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/345/205/254/347/220/206/345/214/226/345/237/272/347/237/263.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/350/256/244/347/237/245/350/277/207/347/250/213.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/350/256/2723.4.md" +0 -0
- /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/346/230/257/344/273/200/344/271/210/357/274/237.md" +0 -0
- /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/347/263/273/345/210/227/302/267/347/254/254/344/272/224/347/257/207/357/274/232/350/256/251AI/347/234/237/346/255/243/350/243/205/344/270/212/350/256/260/345/277/206.md" +0 -0
package/md_cg/mcp_server.py
CHANGED
|
@@ -496,7 +496,9 @@ KERNEL_TOOLS = [
|
|
|
496
496
|
{
|
|
497
497
|
"name": "cg",
|
|
498
498
|
"description": "认知图接口(唯一入口)。op=route:按情境条件路由,返回相关知识 + "
|
|
499
|
-
"建议能力名(不执行,由调用方决定);op=read:召回/检索/按 id
|
|
499
|
+
"建议能力名(不执行,由调用方决定);op=read:召回/检索/按 id 取"
|
|
500
|
+
"(长内容自动截断 2000 行 / 50KB,返回 truncated+next_offset,"
|
|
501
|
+
"续读传 offset=next_offset,不静默丢内容);"
|
|
500
502
|
"op=write:写入前按 content_kind 审核(ACCEPT 落盘 / REJECT 进负记忆 / "
|
|
501
503
|
"DEFER 进审核队列)+ 节点间冲突检测(三级决策:情绪→反思→递归反思;"
|
|
502
504
|
"consistency=false 可关,on_conflict=reject|defer|record);"
|
|
@@ -507,6 +509,12 @@ KERNEL_TOOLS = [
|
|
|
507
509
|
"op=forget:软删除/恢复(受保护节点需 override);"
|
|
508
510
|
"op=goal:目标槽(第 5 篇七件套之「目标」,"
|
|
509
511
|
"action=add|list|status;目标不进召回,只给 read 定向);"
|
|
512
|
+
"op=task:结构层任务实体(跨会话的工程台账,与信任/自我/协议同级;"
|
|
513
|
+
"action=open 登记或更新(同名即同卡)、status 状态迁移"
|
|
514
|
+
"(进行中/受阻/完成/放弃,迁 完成 时结果必填)、plan_add 追加计划变更、"
|
|
515
|
+
"get 单卡全字段、list 清单、find 同族提示(只提示不合并)、"
|
|
516
|
+
"session 会话装配面(进行中+近期完成);"
|
|
517
|
+
"任务只存骨架,中间过程不入库,任务知识走 knowledge 层);"
|
|
510
518
|
"op=recent:近期事件窗口(七件套之「近期事件」,"
|
|
511
519
|
"action=add|list|clear,滚动保留最近 N 条);"
|
|
512
520
|
"op=identity:身份特征识别(智能论 v3.4 位置效应 + 扮演论"
|
|
@@ -562,16 +570,44 @@ KERNEL_TOOLS = [
|
|
|
562
570
|
"另有节点**派生溯源**(区别于对端信任):derive 列边、"
|
|
563
571
|
"derive_dangling 悬空巡检(只读、不删边)、derive_catalog 自描述、"
|
|
564
572
|
"derive_rebuild 按 frontmatter 重建台账(默认预演);权威声明只在"
|
|
565
|
-
"节点写入时产生(write/remember 的 derived_from
|
|
573
|
+
"节点写入时产生(write/remember 的 derived_from),本层不新增写入口);"
|
|
574
|
+
"op=session:会话三件套(action=note 写要点 / recall 续接 / "
|
|
575
|
+
"compact 压摘要;hook 缺失时的库侧替代——载体负责「何时做」、库保证"
|
|
576
|
+
"「一次调用就够用」;note 与 compact(note=True) 需 can_write,recall 只读);"
|
|
577
|
+
"op=ingest:文件摄取(action=file|dir|jsonl|stat;写链需 can_write,"
|
|
578
|
+
"支持 dry_run 预演与 incremental 增量去重、watermark 留痕);"
|
|
579
|
+
"op=export:全库导出(action=graph|nodes|slice|stat;导出整库属管理"
|
|
580
|
+
"操作,一律 require_admin);"
|
|
581
|
+
"op=maintain:记忆维护(action=stat|history|importance|longterm|"
|
|
582
|
+
"prefeed|separate|rollback|backfill|cap|exempt|vision_evidence|refine "
|
|
583
|
+
"及其 *_history;权限按 action 分档:只读放行、prefeed 写入需 "
|
|
584
|
+
"can_write、批量改写与 rollback 需 admin;dry-run 只出报表不改盘);"
|
|
585
|
+
"op=consolidate:离线固化(action=promote 提升 | induce 归纳 | "
|
|
586
|
+
"contextualize 语境化,及其 _rollback/_history;批量提升属管理操作,"
|
|
587
|
+
"一律 require_admin);"
|
|
588
|
+
"op=insight:洞察(action=window|record|verify|list|report|"
|
|
589
|
+
"reconstruct|learn|outlook|catalog|fork|branch_rewrite|branch_search|"
|
|
590
|
+
"branch_merge|branch_discard|branches;权限按 action 分档:只读放行、"
|
|
591
|
+
"条件记账与分支写需 can_write、落库 apply 与分支弃置需 admin);"
|
|
592
|
+
"op=ccg:CCG 六要素编译器(action=compile|review|attest|link|"
|
|
593
|
+
"recalibrate|units|catalog;入参统一在 ccg 对象里)。"
|
|
594
|
+
"把对话记录编译为六要素候选 → **编外复核**(裁定 A:编译者不得自证,"
|
|
595
|
+
"E041 机械拒绝)→ 落库;复核优先走蜂巢 reflect/verify 单元,"
|
|
596
|
+
"蜂巢不可用则提示配置,或显式 allow_degrade 降级 harness 端子代理。",
|
|
566
597
|
"inputSchema": _s("",
|
|
567
598
|
op=_p("string", "route|read|write|verify|review|protect|identity|"
|
|
568
599
|
"consistency|metacognition|self_state|evolution|sustain|"
|
|
569
600
|
"scrub|predict|causal|"
|
|
570
|
-
"forget|goal|recent|info|index_code|index_doc|ref|whitebox|"
|
|
601
|
+
"forget|goal|task|recent|info|index_code|index_doc|ref|whitebox|"
|
|
571
602
|
"theory|link|session|ingest|export|maintain|consolidate|"
|
|
572
|
-
"insight", True),
|
|
603
|
+
"insight|ccg|help", True),
|
|
604
|
+
ccg=_p("object", "CCG 六要素编译器入参:{action, node_id, dialog, marks, "
|
|
605
|
+
"slots, strict_spans, role, verdict, verifier, compiled_by, "
|
|
606
|
+
"evidence, slot_corrections, model, jobs, blocking, wait_s, "
|
|
607
|
+
"allow_degrade, channel, autostart, doctor, apply, basis}"),
|
|
573
608
|
intent=_p("string", "route 的查询意图"), query=_p("string", "read 的查询"),
|
|
574
|
-
goal=_p("string", "goal op 的目标文本;read
|
|
609
|
+
goal=_p("string", "goal op 的目标文本;read 的定向目标(缺省用活跃目标);"
|
|
610
|
+
"task op:任务目标(CCG「执行」栏)"),
|
|
575
611
|
goal_status=_p("string", "goal op:active|done|dropped"),
|
|
576
612
|
priority=_p("number", "goal op:优先级 0-1(兼作定向偏置依据)"),
|
|
577
613
|
deadline=_p("string", "goal op:截止时间(仅排序用,不做硬约束)"),
|
|
@@ -585,8 +621,9 @@ KERNEL_TOOLS = [
|
|
|
585
621
|
include_recent=_p("boolean", "read:是否附近期事件窗口(默认否)"),
|
|
586
622
|
limit=_p("integer", "goal/recent 的返回条数;read 的近期事件条数"),
|
|
587
623
|
node_id=_p("string", "节点 id"),
|
|
624
|
+
offset=_p("integer", "read 的续读起始行(1 基;传上次返回的 next_offset)"),
|
|
588
625
|
content=_p("string", "write 的内容(建议含 CCG 5 要素注释)"),
|
|
589
|
-
content_kind=_p("string", "write 的内容类型:code|image_desc|text|permission|work_done|work_wip"),
|
|
626
|
+
content_kind=_p("string", "write 的内容类型:code|image_desc|text|permission|work_done|work_wip|ccg_marks"),
|
|
590
627
|
layer=_p("string", "层:anchor|structural|knowledge|contextual|self"),
|
|
591
628
|
tags=_p("array", "标签(cap:xxx 会作为 route 的建议能力名)"),
|
|
592
629
|
importance=_p("number", "重要性 0-1"),
|
|
@@ -652,7 +689,11 @@ KERNEL_TOOLS = [
|
|
|
652
689
|
"promote_history|induce|contextualize|"
|
|
653
690
|
"contextualize_rollback|contextualize_history;"
|
|
654
691
|
"insight: window|record|verify|list|report|"
|
|
655
|
-
"reconstruct|learn|outlook|catalog"
|
|
692
|
+
"reconstruct|learn|outlook|catalog|"
|
|
693
|
+
"fork|branch_rewrite|branch_search|"
|
|
694
|
+
"branch_merge|branch_discard|branches;"
|
|
695
|
+
"分支六 act:node_ids/branch_id/note/content/"
|
|
696
|
+
"reason 按 act 取用(rewrite 传 node_id+content)"),
|
|
656
697
|
pid=_p("string", "review decide 的提案 id"),
|
|
657
698
|
decision=_p("string", "review 裁决:accept|reject|edit|merge"),
|
|
658
699
|
edits=_p("object", "review edit 的覆盖字段(不可含 verify)"),
|
|
@@ -686,7 +727,8 @@ KERNEL_TOOLS = [
|
|
|
686
727
|
"路径命中私有提示时保守降为 private)"),
|
|
687
728
|
ref=_p("object", "ref op:直接给 code_ref/doc_ref 对象(与 node_id 二选一)"),
|
|
688
729
|
root=_p("string", "ref op:覆盖 ref 里记录的 root(索引结果的跨机器搬迁)"),
|
|
689
|
-
name=_p("string", "sustain:心跳名(默认 md_cg
|
|
730
|
+
name=_p("string", "sustain:心跳名(默认 md_cg);"
|
|
731
|
+
"task op:任务名(**身份判据**:同名即同任务,slug 归一后落 id)"),
|
|
690
732
|
session=_p("string", "read(search/recall 分支):会话归属过滤"
|
|
691
733
|
"(frontmatter.session;缺省不过滤);"
|
|
692
734
|
"sustain:会话 id(resume/note 用)"),
|
|
@@ -729,7 +771,8 @@ KERNEL_TOOLS = [
|
|
|
729
771
|
hit=_p("boolean", "predict feedback:是否命中(缺省按 predicted==actual)"),
|
|
730
772
|
rule=_p("string", "evolution record:规律(必填,一句话认知规律)"),
|
|
731
773
|
missing=_p("string", "evolution record:补的是哪一维缺失条件"),
|
|
732
|
-
change=_p("string", "evolution record
|
|
774
|
+
change=_p("string", "evolution record:这次具体改了什么;"
|
|
775
|
+
"task op:本轮计划变更/新增问题(追加进「计划变更」节,可追溯)"),
|
|
733
776
|
kind=_p("string", "evolution:condition_gap|layer_shift|general"),
|
|
734
777
|
entry_id=_p("string", "evolution show/rollback:条目 id"),
|
|
735
778
|
source=_p("string", "evolution record:来源 consolidate|verify|manual;"
|
|
@@ -810,7 +853,20 @@ KERNEL_TOOLS = [
|
|
|
810
853
|
neighbors=_p("boolean", "insight reconstruct:是否并入一跳邻域(默认 true)"),
|
|
811
854
|
recent_days=_p("integer", "insight outlook:近期窗口天数(默认 7)"),
|
|
812
855
|
sample_limit=_p("integer", "insight outlook:抽样清单条数(默认 8)"),
|
|
813
|
-
max_events=_p("integer", "ingest:单次最多摄取事件数")
|
|
856
|
+
max_events=_p("integer", "ingest:单次最多摄取事件数"),
|
|
857
|
+
task_status=_p("string", "task op:active|blocked|done|dropped;"
|
|
858
|
+
"迁 done 必须同时给 result(缺一不收)"),
|
|
859
|
+
plan=_p("string", "task op:分步计划(每轮覆盖更新,跨会话持久存在)"),
|
|
860
|
+
result=_p("string", "task op:任务结果(done 时必填;本次不传则**保留旧值**,"
|
|
861
|
+
"不会被静默清空)"),
|
|
862
|
+
acceptance=_p("string", "task op:验收判据(怎么算完成)"),
|
|
863
|
+
boundary=_p("string", "task op:不适用条件/边界"),
|
|
864
|
+
note=_p("string", "task op:本轮备注(change 是计划变更,note 是附注);"
|
|
865
|
+
"self_state relate:备注"),
|
|
866
|
+
condition=_p("string", "task op:生效条件(CCG「生效条件」栏);"
|
|
867
|
+
"self_state relate:关系成立条件"),
|
|
868
|
+
active_limit=_p("integer", "task action=session:进行中任务条数(默认 5)"),
|
|
869
|
+
done_limit=_p("integer", "task action=session:近期已完成条数(默认 5)")),
|
|
814
870
|
},
|
|
815
871
|
{
|
|
816
872
|
"name": "stg",
|
|
@@ -833,8 +889,16 @@ SURFACE = os.environ.get("MDCG_MCP_SURFACE", "kernel").strip().lower()
|
|
|
833
889
|
|
|
834
890
|
|
|
835
891
|
def tools_for_surface():
|
|
836
|
-
"""kernel:只暴露 2 个基元;full:2 个基元 + 31 个细粒度工具(兼容/调试)。
|
|
837
|
-
|
|
892
|
+
"""kernel:只暴露 2 个基元;full:2 个基元 + 31 个细粒度工具(兼容/调试)。
|
|
893
|
+
|
|
894
|
+
返回**投影后**的工具面(工具一行职责 + 参数短提示):完整语义由
|
|
895
|
+
``cg(op=help, query=…)`` 按需取回。真源 KERNEL_TOOLS/TOOLS 保持完整定义,
|
|
896
|
+
投影只是运行时视图(信息零丢失,见 md_cg/tool_face.py)。
|
|
897
|
+
关闭投影:``MDCG_TOOL_FACE=full``。
|
|
898
|
+
"""
|
|
899
|
+
tools = ALL_TOOLS if SURFACE == "full" else KERNEL_TOOLS
|
|
900
|
+
from .tool_face import slim_tools
|
|
901
|
+
return slim_tools(tools)
|
|
838
902
|
|
|
839
903
|
|
|
840
904
|
# --------------------------------------------------------------------------
|
|
@@ -866,11 +930,60 @@ def _pick_source(path):
|
|
|
866
930
|
return JsonlSource(path)
|
|
867
931
|
|
|
868
932
|
|
|
869
|
-
|
|
933
|
+
READ_MAX_LINES = 2000 # 单次 read 返回行数上限(Pi⑦② 截断)
|
|
934
|
+
READ_MAX_BYTES = 50 * 1024 # 单次 read 返回字节上限(Pi⑦② 截断)
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
def _clip_text(text: str, *, offset: int = 0, max_lines: int = READ_MAX_LINES,
|
|
938
|
+
max_bytes: int = READ_MAX_BYTES) -> dict:
|
|
939
|
+
"""行窗口 + 双阈值截断(Pi⑦② 截断必带续读提示)。
|
|
940
|
+
|
|
941
|
+
offset 为 1 基起始行(续读传上次 next_offset)。不静默丢内容——截断时
|
|
942
|
+
返回 total_lines / total_bytes / next_offset / note,调用方按 offset 续读。
|
|
943
|
+
"""
|
|
944
|
+
text = text or ""
|
|
945
|
+
lines = text.split("\n")
|
|
946
|
+
total_lines = len(lines)
|
|
947
|
+
total_bytes = len(text.encode("utf-8"))
|
|
948
|
+
start = max(0, int(offset) - 1) if offset else 0
|
|
949
|
+
if start >= total_lines:
|
|
950
|
+
return {"text": "", "offset": start + 1, "next_offset": None,
|
|
951
|
+
"returned_lines": 0, "total_lines": total_lines,
|
|
952
|
+
"total_bytes": total_bytes, "truncated": False,
|
|
953
|
+
"note": f"offset={start + 1} 超出总行数 {total_lines},返回空"}
|
|
954
|
+
got, used = [], 0
|
|
955
|
+
for ln in lines[start:start + max_lines]:
|
|
956
|
+
b = len(ln.encode("utf-8")) + 1
|
|
957
|
+
if got and used + b > max_bytes:
|
|
958
|
+
break
|
|
959
|
+
got.append(ln)
|
|
960
|
+
used += b
|
|
961
|
+
end = start + len(got)
|
|
962
|
+
truncated = end < total_lines
|
|
963
|
+
out = {"text": "\n".join(got), "offset": start + 1,
|
|
964
|
+
"next_offset": end + 1 if truncated else None,
|
|
965
|
+
"returned_lines": len(got), "total_lines": total_lines,
|
|
966
|
+
"total_bytes": total_bytes, "truncated": truncated, "note": ""}
|
|
967
|
+
if truncated:
|
|
968
|
+
out["note"] = (f"内容已截断(单次上限 {max_lines} 行 / {max_bytes} 字节):"
|
|
969
|
+
f"共 {total_lines} 行 / {total_bytes} 字节,本次返回第 "
|
|
970
|
+
f"{start + 1}–{end} 行;续读传 offset={end + 1}。")
|
|
971
|
+
return out
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
def _node_view(node, offset: int = 0):
|
|
870
975
|
if not node:
|
|
871
976
|
return None
|
|
872
|
-
|
|
873
|
-
|
|
977
|
+
clip = _clip_text(node.get("content") or "", offset=offset)
|
|
978
|
+
out = {"id": node.get("id"), "path": node.get("path"),
|
|
979
|
+
"frontmatter": node.get("frontmatter"), "content": clip["text"]}
|
|
980
|
+
if clip["truncated"] or offset:
|
|
981
|
+
out.update({"truncated": clip["truncated"],
|
|
982
|
+
"content_lines": clip["total_lines"],
|
|
983
|
+
"content_bytes": clip["total_bytes"],
|
|
984
|
+
"offset": clip["offset"], "next_offset": clip["next_offset"],
|
|
985
|
+
"note": clip["note"]})
|
|
986
|
+
return out
|
|
874
987
|
|
|
875
988
|
|
|
876
989
|
# --------------------------------------------------------------------------
|
|
@@ -1400,8 +1513,75 @@ def _scrub_call(cg, a):
|
|
|
1400
1513
|
raise ValueError(f"scrub 未知 action:{act}")
|
|
1401
1514
|
|
|
1402
1515
|
|
|
1516
|
+
# ---- action 缺省防呆(2026-09-16)------------------------------------------
|
|
1517
|
+
# 与「op 缺省静默降级」同构的第二类静默失败:op 传了、action 漏了 → 各分支按
|
|
1518
|
+
# 字面量默认 action 执行。若默认恰是**读类**,写意图会被静默吞掉且返回形似正常
|
|
1519
|
+
# 的结果——最典型是文档化契约 `cg(op=review, pid, decision, reason)`(不带
|
|
1520
|
+
# action)实际静默走 review_list,裁决从未落盘(契约与实现漂移)。
|
|
1521
|
+
# 处置:签名明确指向非默认 action → 按签名推导并透出 action_derived/hint_action;
|
|
1522
|
+
# 无签名可依 → 维持默认执行但同样透出标记,让「按默认走」可见而非静默。
|
|
1523
|
+
# 判据用「键存在且非 None」(False / 0 / "" 属显式传入),避免真值判断误吞。
|
|
1524
|
+
_ACTION_SIGS = {
|
|
1525
|
+
"review": (("decision", "decide"), ("node_id", "verify_record")),
|
|
1526
|
+
"recent": (("text", "add"), ("content", "add")),
|
|
1527
|
+
"goal": (("goal", "add"), ("action_hint", "add")),
|
|
1528
|
+
# task:**写意图优先、读意图最后**。name→open 先命中——open(upsert)本身
|
|
1529
|
+
# 兼容 plan/result/change 全字段,故「name+change」同传也不会丢信息;把
|
|
1530
|
+
# change→plan_add 放其后,只在「只给 change」时才是纯追加变更。node_id→get
|
|
1531
|
+
# 置于末位:否则「node_id+change」会被静默当成只读(写意图被吞,
|
|
1532
|
+
# 与 review 的 `pid+decision` 静默走 list 同构)。
|
|
1533
|
+
"task": (("name", "open"), ("task_status", "status"),
|
|
1534
|
+
("result", "status"), ("change", "plan_add"),
|
|
1535
|
+
("node_id", "get")),
|
|
1536
|
+
"predict": (("hit", "feedback"), ("predicted_node_id", "feedback"),
|
|
1537
|
+
("actual_node_id", "feedback")),
|
|
1538
|
+
"session": (("summary", "note"), ("text", "note"), ("content", "note")),
|
|
1539
|
+
"insight": (("statement", "record"),),
|
|
1540
|
+
"whitebox": (("questions", "verify_existing"), ("question", "ask"),
|
|
1541
|
+
("message", "ask"), ("query", "ask"),
|
|
1542
|
+
("marker", "verify_encoding"),
|
|
1543
|
+
("content", "remember"), ("text", "remember")),
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
# op → 分支内缺省 action 字面量。**仅供缺省透出提示,不参与执行**;与各
|
|
1547
|
+
# _xxx_call / 分支里的 `a.get("action") or "<默认>"` 保持同步(同源守卫见
|
|
1548
|
+
# test_action_derive.py)。
|
|
1549
|
+
_ACTION_DEFAULT = {
|
|
1550
|
+
"theory": "check", "link": "ls", "scrub": "sweep", "forget": "forget",
|
|
1551
|
+
"protect": "stats", "identity": "profile", "consistency": "check",
|
|
1552
|
+
"metacognition": "report", "self_state": "snapshot", "predict": "routes",
|
|
1553
|
+
"causal": "path", "evolution": "summary", "sustain": "status",
|
|
1554
|
+
"goal": "list", "task": "list", "recent": "list", "review": "list", "session": "recall",
|
|
1555
|
+
"ingest": "stat", "export": "stat", "maintain": "stat",
|
|
1556
|
+
"consolidate": "promote", "insight": "outlook",
|
|
1557
|
+
"ccg": "compile", "ref": "read", "whitebox": "ping",
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
|
|
1561
|
+
def _action_sig(a, op):
|
|
1562
|
+
"""action 缺省时的签名推导 → (action, 依据键);无签名可依 → (None, None)。
|
|
1563
|
+
|
|
1564
|
+
`ingest` 单独处理:其 op 语义是**写**(摄入),缺省 action 却是**读**(stat)
|
|
1565
|
+
——「传了 path 却静默 stat」会把摄入整件事吞掉。类型按**保守优先**推导:
|
|
1566
|
+
patterns→dir、`*.jsonl`→jsonl、其余 path→file(file 最保守:若实为目录会
|
|
1567
|
+
报错可见,而不会误把整棵目录树摄进来)。
|
|
1568
|
+
"""
|
|
1569
|
+
if op == "ingest":
|
|
1570
|
+
path = str(a.get("path") or "").strip()
|
|
1571
|
+
if path:
|
|
1572
|
+
if a.get("patterns"):
|
|
1573
|
+
return "dir", "patterns"
|
|
1574
|
+
if path.lower().endswith(".jsonl"):
|
|
1575
|
+
return "jsonl", "path(*.jsonl)"
|
|
1576
|
+
return "file", "path"
|
|
1577
|
+
for key, act in _ACTION_SIGS.get(op, ()):
|
|
1578
|
+
if key in a and a.get(key) is not None:
|
|
1579
|
+
return act, key
|
|
1580
|
+
return None, None
|
|
1581
|
+
|
|
1582
|
+
|
|
1403
1583
|
def _cg_call(cg, a):
|
|
1404
|
-
"""认知图唯一入口(外层:op 缺省推导兜底 +
|
|
1584
|
+
"""认知图唯一入口(外层:op/action 缺省推导兜底 + 推导透出;主体见 _cg_dispatch)。"""
|
|
1405
1585
|
op0 = (a.get("op") or "").strip().lower()
|
|
1406
1586
|
op = op0
|
|
1407
1587
|
if not op:
|
|
@@ -1416,19 +1596,117 @@ def _cg_call(cg, a):
|
|
|
1416
1596
|
else:
|
|
1417
1597
|
op = "read" # 无任何签名可依:维持旧缺省 read
|
|
1418
1598
|
args = dict(a)
|
|
1599
|
+
act0 = (args.get("action") or "").strip().lower()
|
|
1600
|
+
act_sig = act_derived = None
|
|
1601
|
+
if not act0:
|
|
1602
|
+
act_derived, act_sig = _action_sig(args, op)
|
|
1603
|
+
if act_derived:
|
|
1604
|
+
args["action"] = act_derived # 按签名补 action:避免写意图被默认吞掉
|
|
1419
1605
|
args["op"] = op
|
|
1420
1606
|
out = _cg_dispatch(cg, args)
|
|
1421
|
-
if isinstance(out, dict)
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1607
|
+
if isinstance(out, dict):
|
|
1608
|
+
if not op0:
|
|
1609
|
+
out["op"] = op
|
|
1610
|
+
out["op_derived"] = True
|
|
1611
|
+
out["hint"] = ("op 未显式传入,已按参数签名推导(本次按 %s 执行);op 为必填参数,"
|
|
1612
|
+
"复杂任务中也请始终显式传 op,避免静默执行错误意图" % op)
|
|
1613
|
+
if not act0 and (act_derived or op in _ACTION_DEFAULT):
|
|
1614
|
+
eff = act_derived or _ACTION_DEFAULT[op]
|
|
1615
|
+
out.setdefault("action", eff)
|
|
1616
|
+
out["action_derived"] = True
|
|
1617
|
+
if act_derived:
|
|
1618
|
+
out["hint_action"] = (
|
|
1619
|
+
"action 未显式传入,已按参数 %s 推导为 action=%s(旧行为会静默走默认 %s,"
|
|
1620
|
+
"意图被吞);建议显式传 action" % (act_sig, act_derived,
|
|
1621
|
+
_ACTION_DEFAULT.get(op, "?")))
|
|
1622
|
+
else:
|
|
1623
|
+
out["hint_action"] = (
|
|
1624
|
+
"action 未显式传入,本次按 %s 的默认 action=%s 执行;"
|
|
1625
|
+
"若意图是其它 action 请显式传 action" % (op, eff))
|
|
1426
1626
|
return out
|
|
1427
1627
|
|
|
1428
1628
|
|
|
1629
|
+
def _help_call(cg, a):
|
|
1630
|
+
"""按需披露入口(工具面渐进披露的读取面,见 md_cg/tool_face.py)。
|
|
1631
|
+
|
|
1632
|
+
常驻上下文只留「一行职责 + 参数短提示」;被投影掉的完整 op/参数语义
|
|
1633
|
+
在此从真源无损取回——所以瘦身不损失能力,只把「随时付费」换成「按需取」。
|
|
1634
|
+
只读元信息(工具 schema 本身对客户端可见),故不过角色权限闸。
|
|
1635
|
+
"""
|
|
1636
|
+
from .tool_face import help_text
|
|
1637
|
+
return help_text(ALL_TOOLS, query=a.get("query") or a.get("intent"),
|
|
1638
|
+
limit=int(a.get("limit") or a.get("k") or 40))
|
|
1639
|
+
|
|
1640
|
+
|
|
1641
|
+
def _task_call(cg, a):
|
|
1642
|
+
"""结构层任务实体(op=task)——跨会话的工程台账。
|
|
1643
|
+
|
|
1644
|
+
action:
|
|
1645
|
+
open / add 登记或更新任务卡(**同名即同卡**;未给字段沿用旧值,不静默清空)
|
|
1646
|
+
status 状态迁移(active|blocked|done|dropped;迁 done 时「结果」必填)
|
|
1647
|
+
plan_add 追加计划变更(执行中发现的偏差与新问题)
|
|
1648
|
+
get 单卡全字段读回
|
|
1649
|
+
list 任务清单(默认;可按 task_status 过滤)
|
|
1650
|
+
find 同族任务提示(**只提示,不自动合并**)
|
|
1651
|
+
session 会话装配面(进行中 + 近期完成)——供上下文召回
|
|
1652
|
+
|
|
1653
|
+
:param name: 任务名(身份判据:同名即同任务,slug 归一后落节点 id)
|
|
1654
|
+
"""
|
|
1655
|
+
from . import tasks as _t
|
|
1656
|
+
act = (a.get("action") or "").strip().lower()
|
|
1657
|
+
if not act:
|
|
1658
|
+
act = _action_sig(a, "task")[0] or "list"
|
|
1659
|
+
name = a.get("name") or a.get("task_name") or a.get("task") or ""
|
|
1660
|
+
nid = a.get("node_id") or a.get("task_id") or ""
|
|
1661
|
+
tstat = a.get("task_status") or a.get("new_status") or ""
|
|
1662
|
+
|
|
1663
|
+
if act in ("open", "add", "upsert"):
|
|
1664
|
+
imp = a.get("importance")
|
|
1665
|
+
try:
|
|
1666
|
+
imp = float(imp) if imp is not None else None
|
|
1667
|
+
except (TypeError, ValueError):
|
|
1668
|
+
imp = None
|
|
1669
|
+
return _t.upsert(cg, name or nid,
|
|
1670
|
+
plan=a.get("plan"), status=tstat or None,
|
|
1671
|
+
result=a.get("result"), condition=a.get("condition"),
|
|
1672
|
+
goal=a.get("goal_text") or a.get("goal"),
|
|
1673
|
+
acceptance=a.get("acceptance"), boundary=a.get("boundary"),
|
|
1674
|
+
change=a.get("change"), note=a.get("note"),
|
|
1675
|
+
tags=a.get("tags"), importance=imp, actor=a.get("actor"))
|
|
1676
|
+
|
|
1677
|
+
if act in ("status", "set_status"):
|
|
1678
|
+
if not tstat:
|
|
1679
|
+
return {"ok": False, "error": "缺 task_status",
|
|
1680
|
+
"hint": "可选 active|blocked|done|dropped;迁 done 必须同时给 result"}
|
|
1681
|
+
return _t.set_status(cg, nid or name, tstat, result=a.get("result"),
|
|
1682
|
+
note=a.get("note"), actor=a.get("actor"))
|
|
1683
|
+
|
|
1684
|
+
if act == "plan_add":
|
|
1685
|
+
return _t.plan_add(cg, nid or name, a.get("change") or a.get("text"),
|
|
1686
|
+
actor=a.get("actor"))
|
|
1687
|
+
|
|
1688
|
+
if act == "get":
|
|
1689
|
+
return _t.get_task(cg, nid or name)
|
|
1690
|
+
|
|
1691
|
+
if act == "find":
|
|
1692
|
+
return _t.find_similar(cg, name, k=int(a.get("k") or a.get("limit") or 5))
|
|
1693
|
+
|
|
1694
|
+
if act == "session":
|
|
1695
|
+
return _t.session_tasks(cg, active_limit=int(a.get("active_limit") or 5),
|
|
1696
|
+
done_limit=int(a.get("done_limit") or 5))
|
|
1697
|
+
|
|
1698
|
+
if act != "list":
|
|
1699
|
+
return {"ok": False, "error": "未知 task action:%r" % act,
|
|
1700
|
+
"hint": "可选 open|status|plan_add|get|list|find|session"}
|
|
1701
|
+
|
|
1702
|
+
return _t.list_tasks(cg, status=tstat or None, limit=a.get("limit"))
|
|
1703
|
+
|
|
1704
|
+
|
|
1429
1705
|
def _cg_dispatch(cg, a):
|
|
1430
1706
|
"""认知图唯一入口的 op 分发主体。"""
|
|
1431
1707
|
op = (a.get("op") or "read").strip().lower()
|
|
1708
|
+
if op == "help":
|
|
1709
|
+
return _help_call(cg, a)
|
|
1432
1710
|
_p = getattr(cg, "principal", None)
|
|
1433
1711
|
if _p is not None and hasattr(_p, "require_op"):
|
|
1434
1712
|
_p.require_op(op) # 角色作用域闸门:越权即 AccessDenied
|
|
@@ -1561,12 +1839,15 @@ def _cg_dispatch(cg, a):
|
|
|
1561
1839
|
|
|
1562
1840
|
if op == "info":
|
|
1563
1841
|
from . import audit
|
|
1842
|
+
from . import nodefile
|
|
1564
1843
|
from . import theory as _th
|
|
1565
1844
|
from . import links as _lk
|
|
1566
1845
|
h = cg.health_os()
|
|
1567
1846
|
h.update({"surface": SURFACE,
|
|
1568
1847
|
"tools": [t["name"] for t in tools_for_surface()],
|
|
1569
|
-
"audit_kinds": audit.kinds(), "whoami": cg.whoami()
|
|
1848
|
+
"audit_kinds": audit.kinds(), "whoami": cg.whoami(),
|
|
1849
|
+
# 裁定 B:CCG 六要素的契约角色(术语真源在 nodefile,此处只透出)
|
|
1850
|
+
"ccg_contract": dict(nodefile.CCG_CONTRACT_ROLES)})
|
|
1570
1851
|
# 能力外置可观测:本进程实际注入了哪些外部验证器(含失败原因)
|
|
1571
1852
|
h["external_verifiers"] = audit.load_external_verifiers()
|
|
1572
1853
|
h["theory"] = _th.check()
|
|
@@ -1595,7 +1876,8 @@ def _cg_dispatch(cg, a):
|
|
|
1595
1876
|
|
|
1596
1877
|
if op == "read":
|
|
1597
1878
|
if a.get("node_id"):
|
|
1598
|
-
return _node_view(cg.get(a["node_id"])
|
|
1879
|
+
return _node_view(cg.get(a["node_id"]),
|
|
1880
|
+
offset=int(a.get("offset") or 0))
|
|
1599
1881
|
q = a.get("query") or a.get("intent") or ""
|
|
1600
1882
|
if a.get("budget_tokens"):
|
|
1601
1883
|
return cg.recall(q, budget_tokens=int(a["budget_tokens"]),
|
|
@@ -1614,110 +1896,12 @@ def _cg_dispatch(cg, a):
|
|
|
1614
1896
|
for n, s, q2 in res]}
|
|
1615
1897
|
|
|
1616
1898
|
if op == "write":
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
{"cg": cg, "principal": getattr(cg, "principal", None)})
|
|
1624
|
-
nid = a.get("node_id") or ("mem_" + str(int(__import__("time").time() * 1000)))
|
|
1625
|
-
st = verdict["state"]
|
|
1626
|
-
if st == audit.ACCEPT:
|
|
1627
|
-
# 节点间自动冲突检测(三级决策:情绪→反思→递归反思):
|
|
1628
|
-
# 写入前与既有条件/纪律校验;不通过则不落盘(可进审核队列)。
|
|
1629
|
-
# 与 mdcg_remember 同源、默认开启——「信息的修改必须先通过校验」。
|
|
1630
|
-
cvd = None
|
|
1631
|
-
if bool(a.get("consistency", True)):
|
|
1632
|
-
oc = (a.get("on_conflict") or "defer").strip().lower()
|
|
1633
|
-
cvd = cg.check_consistency(
|
|
1634
|
-
a.get("content", ""),
|
|
1635
|
-
layer=a.get("layer") or ("contextual" if a.get("gated")
|
|
1636
|
-
else "knowledge"),
|
|
1637
|
-
condition_space=a.get("condition_space"),
|
|
1638
|
-
non_applicable_conditions=a.get("non_applicable_conditions"),
|
|
1639
|
-
tags=a.get("tags"), exclude=nid, auto_flywheel=True)
|
|
1640
|
-
v = cvd.get("verdict")
|
|
1641
|
-
blocked = ((v == "REJECT" and oc == "reject")
|
|
1642
|
-
or (v in ("REJECT", "BLINDSPOT") and oc == "defer"))
|
|
1643
|
-
if blocked:
|
|
1644
|
-
if oc == "reject":
|
|
1645
|
-
return {"ok": False, "id": nid, "committed": False,
|
|
1646
|
-
"moved_to": "conflict_rejected",
|
|
1647
|
-
"consistency": cvd, "verdict": verdict}
|
|
1648
|
-
pid = cg.propose(nid, a.get("content", ""),
|
|
1649
|
-
layer=a.get("layer") or "knowledge",
|
|
1650
|
-
tags=a.get("tags"),
|
|
1651
|
-
condition_space=a.get("condition_space"),
|
|
1652
|
-
**_proposal_extras(a, verdict))
|
|
1653
|
-
return {"ok": False, "id": nid, "pid": pid, "committed": False,
|
|
1654
|
-
"moved_to": "review_queue", "consistency": cvd,
|
|
1655
|
-
"verdict": verdict,
|
|
1656
|
-
"hint": "这是冲突闸门的正常行为:本次写入与既有条件/纪律冲突"
|
|
1657
|
-
"(on_conflict=defer),已转入审核队列待裁决——"
|
|
1658
|
-
"不是工具故障,重试同样结果;"
|
|
1659
|
-
"落盘须由设计者权限(can_admin)裁决,转告使用者:"
|
|
1660
|
-
"python scripts/review_cli.py list 后 accept/reject,"
|
|
1661
|
-
"或 cg(op=review, pid=<pid>, decision=accept|reject|"
|
|
1662
|
-
"edit|merge, reason=<理由>)"}
|
|
1663
|
-
if a.get("gated"):
|
|
1664
|
-
hint = a.get("importance_hint")
|
|
1665
|
-
if hint is None and a.get("importance") is not None:
|
|
1666
|
-
hint = float(a["importance"])
|
|
1667
|
-
res = cg.remember_gated(
|
|
1668
|
-
nid, a.get("content", ""), layer=a.get("layer") or "contextual",
|
|
1669
|
-
role=a.get("role"), tags=a.get("tags"),
|
|
1670
|
-
condition_space=a.get("condition_space"),
|
|
1671
|
-
verification_basis=(a.get("verification_basis")
|
|
1672
|
-
or verdict.get("basis")),
|
|
1673
|
-
non_applicable_conditions=a.get("non_applicable_conditions"),
|
|
1674
|
-
importance_hint=hint, override=bool(a.get("override")),
|
|
1675
|
-
consistency=False,
|
|
1676
|
-
derived_from=_split_ids(a.get("derived_from")),
|
|
1677
|
-
relation=a.get("relation"))
|
|
1678
|
-
v = res.get("verdict")
|
|
1679
|
-
committed = v == "ACCEPT"
|
|
1680
|
-
out = {"ok": committed, "id": nid, "committed": committed,
|
|
1681
|
-
"gate": res, "verdict": verdict}
|
|
1682
|
-
if cvd is not None:
|
|
1683
|
-
out["consistency"] = cvd
|
|
1684
|
-
if v == "MERGE":
|
|
1685
|
-
out["moved_to"] = "merged_into:" + str(res.get("merged_into"))
|
|
1686
|
-
elif v in ("DROP", "DEFER"):
|
|
1687
|
-
out["moved_to"] = v.lower()
|
|
1688
|
-
return out
|
|
1689
|
-
cg.add(nid, a.get("content", ""), layer=a.get("layer") or "knowledge",
|
|
1690
|
-
tags=a.get("tags"), condition_space=a.get("condition_space"),
|
|
1691
|
-
importance=float(a.get("importance", 0.5)),
|
|
1692
|
-
verification_basis=a.get("verification_basis") or verdict.get("basis"),
|
|
1693
|
-
non_applicable_conditions=a.get("non_applicable_conditions"),
|
|
1694
|
-
override=bool(a.get("override")), consistency=False,
|
|
1695
|
-
derived_from=_split_ids(a.get("derived_from")),
|
|
1696
|
-
relation=a.get("relation"))
|
|
1697
|
-
out = {"ok": True, "id": nid, "committed": True, "verdict": verdict}
|
|
1698
|
-
if cvd is not None:
|
|
1699
|
-
out["consistency"] = cvd
|
|
1700
|
-
return out
|
|
1701
|
-
if st == audit.REJECT:
|
|
1702
|
-
rid = cg.add_rejected((a.get("content") or "")[:200], verdict["evidence"],
|
|
1703
|
-
verification_basis=verdict.get("basis") or "test",
|
|
1704
|
-
tags=a.get("tags"))
|
|
1705
|
-
return {"ok": False, "id": rid, "committed": False,
|
|
1706
|
-
"moved_to": "rejected", "verdict": verdict,
|
|
1707
|
-
"hint": "这是审核闸门的正常行为:内容未过内容政策审核(REJECT),"
|
|
1708
|
-
"已记入负记忆——不是工具故障,重试同样结果;"
|
|
1709
|
-
"拒绝依据见 verdict.evidence"}
|
|
1710
|
-
pid = cg.propose(nid, a.get("content", ""), layer=a.get("layer") or "knowledge",
|
|
1711
|
-
tags=a.get("tags"), condition_space=a.get("condition_space"),
|
|
1712
|
-
**_proposal_extras(a, verdict))
|
|
1713
|
-
return {"ok": True, "id": nid, "pid": pid, "committed": False,
|
|
1714
|
-
"moved_to": "review_queue", "verdict": verdict,
|
|
1715
|
-
"hint": "这是校验闸门的正常行为(verdict=%s):内容未达 ACCEPT,"
|
|
1716
|
-
"已入审核队列——不需要重试;落盘须由设计者权限(can_admin)"
|
|
1717
|
-
"对提案 pid 裁决(agent 端无裁决权是设计),转告使用者:"
|
|
1718
|
-
"python scripts/review_cli.py list 后 accept/reject,"
|
|
1719
|
-
"或 cg(op=review, pid=<pid>, decision=accept|reject|"
|
|
1720
|
-
"edit|merge, reason=<理由>)" % verdict.get("state")}
|
|
1899
|
+
# 写入路径拦截器链(Pi 钩子化移植,writepipe.py):六道闸以扩展
|
|
1900
|
+
# 形态注册于 writepipe.default_pipeline(),次序/启停不再硬编码于
|
|
1901
|
+
# 本文件;新增闸门 = register_before 一行,即插即拔。
|
|
1902
|
+
# 角色/层权限校验在 MdCGSecure.add 库层,结构上不可被拦截器绕过。
|
|
1903
|
+
from .writepipe import default_pipeline
|
|
1904
|
+
return default_pipeline().execute(cg, a)
|
|
1721
1905
|
|
|
1722
1906
|
if op == "goal":
|
|
1723
1907
|
act = (a.get("action") or "list").strip().lower()
|
|
@@ -1738,6 +1922,9 @@ def _cg_dispatch(cg, a):
|
|
|
1738
1922
|
limit=int(a.get("limit") or 20)),
|
|
1739
1923
|
"active": cg.active_goals(limit=int(a.get("limit") or 5))}
|
|
1740
1924
|
|
|
1925
|
+
if op == "task":
|
|
1926
|
+
return _task_call(cg, a)
|
|
1927
|
+
|
|
1741
1928
|
if op == "recent":
|
|
1742
1929
|
act = (a.get("action") or "list").strip().lower()
|
|
1743
1930
|
if act in ("add", "append", "remember"):
|
|
@@ -1898,9 +2085,182 @@ def _cg_dispatch(cg, a):
|
|
|
1898
2085
|
if op == "insight":
|
|
1899
2086
|
return _insight_call(cg, a)
|
|
1900
2087
|
|
|
2088
|
+
if op == "ccg":
|
|
2089
|
+
return _ccg_call(cg, a)
|
|
2090
|
+
|
|
1901
2091
|
raise ValueError(f"cg 未知 op:{op}")
|
|
1902
2092
|
|
|
1903
2093
|
|
|
2094
|
+
def _ccg_call(cg, a):
|
|
2095
|
+
"""CCG 六要素编译器(op=ccg):对话记录 → 六要素候选 → **编外复核** → 落库。
|
|
2096
|
+
|
|
2097
|
+
定位:**记忆可靠性闸**——不是又一个写入通道,而是写入前「条件是否成立」的检查。
|
|
2098
|
+
裁定 A(LLM 不得自己验证自己)由 ccgc 的 E041 **机械执行**,不依赖 prompt 自觉。
|
|
2099
|
+
|
|
2100
|
+
action(缺省 compile):
|
|
2101
|
+
compile 对话记录 → 六要素候选(五环编译);候选+签章槽落
|
|
2102
|
+
`_ccgc_pending/<node_id>.json`(**不当场写库**)
|
|
2103
|
+
review 派发编外复核单元:**蜂巢 reflect/verify 优先** → 不可用则提示配置
|
|
2104
|
+
→ 显式 allow_degrade 才降级 harness 端子代理;拿到裁决即自动签章
|
|
2105
|
+
attest 外部裁决签章(verifier 须 != compiled_by;E041/E042 机械把关)
|
|
2106
|
+
link 读回候选+签章 → 准入校验 → apply=True 落库(成功后清 pending)
|
|
2107
|
+
recalibrate 四槽修正(须编外验证方;E043 只放开 condition_space 四槽)
|
|
2108
|
+
units 复核通道体检/计划(hive → 提示配置 → 子代理 三级链)
|
|
2109
|
+
catalog 引擎自描述(错误码/契约角色/动作清单)
|
|
2110
|
+
|
|
2111
|
+
入参集中在 `ccg` 对象里(与 `redteam`/`verify` 同风格)——避免与既有扁平参数
|
|
2112
|
+
重名(如 `verdict` 在 verify 面是 confirmed|weakened|falsified,语义不同)。
|
|
2113
|
+
|
|
2114
|
+
返回语义:`ok` 表示**本次请求本身**是否成立;`verdict` 是单元给出的裁决
|
|
2115
|
+
(未复核为 None);`passed` = 裁决为 ACCEPT。三者分开,避免「派发成功」
|
|
2116
|
+
被误读成「复核通过」。
|
|
2117
|
+
|
|
2118
|
+
权限:编译器属写路径 → 记录/设计者角色可用(见 tokens.ALL_OPS 的 ccg 条目)。
|
|
2119
|
+
attest/link 的准入**不靠 admin 闸**,而靠签章机械闸(E040/E041/E042)——理由:
|
|
2120
|
+
默认部署(未设 MDCG_CAN_ADMIN)下再加 admin 会让编译器对使用者不可见
|
|
2121
|
+
(「权限到位但通路不可见」是既有教训),而裁定 A 的保证本就在机械闸里。
|
|
2122
|
+
"""
|
|
2123
|
+
from . import ccgc
|
|
2124
|
+
from . import units as _units
|
|
2125
|
+
|
|
2126
|
+
o = a.get("ccg") or {}
|
|
2127
|
+
if not isinstance(o, dict):
|
|
2128
|
+
return {"ok": False, "op": "ccg",
|
|
2129
|
+
"error": "ccg 参数须为对象:{action, node_id, dialog, ...}"}
|
|
2130
|
+
act = str(o.get("action") or a.get("action") or "compile").strip().lower()
|
|
2131
|
+
node_id = str(o.get("node_id") or a.get("node_id") or "").strip()
|
|
2132
|
+
actor = str(getattr(getattr(cg, "principal", None), "actor", "") or o.get("actor") or "agent")
|
|
2133
|
+
jobs = str(o.get("jobs") or "")
|
|
2134
|
+
|
|
2135
|
+
if act == "catalog":
|
|
2136
|
+
return {"ok": True, "op": "ccg", "action": "catalog",
|
|
2137
|
+
"actions": ["compile", "review", "attest", "link", "recalibrate",
|
|
2138
|
+
"units", "catalog"],
|
|
2139
|
+
"states": list(ccgc.STATES), "contract_roles": list(ccgc.CONTRACT_ROLES),
|
|
2140
|
+
"errors": dict(ccgc.E_CODES),
|
|
2141
|
+
"rule": "裁定 A:验证方标识不得等于编译执行者(E041);缺签章不写库(E040);"
|
|
2142
|
+
"未通过不写库(E042)"}
|
|
2143
|
+
|
|
2144
|
+
if act == "units":
|
|
2145
|
+
if o.get("doctor"):
|
|
2146
|
+
return {"ok": True, "op": "ccg", "action": "units", **_units.doctor(jobs)}
|
|
2147
|
+
p = _units.plan(jobs=jobs, model=o.get("model") or "",
|
|
2148
|
+
allow_degrade=bool(o.get("allow_degrade")),
|
|
2149
|
+
channel=o.get("channel") or "")
|
|
2150
|
+
return {"ok": True, "op": "ccg", "action": "units", **p}
|
|
2151
|
+
|
|
2152
|
+
if act == "compile":
|
|
2153
|
+
dialog = str(o.get("dialog") or o.get("content") or a.get("content") or "")
|
|
2154
|
+
if not dialog.strip():
|
|
2155
|
+
return {"ok": False, "op": "ccg", "action": "compile",
|
|
2156
|
+
"error": "缺对话记录:传 ccg.dialog(或顶层 content)"}
|
|
2157
|
+
if not node_id:
|
|
2158
|
+
return {"ok": False, "op": "ccg", "action": "compile",
|
|
2159
|
+
"error": "缺 node_id:六要素候选须指明目标节点"}
|
|
2160
|
+
res = ccgc.compile_dialog(dialog, node_id, actor,
|
|
2161
|
+
marks=o.get("marks"), slots=o.get("slots"),
|
|
2162
|
+
strict_spans=bool(o.get("strict_spans", True)), cg=cg)
|
|
2163
|
+
saved = ccgc.save_pending(cg, res)
|
|
2164
|
+
return {"ok": bool(res.success), "op": "ccg", "action": "compile",
|
|
2165
|
+
"compiled": ccgc.asdict(res), "pending": saved,
|
|
2166
|
+
"actor": actor, "compiled_by": actor,
|
|
2167
|
+
"hint": ("候选已落 pending;下一步 cg(op=ccg, action=review, "
|
|
2168
|
+
"ccg={node_id, blocking:true}) 交编外单元复核"
|
|
2169
|
+
"——编译者不得自证(E041)" if res.success else
|
|
2170
|
+
"编译未通过:" + (res.errors[0] if res.errors else "未知错误"))}
|
|
2171
|
+
|
|
2172
|
+
if act == "review":
|
|
2173
|
+
got = ccgc.load_pending(cg, node_id)
|
|
2174
|
+
if not got.get("ok") or not got.get("hash_ok"):
|
|
2175
|
+
return {"ok": False, "op": "ccg", "action": "review",
|
|
2176
|
+
"error": got.get("error") or "pending 产物与编译时不一致(hash 不符)",
|
|
2177
|
+
"hint": "先 cg(op=ccg, action=compile, ccg={node_id, dialog}) 生成候选"}
|
|
2178
|
+
compiled = got["compiled"]
|
|
2179
|
+
role = str(o.get("role") or _units.REFLECT).strip().lower()
|
|
2180
|
+
prompt = _units.prompt_for(role, compiled, dialog=str(o.get("dialog") or ""))
|
|
2181
|
+
r = _units.review(prompt=prompt, role=role, node_id=node_id, jobs=jobs,
|
|
2182
|
+
model=o.get("model") or "",
|
|
2183
|
+
timeout_s=int(o.get("timeout_s") or _units.DEFAULT_TIMEOUT_S),
|
|
2184
|
+
allow_degrade=bool(o.get("allow_degrade")),
|
|
2185
|
+
channel=o.get("channel") or "",
|
|
2186
|
+
wait_s=float(o.get("wait_s") or _units.DEFAULT_TIMEOUT_S),
|
|
2187
|
+
blocking=bool(o.get("blocking")), cg=cg, actor=actor,
|
|
2188
|
+
autostart=bool(o.get("autostart")))
|
|
2189
|
+
unit = r.get("unit")
|
|
2190
|
+
out = {"ok": True, "op": "ccg", "action": "review", "state": r["state"],
|
|
2191
|
+
"role": role, "node_id": node_id, "job_id": r.get("job_id"),
|
|
2192
|
+
"transport": r.get("transport"), "verdict": (unit or {}).get("verdict"),
|
|
2193
|
+
"passed": bool((unit or {}).get("verdict") == ccgc.ACCEPT),
|
|
2194
|
+
"unit": unit, "channel": r.get("channel") or "",
|
|
2195
|
+
"blocking": bool(o.get("blocking")), "hint": r.get("hint") or ""}
|
|
2196
|
+
if r["state"] != _units.HIVE:
|
|
2197
|
+
out["ok"] = False
|
|
2198
|
+
out["prompt"] = r.get("prompt") # 降级/配置路径:把复核请求包交回调用方
|
|
2199
|
+
return out
|
|
2200
|
+
if unit: # 已获编外裁决 → 自动签章
|
|
2201
|
+
args = r.get("attest") or {}
|
|
2202
|
+
at = ccgc.attest(node_id, args.get("verdict") or ccgc.DEFER,
|
|
2203
|
+
args.get("verifier") or "", compiled.actor or actor,
|
|
2204
|
+
slot_corrections=args.get("slot_corrections"),
|
|
2205
|
+
evidence=args.get("evidence") or "", cg=cg)
|
|
2206
|
+
out["attest"] = ccgc.asdict(at)
|
|
2207
|
+
out["pending"] = ccgc.save_pending(cg, compiled, at)
|
|
2208
|
+
out["hint"] = ("已签章(%s);下一步 cg(op=ccg, action=link, "
|
|
2209
|
+
"ccg={node_id, apply:true}) 落库"
|
|
2210
|
+
% (args.get("verifier") or "-") if at.ok else
|
|
2211
|
+
"签章未通过:" + (at.error or "DEFER/REJECT 不构成准入"))
|
|
2212
|
+
return out
|
|
2213
|
+
|
|
2214
|
+
if act == "attest":
|
|
2215
|
+
got = ccgc.load_pending(cg, node_id)
|
|
2216
|
+
if not got.get("ok") or not got.get("hash_ok"):
|
|
2217
|
+
return {"ok": False, "op": "ccg", "action": "attest",
|
|
2218
|
+
"error": got.get("error") or "pending 产物与编译时不一致(hash 不符)",
|
|
2219
|
+
"hint": "先 cg(op=ccg, action=compile, ...) 生成候选"}
|
|
2220
|
+
compiled = got["compiled"]
|
|
2221
|
+
at = ccgc.attest(node_id, str(o.get("verdict") or ""),
|
|
2222
|
+
str(o.get("verifier") or ""),
|
|
2223
|
+
str(o.get("compiled_by") or compiled.actor or actor),
|
|
2224
|
+
slot_corrections=o.get("slot_corrections"),
|
|
2225
|
+
evidence=str(o.get("evidence") or ""), cg=cg)
|
|
2226
|
+
return {"ok": bool(at.ok), "op": "ccg", "action": "attest",
|
|
2227
|
+
"attest": ccgc.asdict(at),
|
|
2228
|
+
"pending": ccgc.save_pending(cg, compiled, at),
|
|
2229
|
+
"hint": ("签章通过;下一步 cg(op=ccg, action=link, ccg={node_id, apply:true})"
|
|
2230
|
+
if at.ok else "签章未通过:" + (at.error or "DEFER/REJECT 不构成准入"))}
|
|
2231
|
+
|
|
2232
|
+
if act == "link":
|
|
2233
|
+
apply = bool(o.get("apply"))
|
|
2234
|
+
res = ccgc.link_pending(cg, node_id, apply=apply, actor=actor,
|
|
2235
|
+
basis=str(o.get("basis") or "ccgc link"))
|
|
2236
|
+
return {"ok": bool(res.ok), "op": "ccg", "action": "link", "apply": apply,
|
|
2237
|
+
"link": ccgc.asdict(res),
|
|
2238
|
+
"hint": ("已落库(entry_id=%s,written=%s)" % (res.entry_id, res.written)
|
|
2239
|
+
if res.ok and apply else
|
|
2240
|
+
("准入通过(dry_run 未写库);apply=true 才落库" if res.ok else
|
|
2241
|
+
";".join(res.errors or []) or "准入未通过"))}
|
|
2242
|
+
|
|
2243
|
+
if act == "recalibrate":
|
|
2244
|
+
corr = o.get("slot_corrections") or o.get("corrections") or {}
|
|
2245
|
+
verifier = str(o.get("verifier") or "").strip()
|
|
2246
|
+
compiled_by = str(o.get("compiled_by") or "").strip()
|
|
2247
|
+
if not verifier or verifier == compiled_by:
|
|
2248
|
+
return {"ok": False, "op": "ccg", "action": "recalibrate",
|
|
2249
|
+
"error": "E041 自证拒绝:recalibrate 须由编外验证方给出"
|
|
2250
|
+
"(verifier 必填且 != compiled_by)"}
|
|
2251
|
+
res = ccgc.recalibrate(node_id, corr, verifier, compiled_by,
|
|
2252
|
+
evidence=str(o.get("evidence") or ""), cg=cg,
|
|
2253
|
+
apply=bool(o.get("apply")))
|
|
2254
|
+
return {"ok": bool(res.ok), "op": "ccg", "action": "recalibrate",
|
|
2255
|
+
"recalibrate": ccgc.asdict(res),
|
|
2256
|
+
"hint": (";".join(res.errors or []) or "修正已应用(apply=true)" if res.ok
|
|
2257
|
+
else ";".join(res.errors or []) or "修正未通过")}
|
|
2258
|
+
|
|
2259
|
+
return {"ok": False, "op": "ccg", "action": act,
|
|
2260
|
+
"error": "ccg 未知 action:%s(可选 compile|review|attest|link|recalibrate|"
|
|
2261
|
+
"units|catalog)" % act}
|
|
2262
|
+
|
|
2263
|
+
|
|
1904
2264
|
def _session_call(cg, a):
|
|
1905
2265
|
"""会话三件套(P0):note 写要点 / recall 续接 / compact 压摘要。
|
|
1906
2266
|
|
|
@@ -2103,13 +2463,16 @@ def _consolidate_call(cg, a):
|
|
|
2103
2463
|
|
|
2104
2464
|
def _insight_call(cg, a):
|
|
2105
2465
|
"""洞察(P2):window / record / verify / list / report / reconstruct / learn /
|
|
2106
|
-
outlook / catalog
|
|
2466
|
+
outlook / catalog / fork / branch_rewrite / branch_search / branch_merge /
|
|
2467
|
+
branch_discard / branches。
|
|
2107
2468
|
|
|
2108
2469
|
权限**按 action 分档**(与 maintain 同构,比整 op 收窄更贴合语义):
|
|
2109
|
-
· 只读(window / list / report / reconstruct 预演 / outlook / catalog
|
|
2110
|
-
|
|
2111
|
-
· 条件层记账(record / verify
|
|
2112
|
-
|
|
2470
|
+
· 只读(window / list / report / reconstruct 预演 / outlook / catalog /
|
|
2471
|
+
branch_search / branches / fork 预演)→ 不额外拦截;
|
|
2472
|
+
· 条件层记账(record / verify)与分支写操作(fork / branch_rewrite /
|
|
2473
|
+
branch_merge)→ 需 can_write;
|
|
2474
|
+
· 落库(reconstruct apply / learn apply)与分支弃置(branch_discard,
|
|
2475
|
+
改变库可见性)→ require_admin(discard 库层还有第二道闸)。
|
|
2113
2476
|
这样 output 角色能读洞察但不能记;reflect 能重构与学习预演;批量落库须请示。
|
|
2114
2477
|
"""
|
|
2115
2478
|
act = (a.get("action") or "outlook").strip().lower()
|
|
@@ -2119,18 +2482,26 @@ def _insight_call(cg, a):
|
|
|
2119
2482
|
actor = getattr(principal, "actor", None) if principal is not None else None
|
|
2120
2483
|
if principal is not None and act in ("record", "verify") and not can_write:
|
|
2121
2484
|
principal.require_admin(f"insight_{act}") # 无写权 → 抛 AccessDenied
|
|
2485
|
+
if principal is not None and act in ("fork", "branch_rewrite",
|
|
2486
|
+
"branch_merge") and not can_write:
|
|
2487
|
+
principal.require_admin(f"insight_{act}") # 分支写 → 需写权
|
|
2122
2488
|
if principal is not None and act in ("reconstruct", "learn") and apply:
|
|
2123
2489
|
principal.require_admin(f"insight_{act}")
|
|
2490
|
+
if principal is not None and act == "branch_discard":
|
|
2491
|
+
principal.require_admin("branch_discard") # 弃置:分发层+库层双闸
|
|
2124
2492
|
return cg.insight(
|
|
2125
2493
|
action=act, layer=a.get("layer"), limit=a.get("limit"),
|
|
2126
2494
|
conditions=a.get("conditions"), apply=apply, actor=actor,
|
|
2127
2495
|
statement=a.get("statement"), category=a.get("category"),
|
|
2128
2496
|
source=a.get("source"), tags=a.get("tags"),
|
|
2129
2497
|
importance=a.get("importance"), node_id=a.get("node_id"),
|
|
2498
|
+
content=a.get("content"),
|
|
2130
2499
|
evidence=a.get("evidence"), v_types=a.get("v_types"),
|
|
2131
2500
|
verdict=a.get("verdict"), state=a.get("state"),
|
|
2132
2501
|
window_days=a.get("window_days"), clues=a.get("clues"),
|
|
2133
2502
|
ids=a.get("ids"), neighbors=a.get("neighbors"),
|
|
2503
|
+
branch_id=a.get("branch_id"), note=a.get("note"),
|
|
2504
|
+
reason=a.get("reason"),
|
|
2134
2505
|
blindspot_id=a.get("blindspot_id"), horizon=a.get("horizon"),
|
|
2135
2506
|
max_branches=a.get("max_branches"), recent_days=a.get("recent_days"),
|
|
2136
2507
|
sample_limit=a.get("sample_limit"), max_nodes=a.get("max_nodes"))
|
|
@@ -2208,7 +2579,7 @@ def _whitebox_call(cg, a):
|
|
|
2208
2579
|
"""显式调用白箱能力库(AEIS 降为本地库后的唯一入口)。
|
|
2209
2580
|
|
|
2210
2581
|
显式调用映射:md_cg.whitebox.dispatch
|
|
2211
|
-
见 docs/功能调用映射表_v0.1.md。
|
|
2582
|
+
见 docs/mdcg/功能调用映射表_v0.1.md。
|
|
2212
2583
|
"""
|
|
2213
2584
|
from . import whitebox
|
|
2214
2585
|
return whitebox.dispatch(cg, a)
|
|
@@ -2230,7 +2601,13 @@ def _stg_call(cg, a):
|
|
|
2230
2601
|
if op == "consistency":
|
|
2231
2602
|
return stg.consistency(cg, layer=a.get("layer"),
|
|
2232
2603
|
limit=int(a.get("limit") or 50))
|
|
2233
|
-
|
|
2604
|
+
if not op:
|
|
2605
|
+
# fail-closed 且给出可操作提示:stg 的 op 四值签名区分度低于 cg(relation 需
|
|
2606
|
+
# a+b、timeline/anchors/consistency 皆以 layer+limit 为主),**不做签名推导**
|
|
2607
|
+
# ——猜错会静默返回错误视图,比报错更贵。
|
|
2608
|
+
raise ValueError("stg 的 op 为必填参数(缺失即报错,不静默降级);"
|
|
2609
|
+
"允许 op:relation | timeline | anchors | consistency")
|
|
2610
|
+
raise ValueError(f"stg 未知 op:{op}(允许 relation | timeline | anchors | consistency)")
|
|
2234
2611
|
|
|
2235
2612
|
|
|
2236
2613
|
# --------------------------------------------------------------------------
|
|
@@ -2371,7 +2748,8 @@ def _dispatch(cg, name, args):
|
|
|
2371
2748
|
for n, s, q in res]}
|
|
2372
2749
|
|
|
2373
2750
|
if name == "mdcg_get":
|
|
2374
|
-
return _node_view(cg.get(a.get("node_id", ""))
|
|
2751
|
+
return _node_view(cg.get(a.get("node_id", "")),
|
|
2752
|
+
offset=int(a.get("offset") or 0))
|
|
2375
2753
|
|
|
2376
2754
|
if name == "mdcg_reflect":
|
|
2377
2755
|
res, _ = cg.search(a.get("query", ""), k=int(a.get("k") or 10), record=False)
|
|
@@ -2396,10 +2774,18 @@ def _dispatch(cg, name, args):
|
|
|
2396
2774
|
a.get("goal", ""))}
|
|
2397
2775
|
|
|
2398
2776
|
if name == "mdcg_propose":
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2777
|
+
pr = cg.propose(a.get("node_id", ""), a.get("content", ""), info=True,
|
|
2778
|
+
layer=a.get("layer") or "knowledge",
|
|
2779
|
+
tags=a.get("tags"), condition_space=a.get("condition_space"),
|
|
2780
|
+
**_proposal_extras(a))
|
|
2781
|
+
out = {"pid": pr["pid"], "dedup": bool(pr.get("dedup"))}
|
|
2782
|
+
if pr.get("dedup"):
|
|
2783
|
+
out["dup_of"] = pr["pid"]
|
|
2784
|
+
out["dup_status"] = pr.get("dup_status")
|
|
2785
|
+
out["hint"] = ("同内容提案已存在(pid=%s,状态=%s),幂等返回既有提案、"
|
|
2786
|
+
"未重复入队,无需重试"
|
|
2787
|
+
% (pr["pid"], pr.get("dup_status") or "pending"))
|
|
2788
|
+
return out
|
|
2403
2789
|
|
|
2404
2790
|
if name == "mdcg_review_list":
|
|
2405
2791
|
return {"pending": cg.review_list()}
|
|
@@ -2678,7 +3064,14 @@ def main():
|
|
|
2678
3064
|
_p_session = os.environ.get("MDCG_SESSION", "").strip()
|
|
2679
3065
|
if _p_session:
|
|
2680
3066
|
principal.session = _p_session
|
|
2681
|
-
|
|
3067
|
+
# 索引可见性(2026-09-16):autoflush=1 —— 逐条写入立即落分片日志
|
|
3068
|
+
# `_index_log/`。根因(第4条取证):默认 autoflush=64 且常驻进程不 close,
|
|
3069
|
+
# 单条写入在达阈值前**对其他进程不可见**(`_load_index` = 快照 + 分片日志
|
|
3070
|
+
# 重放;`_index.json` 只在 compact/rebuild 时重写),表现为「写入返回
|
|
3071
|
+
# committed=true 但第16条读回确认在跨进程读面上不可检索」。本参数是
|
|
3072
|
+
# server 级兜底:覆盖不经 writepipe 写链的路径(propose / remember_gated /
|
|
3073
|
+
# add_rejected 等);写链另有显式提交边界(writepipe._commit_visibility)。
|
|
3074
|
+
cg = MdCGSecure(root, principal=principal, autoflush=1)
|
|
2682
3075
|
# 外部验证器注入(**能力外置**):识图/实测/验收等能力不在认知图内,
|
|
2683
3076
|
# 由 MDCG_VERIFIER_MODULES(逗号分隔 import 路径)声明的外部模块注入,
|
|
2684
3077
|
# 通常位于私有运行时仓。加载失败不阻塞启动——失败原因写进 stderr 与
|
|
@@ -2688,6 +3081,20 @@ def main():
|
|
|
2688
3081
|
if _verifiers.get("loaded") or _verifiers.get("failed"):
|
|
2689
3082
|
sys.stderr.write("[mdcg-mcp] 外部验证器: loaded=%s failed=%s\n"
|
|
2690
3083
|
% (_verifiers.get("loaded"), _verifiers.get("failed")))
|
|
3084
|
+
# ③ 两段式对账:上个进程若被杀在「落盘前后」之间,账本里会留下「有意图
|
|
3085
|
+
# 无结果」的写入——启动即清账(内容确已落盘 → 补账 committed;没落上 →
|
|
3086
|
+
# 如实标记 interrupted)。失败**不阻塞启动**:对账是增益,不是服务前提,
|
|
3087
|
+
# 但必须上报(stderr),不静默。
|
|
3088
|
+
try:
|
|
3089
|
+
_rep = cg.reconcile_writes()
|
|
3090
|
+
if _rep.get("unpaired"):
|
|
3091
|
+
sys.stderr.write("[mdcg-mcp] 写入两段式对账: 未结清=%s 补账=%s "
|
|
3092
|
+
"中断=%s\n" % (_rep.get("unpaired"),
|
|
3093
|
+
_rep.get("committed"),
|
|
3094
|
+
_rep.get("interrupted")))
|
|
3095
|
+
except Exception as _exc: # 对账故障不得影响服务可用性
|
|
3096
|
+
sys.stderr.write("[mdcg-mcp] 两段式对账失败(不阻塞启动): %r\n"
|
|
3097
|
+
% (_exc,))
|
|
2691
3098
|
_start_sustain(cg)
|
|
2692
3099
|
|
|
2693
3100
|
for line in sys.stdin:
|