liquid-loop 0.6.4__tar.gz → 0.7.0__tar.gz

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.
Files changed (27) hide show
  1. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/PKG-INFO +23 -2
  2. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/README.md +22 -1
  3. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop/__init__.py +3 -3
  4. liquid_loop-0.7.0/liquid_loop/mesh/__init__.py +50 -0
  5. liquid_loop-0.7.0/liquid_loop/mesh/v2.py +173 -0
  6. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop/storage.py +27 -1
  7. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop/workspace.py +60 -13
  8. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop.egg-info/PKG-INFO +23 -2
  9. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop.egg-info/SOURCES.txt +4 -0
  10. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/pyproject.toml +1 -1
  11. liquid_loop-0.7.0/tests/test_consensus_expansion.py +45 -0
  12. liquid_loop-0.7.0/tests/test_nucleate_dual_track.py +115 -0
  13. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/LICENSE +0 -0
  14. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop/__main__.py +0 -0
  15. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop/cli.py +0 -0
  16. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop/cognitive_budget.py +0 -0
  17. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop/entropy.py +0 -0
  18. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop.egg-info/dependency_links.txt +0 -0
  19. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop.egg-info/entry_points.txt +0 -0
  20. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop.egg-info/requires.txt +0 -0
  21. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/liquid_loop.egg-info/top_level.txt +0 -0
  22. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/setup.cfg +0 -0
  23. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/tests/test_entropy.py +0 -0
  24. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/tests/test_peek_seal.py +0 -0
  25. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/tests/test_seal_persistence.py +0 -0
  26. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/tests/test_self_evolve.py +0 -0
  27. {liquid_loop-0.6.4 → liquid_loop-0.7.0}/tests/test_workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liquid-loop
3
- Version: 0.6.4
3
+ Version: 0.7.0
4
4
  Summary: Self-Organizing Cognitive Memory for AI Agents — Liquid Loop theory implementation
5
5
  Author: fishbook0001
6
6
  Maintainer: fishbook0001
@@ -147,6 +147,26 @@ liquid-loop snapshot
147
147
 
148
148
  ---
149
149
 
150
+ ## MESH 集成(多智能体共识)
151
+
152
+ 液环从 v0.7.0 起内置官方 MESH 集成 `liquid_loop.mesh`,把"多智能体共识协议"落地为可复用代码,作为 agent-mesh 节点的标准接入层。
153
+
154
+ ```python
155
+ from liquid_loop.mesh import validate_evidence, compute_cci, cognitive_health, fetch_state
156
+
157
+ # agent 写入前契约自检(零向量:content 必须精确字符串,禁 embedding)
158
+ ok, errs = validate_evidence({"agent_id": "vera", "content": "用户偏好简洁输出"})
159
+
160
+ # 从 8790 拉取记忆状态,算主体间性共识指数 CCI
161
+ items = fetch_state("http://127.0.0.1:8790")
162
+ health = cognitive_health(items)
163
+ print(health["CCI"], health["consensus_crystals"])
164
+ ```
165
+
166
+ 零向量哲学:一致性判定走**结构化精确相等 + 审计链哈希**,绝不引入任何 embedding / 相似度。规范详见 `mesh/liquid_loop_mesh_v2_spec.md`。
167
+
168
+ ---
169
+
150
170
  ## 架构对比
151
171
 
152
172
  ```
@@ -194,6 +214,7 @@ liquid-loop/
194
214
  │ ├── workspace.py # 核心数据模型 + AuditChain + auto_classify + decay
195
215
  │ ├── storage.py # JSON 持久化 + 审计链写入
196
216
  │ ├── entropy.py # 四维熵值计算
217
+ │ ├── mesh/ # MESH v2 多智能体共识协议集成(validate_evidence / compute_cci / ...)
197
218
  │ └── cli.py # Click CLI (11 命令)
198
219
  ├── examples/
199
220
  │ └── quickstart.py
@@ -220,7 +241,7 @@ pytest -v
220
241
  ## 路线图
221
242
 
222
243
  - [ ] 语义一致性结晶(嵌入相似度替代精确匹配)
223
- - [ ] 多 Agent 液环耦合
244
+ - [x] 多 Agent 液环耦合(`liquid_loop.mesh` v2 共识协议,2026-07-15 落地)
224
245
  - [ ] LX 扩展:世界模型预测纳入液环
225
246
  - [ ] LoCoMo / LongMemEval 基准对比
226
247
  - [ ] 边缘端部署优化(<50KB)
@@ -108,6 +108,26 @@ liquid-loop snapshot
108
108
 
109
109
  ---
110
110
 
111
+ ## MESH 集成(多智能体共识)
112
+
113
+ 液环从 v0.7.0 起内置官方 MESH 集成 `liquid_loop.mesh`,把"多智能体共识协议"落地为可复用代码,作为 agent-mesh 节点的标准接入层。
114
+
115
+ ```python
116
+ from liquid_loop.mesh import validate_evidence, compute_cci, cognitive_health, fetch_state
117
+
118
+ # agent 写入前契约自检(零向量:content 必须精确字符串,禁 embedding)
119
+ ok, errs = validate_evidence({"agent_id": "vera", "content": "用户偏好简洁输出"})
120
+
121
+ # 从 8790 拉取记忆状态,算主体间性共识指数 CCI
122
+ items = fetch_state("http://127.0.0.1:8790")
123
+ health = cognitive_health(items)
124
+ print(health["CCI"], health["consensus_crystals"])
125
+ ```
126
+
127
+ 零向量哲学:一致性判定走**结构化精确相等 + 审计链哈希**,绝不引入任何 embedding / 相似度。规范详见 `mesh/liquid_loop_mesh_v2_spec.md`。
128
+
129
+ ---
130
+
111
131
  ## 架构对比
112
132
 
113
133
  ```
