liquid-loop 0.5.3__tar.gz → 0.5.4__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.
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/PKG-INFO +1 -1
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop/cli.py +2 -2
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop/workspace.py +37 -4
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop.egg-info/PKG-INFO +1 -1
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop.egg-info/SOURCES.txt +2 -1
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/pyproject.toml +1 -1
- liquid_loop-0.5.4/tests/test_self_evolve.py +68 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/LICENSE +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/README.md +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop/__init__.py +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop/__main__.py +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop/entropy.py +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop/storage.py +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop.egg-info/dependency_links.txt +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop.egg-info/entry_points.txt +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop.egg-info/requires.txt +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/liquid_loop.egg-info/top_level.txt +0 -0
- {liquid_loop-0.5.3 → liquid_loop-0.5.4}/setup.cfg +0 -0
|
@@ -80,9 +80,9 @@ def init():
|
|
|
80
80
|
if s.anchors or s.evidences:
|
|
81
81
|
click.echo("工作区已初始化,无需重复操作。")
|
|
82
82
|
return
|
|
83
|
-
s.version = "0.5.
|
|
83
|
+
s.version = "0.5.4"
|
|
84
84
|
_save(s)
|
|
85
|
-
click.echo(f"✓ Liquid Loop v0.5.
|
|
85
|
+
click.echo(f"✓ Liquid Loop v0.5.4 工作区已初始化: {WORKSPACE}/.liquid/")
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
@main.command()
|
|
@@ -197,7 +197,7 @@ class WorkspaceState:
|
|
|
197
197
|
relations: list[AnchorRelation] = field(default_factory=list)
|
|
198
198
|
audit_chain_hash: str = "genesis"
|
|
199
199
|
audit_prev_hash: str = ""
|
|
200
|
-
version: str = "0.5.
|
|
200
|
+
version: str = "0.5.4"
|
|
201
201
|
updated_at: str = field(default_factory=now)
|
|
202
202
|
# 【v0.4.0】后向自进化状态(借鉴 MemMA 原位自进化)
|
|
203
203
|
self_refine_probes: list[dict] = field(default_factory=list)
|
|
@@ -252,10 +252,11 @@ class WorkspaceState:
|
|
|
252
252
|
return e
|
|
253
253
|
|
|
254
254
|
def _on_evidence_added(self, anchor_id: str):
|
|
255
|
-
"""
|
|
255
|
+
"""证据添加后的统一后处理:衰减→成核→稳定性刷新→群内自洽检测"""
|
|
256
256
|
self._decay_anchor(anchor_id)
|
|
257
257
|
self._nucleate(anchor_id)
|
|
258
258
|
self._recalc_anchor(anchor_id)
|
|
259
|
+
self._detect_conflicts(anchor_id)
|
|
259
260
|
|
|
260
261
|
def _decay_anchor(self, anchor_id: str):
|
|
261
262
|
for e in self.evidences:
|
|
@@ -263,10 +264,11 @@ class WorkspaceState:
|
|
|
263
264
|
e.weight = max(e.weight * 0.95, 0.1)
|
|
264
265
|
|
|
265
266
|
def _nucleate(self, anchor_id: str):
|
|
266
|
-
"""成核:同锚点下 >= 2
|
|
267
|
+
"""成核:同锚点下 >= 2 条一致证据形成记忆结晶;高置信结晶回流更新锚点描述"""
|
|
267
268
|
group = [e for e in self.evidences if e.anchor_id == anchor_id]
|
|
268
269
|
if len(group) < 2:
|
|
269
270
|
return
|
|
271
|
+
anchor = next((a for a in self.anchors if a.id == anchor_id), None)
|
|
270
272
|
from collections import Counter
|
|
271
273
|
content_counts = Counter(e.content for e in group)
|
|
272
274
|
for content, count in content_counts.items():
|
|
@@ -280,6 +282,9 @@ class WorkspaceState:
|
|
|
280
282
|
evidence_ids=evidence_ids,
|
|
281
283
|
confidence=confidence,
|
|
282
284
|
))
|
|
285
|
+
# 【自进化回流】高置信结晶自动回填锚点空描述(仅当描述为空,尊重人工设定)
|
|
286
|
+
if confidence >= 0.8 and anchor and not anchor.description:
|
|
287
|
+
anchor.description = content
|
|
283
288
|
|
|
284
289
|
def _recalc_anchor(self, anchor_id: str):
|
|
285
290
|
group = [e for e in self.evidences if e.anchor_id == anchor_id]
|
|
@@ -294,6 +299,35 @@ class WorkspaceState:
|
|
|
294
299
|
a.recalc_strength(evidence_count)
|
|
295
300
|
a.auto_classify(evidence_count)
|
|
296
301
|
|
|
302
|
+
def _detect_conflicts(self, anchor_id: str):
|
|
303
|
+
"""群内自洽检测:同锚点证据一致性过低 → 生成 Conflict 记录并降锚点稳定性。
|
|
304
|
+
|
|
305
|
+
复用 CPE 泛化防线思路:证据间平均关键词重叠 < 0.2 且 >= 3 条 → 潜在冲突/漂移。
|
|
306
|
+
保守处理:只标记'需人工确认',不武断判相反(避免过度工程化误报)。
|
|
307
|
+
"""
|
|
308
|
+
group = [e for e in self.evidences if e.anchor_id == anchor_id]
|
|
309
|
+
if len(group) < 3:
|
|
310
|
+
return
|
|
311
|
+
overlaps = []
|
|
312
|
+
for i in range(len(group)):
|
|
313
|
+
for j in range(i + 1, len(group)):
|
|
314
|
+
if group[i].content and group[j].content:
|
|
315
|
+
overlaps.append(_keyword_overlap(group[i].content, group[j].content))
|
|
316
|
+
if not overlaps:
|
|
317
|
+
return
|
|
318
|
+
avg = sum(overlaps) / len(overlaps)
|
|
319
|
+
if avg < 0.2:
|
|
320
|
+
anchor = next((a for a in self.anchors if a.id == anchor_id), None)
|
|
321
|
+
if any(c.anchor_a == anchor_id for c in self.conflicts):
|
|
322
|
+
return
|
|
323
|
+
self.conflicts.append(Conflict(
|
|
324
|
+
anchor_a=anchor_id,
|
|
325
|
+
description=f"证据间平均一致度 {avg:.2f}(<0.2),存在潜在冲突/漂移,需人工确认",
|
|
326
|
+
severity=round(1.0 - avg, 2),
|
|
327
|
+
))
|
|
328
|
+
if anchor:
|
|
329
|
+
anchor.stability = max(0.1, anchor.stability * 0.9)
|
|
330
|
+
|
|
297
331
|
def add_memory(self, content: str, evidence_ids: list[str] | None = None) -> Memory:
|
|
298
332
|
"""添加一条记忆结晶"""
|
|
299
333
|
m = Memory(id=uid(), content=content, evidence_ids=evidence_ids or [])
|
|
@@ -360,7 +394,6 @@ class CPERegularizer:
|
|
|
360
394
|
"max_overlap": round(max_overlap, 3),
|
|
361
395
|
"avg_overlap": round(avg_overlap, 3),
|
|
362
396
|
"drift_score": round(drift_score, 3),
|
|
363
|
-
"protection_weight": round(protection_weight, 3),
|
|
364
397
|
"existing_evidence_count": len(evs),
|
|
365
398
|
"duplicate_of": duplicate_of,
|
|
366
399
|
}
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "liquid-loop"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.4"
|
|
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,68 @@
|
|
|
1
|
+
"""锚点自进化补强 + 回归测试(v0.5.3)
|
|
2
|
+
|
|
3
|
+
覆盖:
|
|
4
|
+
1. CPE MERGE 分支不再抛 NameError(回归)
|
|
5
|
+
2. 成核回流:高置信结晶自动回填锚点空描述
|
|
6
|
+
3. 群内自洽:低一致性证据自动生成 Conflict
|
|
7
|
+
"""
|
|
8
|
+
from liquid_loop.workspace import WorkspaceState, CPERegularizer
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_cpe_merge_no_nameerror():
|
|
12
|
+
"""回归:命中'近似重复'证据时,MERGE 分支不得抛 NameError"""
|
|
13
|
+
s = WorkspaceState()
|
|
14
|
+
a = s.add_anchor("简洁偏好", "desc")
|
|
15
|
+
s.add_evidence(a, "用户偏好简洁输出")
|
|
16
|
+
s.add_evidence(a, "用户偏好简洁输出")
|
|
17
|
+
reg = CPERegularizer(s)
|
|
18
|
+
# 第三条与已有证据高度重叠 → 命中 MERGE 分支
|
|
19
|
+
result = reg.regularize(a.name, "用户偏好简洁输出")
|
|
20
|
+
assert result["action"] == "MERGE"
|
|
21
|
+
# 修复前此分支引用未定义变量 protection_weight → NameError
|
|
22
|
+
assert "protection_weight" not in result.get("details", {})
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_nucleate_feedback_to_anchor():
|
|
26
|
+
"""成核回流:结晶 confidence >= 0.8 时回填锚点空描述"""
|
|
27
|
+
s = WorkspaceState()
|
|
28
|
+
a = s.add_anchor("核心使命", "") # 描述为空,等待回流
|
|
29
|
+
assert a.description == ""
|
|
30
|
+
s.add_evidence(a, "系统的核心目标是认知自组织")
|
|
31
|
+
s.add_evidence(a, "系统的核心目标是认知自组织") # 一致 → 成核
|
|
32
|
+
# 两条一致 → confidence = min(2/2, 1.0) = 1.0 >= 0.8
|
|
33
|
+
assert len(s.memories) == 1
|
|
34
|
+
assert s.memories[0].confidence >= 0.8
|
|
35
|
+
assert a.description == "系统的核心目标是认知自组织"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_nucleate_no_overwrite_manual_description():
|
|
39
|
+
"""尊重人工设定:锚点已有描述时不被结晶覆盖"""
|
|
40
|
+
s = WorkspaceState()
|
|
41
|
+
a = s.add_anchor("核心使命", "人工写好的描述")
|
|
42
|
+
s.add_evidence(a, "系统的核心目标是认知自组织")
|
|
43
|
+
s.add_evidence(a, "系统的核心目标是认知自组织")
|
|
44
|
+
assert a.description == "人工写好的描述"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_conflict_detection_on_low_consistency():
|
|
48
|
+
"""群内自洽:同锚点 3 条互不相关证据 → 自动生成 Conflict"""
|
|
49
|
+
s = WorkspaceState()
|
|
50
|
+
a = s.add_anchor("混合主题", "一个容纳多主题的锚点")
|
|
51
|
+
s.add_evidence(a, "苹果是一种常见的水果")
|
|
52
|
+
s.add_evidence(a, "地球是太阳系中的一颗行星")
|
|
53
|
+
s.add_evidence(a, "量子纠缠是一种非局域关联现象")
|
|
54
|
+
# 三条证据互不相干 → 平均重叠度极低 < 0.2
|
|
55
|
+
assert len(s.conflicts) == 1
|
|
56
|
+
assert s.conflicts[0].anchor_a == a.id
|
|
57
|
+
# stability 被下调
|
|
58
|
+
assert a.stability < 1.0
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_no_conflict_when_consistent():
|
|
62
|
+
"""一致证据不成冲突"""
|
|
63
|
+
s = WorkspaceState()
|
|
64
|
+
a = s.add_anchor("稳定主题", "desc")
|
|
65
|
+
s.add_evidence(a, "用户偏好简洁输出")
|
|
66
|
+
s.add_evidence(a, "用户偏好简洁输出")
|
|
67
|
+
s.add_evidence(a, "用户偏好简洁输出")
|
|
68
|
+
assert len(s.conflicts) == 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|