@@ -155,6 +175,7 @@ liquid-loop/
155
175
  │ ├── workspace.py # 核心数据模型 + AuditChain + auto_classify + decay
156
176
  │ ├── storage.py # JSON 持久化 + 审计链写入
157
177
  │ ├── entropy.py # 四维熵值计算
178
+ │ ├── mesh/ # MESH v2 多智能体共识协议集成(validate_evidence / compute_cci / ...)
158
179
  │ └── cli.py # Click CLI (11 命令)
159
180
  ├── examples/
160
181
  │ └── quickstart.py
@@ -181,7 +202,7 @@ pytest -v
181
202
  ## 路线图
182
203
 
183
204
  - [ ] 语义一致性结晶(嵌入相似度替代精确匹配)
184
- - [ ] 多 Agent 液环耦合
205
+ - [x] 多 Agent 液环耦合(`liquid_loop.mesh` v2 共识协议,2026-07-15 落地)
185
206
  - [ ] LX 扩展:世界模型预测纳入液环
186
207
  - [ ] LoCoMo / LongMemEval 基准对比
187
208
  - [ ] 边缘端部署优化(<50KB)
@@ -1,10 +1,10 @@
1
- """Liquid Loop — Workspace Cognitive Runtime v0.6.1 (CPE-fused, proactive, rhythmic sampling)"""
2
- __version__ = "0.6.1"
1
+ """Liquid Loop — Workspace Cognitive Runtime v0.7.0 (CPE-fused, SEAL dual-opt, dual-track multi-agent, MESH v2 integration)"""
2
+ __version__ = "0.7.0"
3
3
 
4
4
  from .workspace import (
5
5
  WorkspaceState, Anchor, Evidence, Memory, Conflict,
6
6
  AuditChain, CPERegularizer, SelfRefineEngine,
7
7
  rhythmic_retrieve,
8
8
  )
9
- from .storage import load, save
9
+ from .storage import load, save, locked_state
10
10
  from .entropy import calculate, calculate_detail, calculate as calculate_entropy
@@ -0,0 +1,50 @@
1
+ """
2
+ liquid_loop.mesh — 液环 MESH 进阶版(v2)共识协议集成
3
+ =====================================================
4
+ 把"多智能体共识协议规范"从文档落地为可复用代码,作为 liquid-loop 的官方
5
+ MESH 集成层。零向量哲学:一致性判定走结构化精确相等 + 审计链哈希,绝不引入
6
+ 任何 embedding / 相似度。
7
+
8
+ 职责(详见 .v2):
9
+ - validate_evidence() agent 侧契约自检(结构化证据 schema)
10
+ - check_contract() 双向契约合规检查(身份 / 写 / 消费 / 冲突)
11
+ - compute_cci() 主体间性共识指数(记忆层)
12
+ - cognitive_health() 统一认知健康仪表盘(CCI / drift / H_e / P_mem)
13
+ - detect_conflict() 同锚点冲突证据检测
14
+ - fetch_state() 从 8790 REST /list 拉取当前状态
15
+ - main() 连接 8790 打印认知健康报告(CLI)
16
+
17
+ 快速使用:
18
+ from liquid_loop.mesh import validate_evidence, compute_cci, cognitive_health
19
+ from liquid_loop.mesh import fetch_state, main
20
+
21
+ ok, errs = validate_evidence({"agent_id": "vera", "content": "..."})
22
+ health = cognitive_health(fetch_state())
23
+ """
24
+ from .v2 import (
25
+ REGISTRY,
26
+ CLAIM_TYPES,
27
+ SCOPES,
28
+ Evidence,
29
+ validate_evidence,
30
+ check_contract,
31
+ compute_cci,
32
+ cognitive_health,
33
+ detect_conflict,
34
+ fetch_state,
35
+ main,
36
+ )
37
+
38
+ __all__ = [
39
+ "REGISTRY",
40
+ "CLAIM_TYPES",
41
+ "SCOPES",
42
+ "Evidence",
43
+ "validate_evidence",
44
+ "check_contract",
45
+ "compute_cci",
46
+ "cognitive_health",
47
+ "detect_conflict",
48
+ "fetch_state",
49
+ "main",
50
+ ]
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ liquid_loop_mesh_v2.py — 液环 MESH 进阶版(v2)参考实现
4
+ ======================================================
5
+ 把"共识协议规范"从文档落地为可复用代码。零向量哲学:一致性判定走
6
+ 结构化精确相等 + 审计链哈希,绝不引入任何 embedding / 相似度。
7
+
8
+ 职责:
9
+ 1. validate_evidence() — agent 侧契约自检(结构化证据 schema)
10
+ 2. check_contract() — 双向契约合规检查(身份/写/消费/冲突)
11
+ 3. compute_cci() — 主体间性共识指数(记忆层)
12
+ 4. cognitive_health() — 统一认知健康仪表盘(CCI / drift / H_e / P_mem)
13
+ 5. detect_conflict() — 同锚点冲突证据检测
14
+ 6. fetch_state() — 从 8790 REST /list 拉取当前状态
15
+
16
+ 依赖:标准库 + 可选 liquid_loop(仅类型提示)。可直接 import 使用,
17
+ 也可 `python3 liquid_loop_mesh_v2.py` 连 8790 打印健康报告。
18
+ """
19
+ from __future__ import annotations
20
+ import json
21
+ import sys
22
+ import urllib.request
23
+ from dataclasses import dataclass, field
24
+ from typing import Optional
25
+
26
+ # ── agent-mesh 注册表(接入 agent 的唯一 id 白名单)──────────────
27
+ REGISTRY = {"workbuddy", "vera", "qwenpaw", "marvis", "parlant-ctrl", "cawpaw", "tabbit", "llama"}
28
+
29
+ CLAIM_TYPES = {"fact", "conclusion", "preference", "conflict"}
30
+ SCOPES = {"private", "consensus"}
31
+
32
+
33
+ # ── 1. 结构化证据 schema 校验 ──────────────────────────────────
34
+ @dataclass
35
+ class Evidence:
36
+ agent_id: str
37
+ content: str
38
+ category: str = "fact"
39
+ claim_type: str = "fact"
40
+ value: Optional[float] = None
41
+ session_id: str = ""
42
+ prev_hash: str = ""
43
+ id: str = ""
44
+
45
+ def to_dict(self) -> dict:
46
+ return {
47
+ "agent_id": self.agent_id,
48
+ "content": self.content,
49
+ "category": self.category,
50
+ "claim_type": self.claim_type,
51
+ "value": self.value,
52
+ "session_id": self.session_id,
53
+ "prev_hash": self.prev_hash,
54
+ "id": self.id,
55
+ }
56
+
57
+
58
+ def validate_evidence(ev: dict) -> tuple[bool, list[str]]:
59
+ """agent 侧契约自检:返回 (ok, 错误列表)。"""
60
+ errs: list[str] = []
61
+ if not ev.get("agent_id"):
62
+ errs.append("agent_id 必填(共用机制要求声明写入者标识)")
63
+ elif ev["agent_id"] not in REGISTRY:
64
+ errs.append(f"agent_id '{ev['agent_id']}' 未在 mesh 注册表(禁止匿名污染)")
65
+ if not ev.get("content"):
66
+ errs.append("content 必填(一致性比对键)")
67
+ ct = ev.get("claim_type", "fact")
68
+ if ct not in CLAIM_TYPES:
69
+ errs.append(f"claim_type '{ct}' 非法,须为 {sorted(CLAIM_TYPES)}")
70
+ # content 精确相等判定 → 禁止任何 embedding/相似度
71
+ if ev.get("content") and not isinstance(ev["content"], str):
72
+ errs.append("content 必须为精确字符串(零向量一致性比对键)")
73
+ return (len(errs) == 0, errs)
74
+
75
+
76
+ # ── 2. 双向契约合规检查 ────────────────────────────────────────
77
+ def check_contract(agent_id: str, did_recall: bool, wrote_structured: bool) -> tuple[bool, list[str]]:
78
+ """①身份 ②结构化写 ③主动消费 ④冲突响应(由 detect_conflict 触发)。"""
79
+ errs: list[str] = []
80
+ if agent_id not in REGISTRY:
81
+ errs.append("① 身份未声明/未注册")
82
+ if not wrote_structured:
83
+ errs.append("② 未结构化写入(缺 claim_type/session_id/prev_hash)")
84
+ if not did_recall:
85
+ errs.append("③ 会话未主动消费 consensus 视图(退化成孤岛)")
86
+ return (len(errs) == 0, errs)
87
+
88
+
89
+ # ── 3. CCI 主体间性共识指数(记忆层)────────────────────────────
90
+ def compute_cci(items: list[dict]) -> dict:
91
+ """CCI_mem = |consensus| / (|consensus| + |private|)。"""
92
+ cons = [x for x in items if x.get("scope") == "consensus"]
93
+ priv = [x for x in items if x.get("scope") == "private"]
94
+ denom = len(cons) + len(priv)
95
+ cci = (len(cons) / denom) if denom else 0.0
96
+ # 共识强度 secondary:平均 contributors 基数
97
+ strengths = [len(x.get("contributors", [])) for x in cons] or [0]
98
+ avg_strength = sum(strengths) / len(strengths) if strengths else 0
99
+ return {
100
+ "cci": round(cci, 4),
101
+ "consensus": len(cons),
102
+ "private": len(priv),
103
+ "avg_contributors": round(avg_strength, 2),
104
+ }
105
+
106
+
107
+ # ── 4. 统一认知健康仪表盘 ─────────────────────────────────────
108
+ def cognitive_health(items: list[dict], drift_rate: float = 0.0,
109
+ H_e: float = 0.0, P_mem: float = 0.0) -> dict:
110
+ cci = compute_cci(items)
111
+ evs = [x for x in items if x.get("type") == "evidence"]
112
+ from collections import Counter
113
+ by_agent = Counter(x.get("agent_id") for x in evs)
114
+ return {
115
+ "CCI": cci["cci"],
116
+ "consensus_crystals": cci["consensus"],
117
+ "private_crystals": cci["private"],
118
+ "drift_rate": drift_rate,
119
+ "H_e": H_e,
120
+ "P_mem": P_mem,
121
+ "total_evidence": len(evs),
122
+ "agents": dict(by_agent),
123
+ }
124
+
125
+
126
+ # ── 5. 冲突检测 ───────────────────────────────────────────────
127
+ def detect_conflict(items: list[dict]) -> list[dict]:
128
+ """同锚点下 claim_type=conflict 或同 content 反义 → 标记冲突 agent。"""
129
+ conflicts = []
130
+ by_cat = {}
131
+ for x in items:
132
+ if x.get("type") in ("evidence", "memory"):
133
+ by_cat.setdefault(x.get("category", "?"), []).append(x)
134
+ for cat, recs in by_cat.items():
135
+ conflict_recs = [r for r in recs if r.get("claim_type") == "conflict"]
136
+ if conflict_recs:
137
+ agents = sorted({r.get("agent_id") for r in conflict_recs if r.get("agent_id")})
138
+ conflicts.append({"anchor": cat, "conflict_agents": agents,
139
+ "kind": "explicit_conflict"})
140
+ return conflicts
141
+
142
+
143
+ # ── 6. 从 8790 拉取状态 ───────────────────────────────────────
144
+ def fetch_state(base: str = "http://127.0.0.1:8790") -> list[dict]:
145
+ req = urllib.request.Request(base + "/list", data=b"{}",
146
+ headers={"Content-Type": "application/json"})
147
+ with urllib.request.urlopen(req, timeout=5) as r:
148
+ d = json.load(r)
149
+ return d if isinstance(d, list) else d.get("result", d.get("items", []))
150
+
151
+
152
+ # ── CLI:打印健康报告 ──────────────────────────────────────────
153
+ def main():
154
+ try:
155
+ items = fetch_state()
156
+ except Exception as e:
157
+ print(f"[ERR] 无法连接 8790: {e}")
158
+ sys.exit(1)
159
+ health = cognitive_health(items)
160
+ print("=== 液环 MESH v2 认知健康仪表盘 ===")
161
+ for k, v in health.items():
162
+ print(f" {k:18}: {v}")
163
+ conf = detect_conflict(items)
164
+ if conf:
165
+ print("\n=== 冲突锚点 ===")
166
+ for c in conf:
167
+ print(" ", c)
168
+ else:
169
+ print("\n[OK] 无显式冲突")
170
+
171
+
172
+ if __name__ == "__main__":
173
+ main()
@@ -36,7 +36,12 @@ def _file_lock(filepath: str, mode: str = "w"):
36
36
  finally:
37
37
  fcntl.flock(f, fcntl.LOCK_UN)
38
38
 
39
+ def _lock_path(workspace_root: Path) -> Path:
40
+ return _ensure_dir(workspace_root) / "state.lock"
41
+
42
+
39
43
  def load(workspace_root: Path) -> WorkspaceState:
44
+ """纯读取,无锁。并发安全由上层 locked_state 上下文保证。"""
40
45
  path = _ensure_dir(workspace_root) / STATE_FILE
41
46
  if not path.exists():
42
47
  return WorkspaceState()
@@ -46,6 +51,7 @@ def load(workspace_root: Path) -> WorkspaceState:
46
51
 
47
52
 
48
53
  def save(state: WorkspaceState, workspace_root: Path):
54
+ """原子写(temp+rename):崩溃永不留下半截文件。锁由 locked_state 持有。"""
49
55
  state.updated_at = now()
50
56
  path = _ensure_dir(workspace_root) / STATE_FILE
51
57
  # 审计链:记录并回写哈希
@@ -59,8 +65,28 @@ def save(state: WorkspaceState, workspace_root: Path):
59
65
  data = asdict(state)
60
66
  # overlap_cache 仅为运行时熵计算缓存,键为 tuple,不可 JSON 序列化,且不具持久价值
61
67
  data.pop("overlap_cache", None)
62
- with open(path, "w", encoding="utf-8") as f:
68
+ tmp = path.with_suffix(".tmp")
69
+ with open(tmp, "w", encoding="utf-8") as f:
63
70
  json.dump(data, f, indent=2, ensure_ascii=False)
71
+ f.flush()
72
+ os.fsync(f.fileno())
73
+ os.replace(tmp, path) # POSIX 原子替换,读端永不看到半截文件
74
+
75
+
76
+ @contextmanager
77
+ def locked_state(workspace_root: Path):
78
+ """单一锁层:排他锁跨 load→modify→save 整段,根除并发丢写(P0)。
79
+ 跨进程安全(fcntl 建议锁);server 与批量喂入脚本共用同一把锁。"""
80
+ d = _ensure_dir(workspace_root)
81
+ lk = open(d / "state.lock", "w")
82
+ fcntl.flock(lk, fcntl.LOCK_EX)
83
+ try:
84
+ st = load(workspace_root)
85
+ yield st
86
+ save(st, workspace_root)
87
+ finally:
88
+ fcntl.flock(lk, fcntl.LOCK_UN)
89
+ lk.close()
64
90
 
65
91
 
66
92
  def _from_dict(data: dict) -> WorkspaceState:
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from dataclasses import dataclass, field
2
4
  from datetime import datetime, timezone
3
5
  from typing import Optional, List, Dict, Any
@@ -153,6 +155,7 @@ class Evidence:
153
155
  weight: float = 1.0
154
156
  quality: str = "normal"
155
157
  archived: bool = False # 预算超额冷归档标记(PEEK 落地,零丢失)
158
+ agent_id: str = "" # 多智能体共用:写入者标识(共用机制,缺省=legacy/单实例)
156
159
 
157
160
 
158
161
  @dataclass
@@ -162,6 +165,8 @@ class Memory:
162
165
  formed_at: str = field(default_factory=now)
163
166
  evidence_ids: list[str] = field(default_factory=list)
164
167
  confidence: float = 0.0
168
+ scope: str = "private" # 结晶来源: private(同 agent≥2一致) / consensus(跨 distinct owner≥2一致)
169
+ contributors: list[str] = field(default_factory=list) # 参与成核的 agent_id 列表
165
170
 
166
171
 
167
172
  @dataclass
@@ -243,10 +248,11 @@ class WorkspaceState:
243
248
  self.updated_at = now()
244
249
  return a
245
250
 
246
- def add_evidence(self, anchor: str, content: str, quality: float = 1.0) -> Optional[Evidence]:
251
+ def add_evidence(self, anchor, content: str, quality: float = 1.0, agent_id: str = "") -> Optional[Evidence]:
247
252
  """向指定锚点添加一条证据。
248
253
 
249
254
  anchor 参数兼容:锚点名称(str) | 锚点ID(str) | Anchor对象
255
+ agent_id:多智能体共用写入者标识(缺省空=legacy/单实例)
250
256
  """
251
257
  target = None
252
258
  if isinstance(anchor, Anchor):
@@ -258,9 +264,13 @@ class WorkspaceState:
258
264
  target = next((a for a in self.anchors if a.id == anchor), None)
259
265
  if not target:
260
266
  return None
267
+ # 幂等去重:同锚点+同内容+同 agent 已存在则复用,防止重复证据膨胀(mesh 重试/高频喂入)
268
+ for ex in self.evidences:
269
+ if ex.anchor_id == target.id and ex.content == content and ex.agent_id == agent_id:
270
+ return ex
261
271
  e = Evidence(
262
272
  id=uid(), anchor_id=target.id, content=content,
263
- quality=quality, timestamp=now(),
273
+ quality=quality, timestamp=now(), agent_id=agent_id,
264
274
  )
265
275
  self.evidences.append(e)
266
276
  target.evidence_ids.append(e.id)
@@ -289,31 +299,68 @@ class WorkspaceState:
289
299
  e.weight = max(e.weight * 0.95, 0.1)
290
300
 
291
301
  def _nucleate(self, anchor_id: str):
292
- """成核:同锚点下 >= 2 条一致证据形成记忆结晶。
302
+ """双轨成核(多智能体共用机制):
303
+
304
+ - private 轨:同一 agent_id 下 >= 2 条一致证据 -> scope=private 结晶
305
+ - consensus 轨:同一 content 被 >= 2 个 distinct agent_id 证据支持 -> scope=consensus 结晶
293
306
 
294
- 复合键判定:查重限定在当前锚点内((anchor_id, content)),避免跨锚点
295
- 同 content 证据被错误吞掉或并入同一结晶(P0 跨锚点误结晶修复, v0.6.2)。
307
+ 复合键 (anchor_id, content, scope) 防跨锚点/跨轨污染。
308
+ 兼容 legacy:agent_id 为空视为单实例私有(走 private 轨,contributors=["legacy"])。
296
309
  """
297
310
  group = [e for e in self.evidences if e.anchor_id == anchor_id]
298
311
  if len(group) < 2:
299
312
  return
300
- # 本锚点已结晶的 content 集合(复合键判定,杜绝跨锚点污染)
301
- crystallized_contents: set[str] = set()
313
+ # 已结晶键集合(复合键判定,杜绝跨锚点/跨轨污染)
314
+ crystallized_keys: set = set()
302
315
  for m in self.memories:
303
316
  for eid in m.evidence_ids:
304
317
  ev = next((e for e in self.evidences if e.id == eid), None)
305
318
  if ev is not None and ev.anchor_id == anchor_id:
306
- crystallized_contents.add(m.content)
319
+ crystallized_keys.add((m.content, m.scope))
307
320
  break
308
- content_counts = Counter(e.content for e in group)
309
- for content, count in content_counts.items():
310
- if count >= 2 and content not in crystallized_contents:
311
- evidence_ids = [e.id for e in group if e.content == content]
312
- confidence = min(count / len(group), 1.0)
321
+ from collections import defaultdict
322
+ # ── private 轨:按 agent_id 分组,组内同 content >= 2 ──
323
+ by_agent: dict = defaultdict(list)
324
+ for e in group:
325
+ by_agent[e.agent_id if e.agent_id else "legacy"].append(e)
326
+ for owner, evs in by_agent.items():
327
+ content_counts = Counter(e.content for e in evs)
328
+ for content, count in content_counts.items():
329
+ if count >= 2 and (content, "private") not in crystallized_keys:
330
+ evidence_ids = [e.id for e in evs if e.content == content]
331
+ confidence = min(count / len(evs), 1.0)
332
+ self.memories.append(Memory(
333
+ content=content,
334
+ evidence_ids=evidence_ids,
335
+ confidence=confidence,
336
+ scope="private",
337
+ contributors=[owner],
338
+ ))
339
+ # ── consensus 轨:跨 distinct owner 同 content >= 2 ──
340
+ owners_by_content: dict = defaultdict(set)
341
+ for e in group:
342
+ if not e.agent_id:
343
+ continue # legacy 不参与共识轨(无法跨主体)
344
+ owners_by_content[e.content].add(e.agent_id)
345
+ for content, owners in owners_by_content.items():
346
+ if len(owners) < 2:
347
+ continue
348
+ # 已存在的共识结晶:把新一致方并入 contributors(动态扩展,支撑三方+ CCI 计量)
349
+ existing = next((m for m in self.memories if m.scope == "consensus" and m.content == content), None)
350
+ if existing is not None:
351
+ merged = set(existing.contributors) | owners
352
+ if merged != set(existing.contributors):
353
+ existing.contributors = sorted(merged)
354
+ continue
355
+ if (content, "consensus") not in crystallized_keys:
356
+ evidence_ids = [e.id for e in group if e.content == content and e.agent_id in owners]
357
+ confidence = min(len(owners) / 2.0, 1.0)
313
358
  self.memories.append(Memory(
314
359
  content=content,
315
360
  evidence_ids=evidence_ids,
316
361
  confidence=confidence,
362
+ scope="consensus",
363
+ contributors=sorted(owners),
317
364
  ))
318
365
  # 成核后触发自动描述回流(仅当描述为空)
319
366
  self._auto_describe_anchor(anchor_id)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liquid-loop
3
- Version: 0.6.4
3
+ Version: 0.7.0
4
4
  Summary: Self-Organizing Cognitive Memory for AI Agents — Liquid Loop theory implementation
5
5
  Author: fishbook0001
6
6
  Maintainer: fishbook0001
@@ -147,6 +147,26 @@ liquid-loop snapshot
147
147
 
148
148
  ---
149
149
 
150
+ ## MESH 集成(多智能体共识)
151
+
152
+ 液环从 v0.7.0 起内置官方 MESH 集成 `liquid_loop.mesh`,把"多智能体共识协议"落地为可复用代码,作为 agent-mesh 节点的标准接入层。
153
+
154
+ ```python
155
+ from liquid_loop.mesh import validate_evidence, compute_cci, cognitive_health, fetch_state
156
+
157
+ # agent 写入前契约自检(零向量:content 必须精确字符串,禁 embedding)
158
+ ok, errs = validate_evidence({"agent_id": "vera", "content": "用户偏好简洁输出"})
159
+
160
+ # 从 8790 拉取记忆状态,算主体间性共识指数 CCI
161
+ items = fetch_state("http://127.0.0.1:8790")
162
+ health = cognitive_health(items)
163
+ print(health["CCI"], health["consensus_crystals"])
164
+ ```
165
+
166
+ 零向量哲学:一致性判定走**结构化精确相等 + 审计链哈希**,绝不引入任何 embedding / 相似度。规范详见 `mesh/liquid_loop_mesh_v2_spec.md`。
167
+
168
+ ---
169
+
150
170
  ## 架构对比
151
171
 
152
172
  ```
@@ -194,6 +214,7 @@ liquid-loop/
194
214
  │ ├── workspace.py # 核心数据模型 + AuditChain + auto_classify + decay
195
215
  │ ├── storage.py # JSON 持久化 + 审计链写入
196
216
  │ ├── entropy.py # 四维熵值计算
217
+ │ ├── mesh/ # MESH v2 多智能体共识协议集成(validate_evidence / compute_cci / ...)
197
218
  │ └── cli.py # Click CLI (11 命令)
198
219
  ├── examples/
199
220
  │ └── quickstart.py
@@ -220,7 +241,7 @@ pytest -v
220
241
  ## 路线图
221
242
 
222
243
  - [ ] 语义一致性结晶(嵌入相似度替代精确匹配)
223
- - [ ] 多 Agent 液环耦合
244
+ - [x] 多 Agent 液环耦合(`liquid_loop.mesh` v2 共识协议,2026-07-15 落地)
224
245
  - [ ] LX 扩展:世界模型预测纳入液环
225
246
  - [ ] LoCoMo / LongMemEval 基准对比
226
247
  - [ ] 边缘端部署优化(<50KB)
@@ -14,7 +14,11 @@ liquid_loop.egg-info/dependency_links.txt
14
14
  liquid_loop.egg-info/entry_points.txt
15
15
  liquid_loop.egg-info/requires.txt
16
16
  liquid_loop.egg-info/top_level.txt
17
+ liquid_loop/mesh/__init__.py
18
+ liquid_loop/mesh/v2.py
19
+ tests/test_consensus_expansion.py
17
20
  tests/test_entropy.py
21
+ tests/test_nucleate_dual_track.py
18
22
  tests/test_peek_seal.py
19
23
  tests/test_seal_persistence.py
20
24
  tests/test_self_evolve.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "liquid-loop"
7
- version = "0.6.4"
7
+ version = "0.7.0"
8
8
  description = "Self-Organizing Cognitive Memory for AI Agents — Liquid Loop theory implementation"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -0,0 +1,45 @@
1
+ """共识结晶 contributors 随新一致方动态扩展(三方+ CCI 计量)。"""
2
+ from liquid_loop import WorkspaceState
3
+ from liquid_loop.workspace import Anchor, Evidence, Memory
4
+
5
+
6
+ def _add(st, name, content, agent_id):
7
+ a = next((x for x in st.anchors if x.name == name), None)
8
+ if a is None:
9
+ a = st.add_anchor(name)
10
+ e = Evidence(content=content, anchor_id=a.id, agent_id=agent_id)
11
+ st.add_evidence(a, content, agent_id=agent_id)
12
+ return a
13
+
14
+
15
+ def test_consensus_expands_with_third_agent():
16
+ st = WorkspaceState()
17
+ # qwenpaw + vera 先达成共识
18
+ _add(st, "液环", "液环是零向量记忆", "qwenpaw")
19
+ _add(st, "液环", "液环是零向量记忆", "qwenpaw") # qwenpaw >=2 -> private
20
+ _add(st, "液环", "液环是零向量记忆", "vera") # +vera -> consensus[qwenpaw,vera]
21
+ cons = next(m for m in st.memories if m.scope == "consensus")
22
+ assert cons.contributors == ["qwenpaw", "vera"], cons.contributors
23
+ # marvis 也写同内容 -> 应并入三方共识
24
+ _add(st, "液环", "液环是零向量记忆", "marvis")
25
+ cons = next(m for m in st.memories if m.scope == "consensus")
26
+ assert cons.contributors == ["marvis", "qwenpaw", "vera"], cons.contributors
27
+
28
+
29
+ def test_consensus_no_duplicate_on_repeat():
30
+ st = WorkspaceState()
31
+ _add(st, "fact", "X", "a")
32
+ _add(st, "fact", "X", "a") # private[a]
33
+ _add(st, "fact", "X", "b") # consensus[a,b]
34
+ _add(st, "fact", "X", "b") # b 重复,不应扩
35
+ cons = next(m for m in st.memories if m.scope == "consensus")
36
+ assert cons.contributors == ["a", "b"], cons.contributors
37
+
38
+
39
+ def test_private_untouched_by_consensus_expansion():
40
+ st = WorkspaceState()
41
+ _add(st, "fact", "Y", "qwenpaw")
42
+ _add(st, "fact", "Y", "qwenpaw") # private[qwenpaw]
43
+ _add(st, "fact", "Y", "vera") # consensus
44
+ priv = [m for m in st.memories if m.scope == "private"]
45
+ assert priv and priv[0].contributors == ["qwenpaw"], priv
@@ -0,0 +1,115 @@
1
+ """双轨成核 + 防污染回归测试(多智能体共用机制)。
2
+
3
+ 锁住行为:
4
+ - private 轨:同一 agent_id 内 >= 2 一致证据 -> scope=private
5
+ - consensus 轨:同一 content 跨 >= 2 distinct agent_id -> scope=consensus
6
+ - 防污染:不同 agent 不互相成私有晶;跨锚点同 content 不合并;复合键 (anchor,content,scope)
7
+ """
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ sys.path.insert(0, str(Path(__file__).parent.parent))
12
+
13
+ from liquid_loop.workspace import WorkspaceState
14
+
15
+
16
+ def _add(st, name, content, agent_id=""):
17
+ a = next((x for x in st.anchors if x.name == name), None)
18
+ if a is None:
19
+ a = st.add_anchor(name)
20
+ return st.add_evidence(a, content, agent_id=agent_id)
21
+
22
+
23
+ def test_private_nucleation_same_agent():
24
+ st = WorkspaceState()
25
+ _add(st, "topic", "液环是零向量记忆", agent_id="qwenpaw")
26
+ _add(st, "topic", "液环是零向量记忆", agent_id="qwenpaw")
27
+ priv = [m for m in st.memories if m.scope == "private"]
28
+ cons = [m for m in st.memories if m.scope == "consensus"]
29
+ assert len(priv) == 1
30
+ assert priv[0].contributors == ["qwenpaw"]
31
+ assert len(cons) == 0
32
+
33
+
34
+ def test_private_isolation_diff_agents():
35
+ st = WorkspaceState()
36
+ _add(st, "topic", "同一结论", agent_id="qwenpaw")
37
+ _add(st, "topic", "同一结论", agent_id="vera")
38
+ # 各 agent 内仅 1 条 -> 不 privately 成核
39
+ assert all(m.scope != "private" for m in st.memories)
40
+ # 但跨 2 distinct owner -> consensus 成核
41
+ cons = [m for m in st.memories if m.scope == "consensus"]
42
+ assert len(cons) == 1
43
+ assert set(cons[0].contributors) == {"qwenpaw", "vera"}
44
+
45
+
46
+ def test_consensus_requires_distinct_owner():
47
+ st = WorkspaceState()
48
+ _add(st, "topic", "共识结论", agent_id="qwenpaw")
49
+ _add(st, "topic", "共识结论", agent_id="qwenpaw") # 同 owner 重复
50
+ # 同 owner 2 条 -> private,但不该有 consensus(只有 1 个 owner)
51
+ cons = [m for m in st.memories if m.scope == "consensus"]
52
+ assert len(cons) == 0
53
+ priv = [m for m in st.memories if m.scope == "private"]
54
+ assert len(priv) == 1
55
+
56
+
57
+ def test_cross_anchor_no_pollution():
58
+ st = WorkspaceState()
59
+ _add(st, "A", "X", agent_id="qwenpaw")
60
+ _add(st, "A", "X", agent_id="qwenpaw")
61
+ _add(st, "B", "X", agent_id="qwenpaw")
62
+ _add(st, "B", "X", agent_id="qwenpaw")
63
+ # 两个锚点各成 1 个 private 晶,不合并
64
+ priv = [m for m in st.memories if m.scope == "private"]
65
+ assert len(priv) == 2
66
+
67
+
68
+ def test_legacy_compat_no_agent_id():
69
+ st = WorkspaceState()
70
+ _add(st, "topic", "legacy 内容", agent_id="")
71
+ _add(st, "topic", "legacy 内容", agent_id="")
72
+ priv = [m for m in st.memories if m.scope == "private"]
73
+ assert len(priv) == 1
74
+ assert priv[0].contributors == ["legacy"]
75
+
76
+
77
+ def test_dual_track_coexist():
78
+ st = WorkspaceState()
79
+ # 私有:qwenpaw 内 2 条独有结论
80
+ _add(st, "T", "qwenpaw 私有结论", agent_id="qwenpaw")
81
+ _add(st, "T", "qwenpaw 私有结论", agent_id="qwenpaw")
82
+ # 共识:qwenpaw + vera 各 1 条共享结论
83
+ _add(st, "T", "共享结论", agent_id="qwenpaw")
84
+ _add(st, "T", "共享结论", agent_id="vera")
85
+ priv = [m for m in st.memories if m.scope == "private"]
86
+ cons = [m for m in st.memories if m.scope == "consensus"]
87
+ assert len(priv) == 1 and priv[0].contributors == ["qwenpaw"]
88
+ assert len(cons) == 1 and set(cons[0].contributors) == {"qwenpaw", "vera"}
89
+
90
+
91
+ def test_no_pollution_between_agents_private():
92
+ st = WorkspaceState()
93
+ _add(st, "T", "结论A", agent_id="qwenpaw")
94
+ _add(st, "T", "结论A", agent_id="qwenpaw")
95
+ _add(st, "T", "结论A", agent_id="vera") # vera 只有 1 条 -> 不成私有
96
+ priv = [m for m in st.memories if m.scope == "private"]
97
+ cons = [m for m in st.memories if m.scope == "consensus"]
98
+ # qwenpaw 私有 1 晶;vera 仅 1 条不足私有;二者合计 2 distinct owner -> consensus 1 晶
99
+ assert len(priv) == 1 and priv[0].contributors == ["qwenpaw"]
100
+ assert len(cons) == 1 and set(cons[0].contributors) == {"qwenpaw", "vera"}
101
+
102
+
103
+ def test_storage_roundtrip_agent_id_scope(tmp_path):
104
+ """持久化往返:agent_id / scope / contributors 必须无损保存加载。"""
105
+ from liquid_loop import storage
106
+ st = WorkspaceState()
107
+ _add(st, "T", "X", agent_id="qwenpaw")
108
+ _add(st, "T", "X", agent_id="qwenpaw")
109
+ storage.save(st, tmp_path)
110
+ st2 = storage.load(tmp_path)
111
+ assert len(st2.memories) == 1
112
+ m = st2.memories[0]
113
+ assert m.scope == "private"
114
+ assert m.contributors == ["qwenpaw"]
115
+ assert st2.evidences[0].agent_id == "qwenpaw"
File without changes
File without changes