liquid-loop 0.1.2__tar.gz → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liquid-loop
3
- Version: 0.1.2
3
+ Version: 0.3.0
4
4
  Summary: Self-Organizing Cognitive Memory for AI Agents — Liquid Loop theory implementation
5
5
  Author: fishbook0001
6
6
  Maintainer: fishbook0001
@@ -123,27 +123,24 @@ save(state, Path("."))
123
123
  # 初始化工作区(创建 .liquid/state.json)
124
124
  liquid-loop init
125
125
 
126
- # 添加锚点
126
+ # 添加锚点(支持自动四维分类)
127
127
  liquid-loop anchor_add "项目目标" "完成液环论文与开源"
128
128
 
129
129
  # 注入证据
130
130
  liquid-loop evidence_add "项目目标" "已完成 11 轮实验与 4 个实证包"
131
131
 
132
- # 查看状态
132
+ # 查看状态(含审计链哈希)
133
133
  liquid-loop status
134
- # 输出:
135
- # ╭──────────────────────────────────────────────╮
136
- # │ Liquid Loop 认知状态 │
137
- # ├──────────┬──────┬────────┬────────┬────────┬──┤
138
- # │ 锚点 │ 证据 │ 结晶 │ 冲突 │ 熵值 │ │
139
- # ├──────────┼──────┼────────┼────────┼────────┼──┤
140
- # │ 项目目标 │ 3 │ 1 │ 0 │ 0.2760 │ 🟢│
141
- # ╰──────────┴──────┴────────┴────────┴────────┴──╯
142
- # 锚点稳定性: 项目目标=0.88
143
134
 
144
135
  # 列出所有记忆结晶
145
136
  liquid-loop memory_list
146
137
 
138
+ # 审计:验证链式哈希完整性
139
+ liquid-loop audit
140
+
141
+ # 查看审计日志(最近 20 条)
142
+ liquid-loop audit-log --tail 20
143
+
147
144
  # 快照(记录当前认知基线)
148
145
  liquid-loop snapshot
149
146
  ```
@@ -194,10 +191,10 @@ Liquid Loop 是唯一完全自组织 + 零 LLM 管理的系统。
194
191
  liquid-loop/
195
192
  ├── liquid_loop/
196
193
  │ ├── __init__.py # 公共 API 导出
197
- │ ├── workspace.py # 核心数据模型
198
- │ ├── storage.py # JSON 持久化
194
+ │ ├── workspace.py # 核心数据模型 + AuditChain + auto_classify + decay
195
+ │ ├── storage.py # JSON 持久化 + 审计链写入
199
196
  │ ├── entropy.py # 四维熵值计算
200
- │ └── cli.py # Click CLI (9 命令)
197
+ │ └── cli.py # Click CLI (11 命令)
201
198
  ├── examples/
202
199
  │ └── quickstart.py
203
200
  ├── tests/ # 待补充
@@ -84,27 +84,24 @@ save(state, Path("."))
84
84
  # 初始化工作区(创建 .liquid/state.json)
85
85
  liquid-loop init
86
86
 
87
- # 添加锚点
87
+ # 添加锚点(支持自动四维分类)
88
88
  liquid-loop anchor_add "项目目标" "完成液环论文与开源"
89
89
 
90
90
  # 注入证据
91
91
  liquid-loop evidence_add "项目目标" "已完成 11 轮实验与 4 个实证包"
92
92
 
93
- # 查看状态
93
+ # 查看状态(含审计链哈希)
94
94
  liquid-loop status
95
- # 输出:
96
- # ╭──────────────────────────────────────────────╮
97
- # │ Liquid Loop 认知状态 │
98
- # ├──────────┬──────┬────────┬────────┬────────┬──┤
99
- # │ 锚点 │ 证据 │ 结晶 │ 冲突 │ 熵值 │ │
100
- # ├──────────┼──────┼────────┼────────┼────────┼──┤
101
- # │ 项目目标 │ 3 │ 1 │ 0 │ 0.2760 │ 🟢│
102
- # ╰──────────┴──────┴────────┴────────┴────────┴──╯
103
- # 锚点稳定性: 项目目标=0.88
104
95
 
105
96
  # 列出所有记忆结晶
106
97
  liquid-loop memory_list
107
98
 
99
+ # 审计:验证链式哈希完整性
100
+ liquid-loop audit
101
+
102
+ # 查看审计日志(最近 20 条)
103
+ liquid-loop audit-log --tail 20
104
+
108
105
  # 快照(记录当前认知基线)
109
106
  liquid-loop snapshot
110
107
  ```
@@ -155,10 +152,10 @@ Liquid Loop 是唯一完全自组织 + 零 LLM 管理的系统。
155
152
  liquid-loop/
156
153
  ├── liquid_loop/
157
154
  │ ├── __init__.py # 公共 API 导出
158
- │ ├── workspace.py # 核心数据模型
159
- │ ├── storage.py # JSON 持久化
155
+ │ ├── workspace.py # 核心数据模型 + AuditChain + auto_classify + decay
156
+ │ ├── storage.py # JSON 持久化 + 审计链写入
160
157
  │ ├── entropy.py # 四维熵值计算
161
- │ └── cli.py # Click CLI (9 命令)
158
+ │ └── cli.py # Click CLI (11 命令)
162
159
  ├── examples/
163
160
  │ └── quickstart.py
164
161
  ├── tests/ # 待补充
@@ -0,0 +1,2 @@
1
+ """Liquid Loop — Workspace Cognitive Runtime v0.3.0"""
2
+ __version__ = "0.3.0" # KFG补强版
@@ -0,0 +1,322 @@
1
+ import click
2
+ from pathlib import Path
3
+ from collections import Counter
4
+ from .workspace import (
5
+ WorkspaceState, Anchor, Evidence, Memory, StateSnapshot,
6
+ AnchorRelation, now, DensityLevel, CognitiveStage, LiquidityLevel,
7
+ )
8
+ from .storage import load, save, get_audit_chain
9
+ from .entropy import calculate
10
+ from .entropy import calculate
11
+
12
+
13
+ WORKSPACE = Path.cwd()
14
+
15
+
16
+ def _load():
17
+ return load(WORKSPACE)
18
+
19
+
20
+ def _save(state: WorkspaceState):
21
+ state.updated_at = now()
22
+ save(state, WORKSPACE)
23
+
24
+
25
+ # Memory Nucleation: 同一 Anchor 下 >= 2 条一致 Evidence 成核
26
+ def _nucleate(state: WorkspaceState, anchor_id: str):
27
+ group = [e for e in state.evidences if e.anchor_id == anchor_id]
28
+ if len(group) < 2:
29
+ return
30
+ content_counts = Counter(e.content for e in group)
31
+ for content, count in content_counts.items():
32
+ if count >= 2:
33
+ existing = [m for m in state.memories if m.content == content]
34
+ if existing:
35
+ continue
36
+ evidence_ids = [e.id for e in group if e.content == content]
37
+ confidence = min(count / len(group), 1.0)
38
+ memory = Memory(
39
+ content=content,
40
+ evidence_ids=evidence_ids,
41
+ confidence=confidence,
42
+ )
43
+ state.memories.append(memory)
44
+
45
+
46
+ def _decay_evidence(state: WorkspaceState, anchor_id: str):
47
+ for e in state.evidences:
48
+ if e.anchor_id == anchor_id:
49
+ e.weight = max(e.weight * 0.95, 0.1)
50
+
51
+
52
+ def _recalc_stability(state: WorkspaceState, anchor_id: str):
53
+ group = [e for e in state.evidences if e.anchor_id == anchor_id]
54
+ if not group:
55
+ return
56
+ avg_weight = sum(e.weight for e in group) / len(group)
57
+ for a in state.anchors:
58
+ if a.id == anchor_id:
59
+ a.stability = avg_weight
60
+ # 刷新价值衰减 + 锚定强度 + 自动分类
61
+ evidence_count = len(group)
62
+ a.decay_value(evidence_count=evidence_count)
63
+ a.recalc_strength(evidence_count)
64
+ a.auto_classify(evidence_count)
65
+
66
+
67
+ # --- CLI ---
68
+
69
+ @click.group()
70
+ def main():
71
+ """Liquid Loop — Workspace Cognitive Runtime v0.2"""
72
+ pass
73
+
74
+
75
+ @main.command()
76
+ def init():
77
+ """初始化 Liquid Loop 工作区"""
78
+ s = _load()
79
+ if s.anchors or s.evidences:
80
+ click.echo("工作区已初始化,无需重复操作。")
81
+ return
82
+ s.version = "0.2.0"
83
+ _save(s)
84
+ click.echo(f"✓ Liquid Loop v0.2 工作区已初始化: {WORKSPACE}/.liquid/")
85
+
86
+
87
+ @main.command()
88
+ def status():
89
+ """显示当前认知状态(含四维分类概览)"""
90
+ s = _load()
91
+ ent = calculate(s)
92
+ level = "GREEN" if ent < 0.3 else ("YELLOW" if ent < 0.6 else "RED")
93
+ latest_ev = max((e.timestamp for e in s.evidences), default="无活动")
94
+ click.echo(f"锚点: {len(s.anchors)} | 证据: {len(s.evidences)} | 记忆: {len(s.memories)} | 冲突: {len(s.conflicts)} | 关系: {len(s.relations)}")
95
+ click.echo(f"熵值: {ent:.4f} [{level}] | 最新活动: {latest_ev}")
96
+ click.echo(f"版本: {s.version}")
97
+
98
+
99
+ @main.command()
100
+ def anchor_list():
101
+ """列出所有锚点(含四维分类 + 价值衰减)"""
102
+ s = _load()
103
+ if not s.anchors:
104
+ click.echo("暂无锚点。使用 liquid anchor add <名称> <描述> 添加。")
105
+ return
106
+ for a in s.anchors:
107
+ a.decay_value()
108
+ bar = "█" * int(a.stability * 10) + "░" * (10 - int(a.stability * 10))
109
+ strength_bar = "■" * int(a.anchor_strength * 10) + "□" * (10 - int(a.anchor_strength * 10))
110
+ ev_count = len([e for e in s.evidences if e.anchor_id == a.id])
111
+ click.echo(
112
+ f"[{a.stability:.2f}] {bar} {a.name}: {a.description[:50]}"
113
+ )
114
+ click.echo(
115
+ f" 分类: [{a.value_density}/{a.cognitive_stage}/{a.liquidity}] "
116
+ f"证据:{ev_count} 价值:{a.value_score:.2f} "
117
+ f"锚定:[{strength_bar}] {a.anchor_strength:.2f}"
118
+ )
119
+
120
+
121
+ @main.command()
122
+ @click.argument("anchor_name")
123
+ @click.argument("content")
124
+ @click.option("--quality", "-q", default="normal", help="证据质量: strong/normal/weak")
125
+ def evidence_add(anchor_name, content, quality):
126
+ """为锚点添加证据"""
127
+ s = _load()
128
+ anchor = next((a for a in s.anchors if a.name == anchor_name), None)
129
+ if not anchor:
130
+ click.echo(f"锚点 '{anchor_name}' 不存在。请先创建。")
131
+ return
132
+ evidence = Evidence(
133
+ anchor_id=anchor.id,
134
+ content=content,
135
+ quality=quality if quality in ("strong", "normal", "weak") else "normal",
136
+ )
137
+ s.evidences.append(evidence)
138
+ anchor.evidence_ids.append(evidence.id)
139
+ _decay_evidence(s, anchor.id)
140
+ _recalc_stability(s, anchor.id)
141
+ _nucleate(s, anchor.id)
142
+ _save(s)
143
+ click.echo(f"✓ 证据已添加: [{anchor_name}] {content[:40]}... quality={evidence.quality}")
144
+
145
+
146
+ @main.command()
147
+ @click.option("--anchor", "-a", default=None, help="按锚点名称过滤")
148
+ @click.option("--quality", "-q", default=None, help="按质量过滤: strong/normal/weak")
149
+ def evidence_list(anchor, quality):
150
+ """列出证据"""
151
+ s = _load()
152
+ evs = s.evidences
153
+ if anchor:
154
+ a = next((x for x in s.anchors if x.name == anchor), None)
155
+ if not a:
156
+ click.echo(f"锚点 '{anchor}' 不存在。")
157
+ return
158
+ evs = [e for e in evs if e.anchor_id == a.id]
159
+ click.echo(f"--- {anchor} ---")
160
+ if quality:
161
+ evs = [e for e in evs if e.quality == quality]
162
+ click.echo(f"--- quality={quality} ---")
163
+ if not evs:
164
+ click.echo("暂无证据。")
165
+ return
166
+ for e in sorted(evs, key=lambda x: x.timestamp, reverse=True):
167
+ anchor_name = next((a.name for a in s.anchors if a.id == e.anchor_id), "?")
168
+ click.echo(f"[{e.weight:.2f}|{e.quality}] {e.timestamp[:19]} [{anchor_name}] {e.content}")
169
+
170
+
171
+ @main.command()
172
+ def memory_list():
173
+ """列出已形成的记忆"""
174
+ s = _load()
175
+ if not s.memories:
176
+ click.echo("暂无记忆。当同一锚点下有 2 条以上一致证据时自动成核。")
177
+ return
178
+ for m in sorted(s.memories, key=lambda x: x.confidence, reverse=True):
179
+ click.echo(f"[conf={m.confidence:.2f}] {m.formed_at[:19]} {m.content}")
180
+
181
+
182
+ @main.command()
183
+ @click.argument("source")
184
+ @click.argument("target")
185
+ @click.option("--type", "-t", "rel_type", default="relates_to",
186
+ help="关系类型: depends_on/relates_to/supersedes/conflicts_with")
187
+ @click.option("--weight", "-w", default=1.0, help="关系强度 0.0~1.0")
188
+ def relate(source, target, rel_type, weight):
189
+ """在两个锚点之间建立关系"""
190
+ s = _load()
191
+ src = next((a for a in s.anchors if a.name == source), None)
192
+ tgt = next((a for a in s.anchors if a.name == target), None)
193
+ if not src or not tgt:
194
+ click.echo("源或目标锚点不存在。")
195
+ return
196
+ # 去重
197
+ for r in s.relations:
198
+ if r.source_id == src.id and r.target_id == tgt.id:
199
+ click.echo(f"关系已存在: {source} → {target} [{r.relation_type}]")
200
+ return
201
+ rel = AnchorRelation(
202
+ source_id=src.id,
203
+ target_id=tgt.id,
204
+ relation_type=rel_type,
205
+ weight=min(max(weight, 0.0), 1.0),
206
+ )
207
+ s.relations.append(rel)
208
+ _save(s)
209
+ click.echo(f"✓ 关系已建立: {source} --[{rel_type}]--> {target}")
210
+
211
+
212
+ @main.command()
213
+ def relation_list():
214
+ """列出所有锚点关系"""
215
+ s = _load()
216
+ if not s.relations:
217
+ click.echo("暂无关系。使用 liquid relate 建立。")
218
+ return
219
+ name_map = {a.id: a.name for a in s.anchors}
220
+ for r in s.relations:
221
+ src = name_map.get(r.source_id, "?")
222
+ tgt = name_map.get(r.target_id, "?")
223
+ click.echo(f"{src} --[{r.relation_type}:{r.weight:.1f}]--> {tgt}")
224
+
225
+
226
+ @main.command()
227
+ def check():
228
+ """检查工作区熵值(六维)"""
229
+ s = _load()
230
+ ent = calculate(s)
231
+ if ent < 0.3:
232
+ level, icon = "GREEN", "✓"
233
+ elif ent < 0.6:
234
+ level, icon = "YELLOW", "⚠"
235
+ else:
236
+ level, icon = "RED", "✗"
237
+ click.echo(f"{icon} 熵值: {ent:.4f} [{level}]")
238
+ if ent >= 0.6:
239
+ click.echo("建议: 检查锚点漂移、添加新证据或解决冲突。")
240
+
241
+
242
+ @main.command()
243
+ def snapshot():
244
+ """保存当前状态快照"""
245
+ s = _load()
246
+ ent = calculate(s)
247
+ snap = StateSnapshot(
248
+ entropy=ent,
249
+ anchor_count=len(s.anchors),
250
+ evidence_count=len(s.evidences),
251
+ memory_count=len(s.memories),
252
+ conflict_count=len(s.conflicts),
253
+ )
254
+ s.snapshots.append(snap)
255
+ _save(s)
256
+ click.echo(f"✓ 快照已保存 (熵值: {ent:.4f})")
257
+
258
+
259
+ @main.command()
260
+ def snapshots():
261
+ """列出历史快照"""
262
+ s = _load()
263
+ if not s.snapshots:
264
+ click.echo("暂无快照。使用 liquid snapshot 保存。")
265
+ return
266
+ for i, snap in enumerate(s.snapshots):
267
+ click.echo(f"[{i}] {snap.timestamp[:19]} 熵={snap.entropy:.4f} "
268
+ f"A:{snap.anchor_count} E:{snap.evidence_count} "
269
+ f"M:{snap.memory_count} C:{snap.conflict_count}")
270
+
271
+
272
+ @main.command()
273
+ def audit():
274
+ """查看审计链状态"""
275
+ s = _load()
276
+ ac = get_audit_chain(WORKSPACE)
277
+ click.echo(f"审计根哈希: {ac.root}")
278
+ click.echo(f"链长度: {len(ac._chain)}")
279
+ click.echo(f"当前state快照校验: anchors={len(s.anchors)} evidence={len(s.evidences)}")
280
+
281
+
282
+ @main.command()
283
+ def audit_log():
284
+ """查看审计日志"""
285
+ ac = get_audit_chain(WORKSPACE)
286
+ path = WORKSPACE / ".liquid" / "audit.log"
287
+ if not path.exists():
288
+ click.echo("审计日志为空。")
289
+ return
290
+ with open(path, "r") as f:
291
+ content = f.read().strip()
292
+ click.echo(content[-2000:] if len(content) > 2000 else content)
293
+
294
+
295
+ @main.command()
296
+ @click.argument("name")
297
+ @click.argument("description")
298
+ @click.option("--density", "-d", default="medium", help="价值密度: high/medium/low")
299
+ @click.option("--stage", "-s", default="raw", help="认知阶段: raw/wip/crystallized/tooling")
300
+ def anchor_add(name, description, density, stage):
301
+ """添加锚点(手动指定分类,支持 auto_classify 自动刷新)"""
302
+ s = _load()
303
+ if any(a.name == name for a in s.anchors):
304
+ click.echo(f"锚点 '{name}' 已存在。")
305
+ return
306
+ anchor = Anchor(
307
+ name=name,
308
+ description=description,
309
+ value_density=density if density in ("high", "medium", "low") else "medium",
310
+ cognitive_stage=stage if stage in ("raw", "wip", "crystallized", "tooling") else "raw",
311
+ )
312
+ # 自动分类:基于名称+描述
313
+ anchor.auto_classify(0)
314
+ s.anchors.append(anchor)
315
+ ac = get_audit_chain(WORKSPACE)
316
+ ac.append("anchor_add", f"{anchor.id}:{name}")
317
+ _save(s)
318
+ click.echo(f"✓ 锚点已添加: {name} ({anchor.id}) [{anchor.value_density}/{anchor.cognitive_stage}/{anchor.liquidity}]")
319
+
320
+
321
+ if __name__ == "__main__":
322
+ main()
@@ -0,0 +1,62 @@
1
+ import json
2
+ import os
3
+ from pathlib import Path
4
+ from dataclasses import asdict
5
+ from .workspace import (
6
+ WorkspaceState, Anchor, Evidence, Memory,
7
+ Conflict, StateSnapshot, AnchorRelation, AuditChain, now,
8
+ )
9
+
10
+
11
+ LIQUID_DIR = ".liquid"
12
+ STATE_FILE = "state.json"
13
+ AUDIT_FILE = "audit.log"
14
+
15
+
16
+ def _ensure_dir(workspace_root: Path) -> Path:
17
+ d = workspace_root / LIQUID_DIR
18
+ d.mkdir(exist_ok=True)
19
+ return d
20
+
21
+
22
+ def get_audit_chain(workspace_root: Path) -> AuditChain:
23
+ """获取审计链实例"""
24
+ return AuditChain(str(_ensure_dir(workspace_root) / AUDIT_FILE))
25
+
26
+
27
+ def load(workspace_root: Path) -> WorkspaceState:
28
+ path = _ensure_dir(workspace_root) / STATE_FILE
29
+ if not path.exists():
30
+ return WorkspaceState()
31
+ with open(path, "r", encoding="utf-8") as f:
32
+ data = json.load(f)
33
+ return _from_dict(data)
34
+
35
+
36
+ def save(state: WorkspaceState, workspace_root: Path):
37
+ state.updated_at = now()
38
+ path = _ensure_dir(workspace_root) / STATE_FILE
39
+ data = asdict(state)
40
+ # 审计:每次保存记录state快照哈希
41
+ audit = get_audit_chain(workspace_root)
42
+ audit.append("state_save",
43
+ f"anchors={len(state.anchors)}_evidences={len(state.evidences)}"
44
+ f"_memories={len(state.memories)}_relations={len(state.relations)}"
45
+ )
46
+ with open(path, "w", encoding="utf-8") as f:
47
+ json.dump(data, f, indent=2, ensure_ascii=False)
48
+
49
+
50
+ def _from_dict(data: dict) -> WorkspaceState:
51
+ return WorkspaceState(
52
+ anchors=[Anchor(**a) for a in data.get("anchors", [])],
53
+ evidences=[Evidence(**e) for e in data.get("evidences", [])],
54
+ memories=[Memory(**m) for m in data.get("memories", [])],
55
+ conflicts=[Conflict(**c) for c in data.get("conflicts", [])],
56
+ relations=[AnchorRelation(**r) for r in data.get("relations", [])],
57
+ snapshots=[StateSnapshot(**s) for s in data.get("snapshots", [])],
58
+ version=data.get("version", "0.3.0"),
59
+ updated_at=data.get("updated_at", ""),
60
+ audit_chain_hash=data.get("audit_chain_hash", "genesis"),
61
+ audit_prev_hash=data.get("audit_prev_hash", ""),
62
+ )
@@ -0,0 +1,248 @@
1
+ from dataclasses import dataclass, field
2
+ from datetime import datetime, timezone
3
+ from typing import Optional
4
+ import uuid
5
+ import hashlib
6
+ import json
7
+ import os
8
+
9
+
10
+ def now() -> str:
11
+ return datetime.now(timezone.utc).isoformat()
12
+
13
+
14
+ def uid() -> str:
15
+ return uuid.uuid4().hex[:12]
16
+
17
+
18
+ # ========== 链式哈希审计(借鉴 KFG MemoryGovernance)==========
19
+
20
+ class AuditChain:
21
+ """轻量级审计链:每次变更追加 SHA256 链式哈希"""
22
+
23
+ def __init__(self, audit_path: str):
24
+ self._path = audit_path
25
+ self._chain: list[str] = []
26
+ self._load()
27
+
28
+ def _load(self):
29
+ if os.path.exists(self._path):
30
+ with open(self._path, "r") as f:
31
+ for line in f:
32
+ line = line.strip()
33
+ if line:
34
+ parts = line.split("|")
35
+ if len(parts) >= 2:
36
+ self._chain.append(parts[1])
37
+
38
+ def append(self, event_type: str, data: str) -> str:
39
+ prev = self._chain[-1] if self._chain else "genesis"
40
+ chain_hash = hashlib.sha256(f"{event_type}:{data}:{prev}".encode()).hexdigest()[:16]
41
+ self._chain.append(chain_hash)
42
+ ts = now()
43
+ with open(self._path, "a") as f:
44
+ f.write(f"{ts}|{chain_hash}|{event_type}|{data}|{prev}\n")
45
+ return chain_hash
46
+
47
+ @property
48
+ def root(self) -> str:
49
+ return self._chain[-1] if self._chain else "genesis"
50
+
51
+ def verify(self, entry: str) -> bool:
52
+ """验证某条完整日志行是否匹配链中记录
53
+
54
+ 格式: timestamp|chain_hash|event_type|data|prev_hash
55
+ """
56
+ if "|" not in entry:
57
+ return False
58
+ parts = entry.strip().split("|")
59
+ if len(parts) < 5:
60
+ return False
61
+ _, stored_hash, event_type, data, prev = parts[:5]
62
+ expected = hashlib.sha256(f"{event_type}:{data}:{prev}".encode()).hexdigest()[:16]
63
+ return expected == stored_hash
64
+
65
+
66
+ # --- 四维分类(借鉴 KFG 4D Classifier)---
67
+
68
+ # 价值密度等级
69
+ DensityLevel = str # "high" | "medium" | "low"
70
+
71
+ # 认知阶段
72
+ CognitiveStage = str # "raw" | "wip" | "crystallized" | "tooling"
73
+
74
+ # 流动性等级
75
+ LiquidityLevel = str # "hot" | "warm" | "cold" | "frozen"
76
+
77
+
78
+ @dataclass
79
+ class Anchor:
80
+ id: str = field(default_factory=uid)
81
+ name: str = ""
82
+ description: str = ""
83
+ created_at: str = field(default_factory=now)
84
+
85
+ # 稳定性(原)
86
+ stability: float = 1.0 # 0.0=完全漂移, 1.0=完全稳定
87
+ evidence_ids: list[str] = field(default_factory=list)
88
+
89
+ # 【新增】四维分类标签(借鉴 KFG)
90
+ value_density: str = "medium" # high | medium | low
91
+ cognitive_stage: str = "raw" # raw | wip | crystallized | tooling
92
+ liquidity: str = "warm" # hot | warm | cold | frozen
93
+
94
+ # 【新增】价值衰减指标(借鉴 KFG Factor.value 计算)
95
+ access_count: int = 0 # 被引用/访问次数
96
+ last_accessed: str = "" # 最后访问时间
97
+ value_score: float = 1.0 # 衰减后价值(0.0~1.0)
98
+
99
+ # 【新增】锚定强度(基于证据支持度 + 访问活跃度)
100
+ anchor_strength: float = 1.0 # 0.0~1.0
101
+
102
+ def decay_value(self, factor: float = 0.95, evidence_count: int = 0) -> float:
103
+ """价值衰减计算(双因模型,借鉴 KFG MemoryGovernance.check_decay)
104
+
105
+ 公式: score = freq_score × 0.4 + time_score × 0.6
106
+ - freq_score: 使用频率(证据数+访问次数),上限1.0
107
+ - time_score: 时间衰减(30天从1.0→0.0)
108
+ """
109
+ if not self.created_at:
110
+ return 0.0
111
+ try:
112
+ created = datetime.fromisoformat(self.created_at)
113
+ except ValueError:
114
+ return 0.0
115
+ now_dt = datetime.now(timezone.utc)
116
+ days = (now_dt - created).days
117
+
118
+ # 双因模型
119
+ freq_score = min((evidence_count * 0.12 + self.access_count * 0.08), 1.0)
120
+ time_score = max(0.0, 1.0 - days / 30)
121
+ raw = (freq_score * 0.4 + time_score * 0.6) * (factor ** max(days, 0))
122
+ self.value_score = max(0.0, min(1.0, raw))
123
+ return self.value_score
124
+
125
+ def recalc_strength(self, evidence_count: int) -> float:
126
+ """锚定强度 = 证据支持度 × 活跃度"""
127
+ evidence_factor = min(evidence_count / 5, 1.0) # 5条证据满
128
+ activity = self.value_score
129
+ self.anchor_strength = evidence_factor * 0.6 + activity * 0.4
130
+ self.anchor_strength = max(0.0, min(1.0, self.anchor_strength))
131
+ return self.anchor_strength
132
+
133
+ def auto_classify(self, evidence_count: int) -> dict:
134
+ """自动推断四维分类标签(借鉴 KFG 4D Classifier 逻辑)
135
+
136
+ 根据证据数量、锚定强度、活跃度自动调整:
137
+ - 价值密度: evidence多+强锚定 → high, 否则 low
138
+ - 认知阶段: 强锚定+高价值 → crystallized, 弱→raw
139
+ - 流动性: 最近有活动→hot, 否则→cold/frozen
140
+ """
141
+ self.decay_value(evidence_count=evidence_count)
142
+ self.recalc_strength(evidence_count)
143
+
144
+ # 价值密度
145
+ if self.anchor_strength > 0.8 and evidence_count >= 3:
146
+ self.value_density = "high"
147
+ elif self.anchor_strength > 0.4 or evidence_count >= 1:
148
+ self.value_density = "medium"
149
+ else:
150
+ self.value_density = "low"
151
+
152
+ # 认知阶段
153
+ if self.value_score > 0.7 and self.anchor_strength > 0.7:
154
+ self.cognitive_stage = "crystallized"
155
+ elif self.value_score > 0.4:
156
+ self.cognitive_stage = "wip"
157
+ elif evidence_count == 0:
158
+ self.cognitive_stage = "raw"
159
+ else:
160
+ self.cognitive_stage = "wip"
161
+
162
+ # 流动性
163
+ if self.last_accessed:
164
+ try:
165
+ last = datetime.fromisoformat(self.last_accessed)
166
+ gap_hours = (datetime.now(timezone.utc) - last).total_seconds() / 3600
167
+ if gap_hours < 24:
168
+ self.liquidity = "hot"
169
+ elif gap_hours < 168:
170
+ self.liquidity = "warm"
171
+ elif gap_hours < 720:
172
+ self.liquidity = "cold"
173
+ else:
174
+ self.liquidity = "frozen"
175
+ except ValueError:
176
+ pass
177
+
178
+ return {
179
+ "value_density": self.value_density,
180
+ "cognitive_stage": self.cognitive_stage,
181
+ "liquidity": self.liquidity,
182
+ }
183
+
184
+
185
+ @dataclass
186
+ class Evidence:
187
+ id: str = field(default_factory=uid)
188
+ anchor_id: str = ""
189
+ content: str = ""
190
+ timestamp: str = field(default_factory=now)
191
+ weight: float = 1.0 # 证据权重, 默认1.0
192
+
193
+ # 【新增】证据质量标签
194
+ quality: str = "normal" # strong | normal | weak
195
+
196
+
197
+ @dataclass
198
+ class Memory:
199
+ id: str = field(default_factory=uid)
200
+ content: str = ""
201
+ formed_at: str = field(default_factory=now)
202
+ evidence_ids: list[str] = field(default_factory=list) # 成核来源
203
+ confidence: float = 0.0 # 0.0-1.0, 基于证据一致性
204
+
205
+
206
+ @dataclass
207
+ class Conflict:
208
+ anchor_a: str = ""
209
+ anchor_b: str = ""
210
+ description: str = ""
211
+ detected_at: str = field(default_factory=now)
212
+ severity: float = 0.0 # 0.0-1.0
213
+
214
+
215
+ # 【新增】锚点关系(借鉴 KFG Relation + 传递闭包)
216
+ @dataclass
217
+ class AnchorRelation:
218
+ source_id: str = ""
219
+ target_id: str = ""
220
+ relation_type: str = "relates_to" # depends_on | relates_to | supersedes | conflicts_with
221
+ weight: float = 1.0 # 0.0~1.0
222
+ created_at: str = field(default_factory=now)
223
+
224
+
225
+ @dataclass
226
+ class StateSnapshot:
227
+ timestamp: str = field(default_factory=now)
228
+ entropy: float = 0.0
229
+ anchor_count: int = 0
230
+ evidence_count: int = 0
231
+ memory_count: int = 0
232
+ conflict_count: int = 0
233
+
234
+
235
+ @dataclass
236
+ class WorkspaceState:
237
+ anchors: list[Anchor] = field(default_factory=list)
238
+ evidences: list[Evidence] = field(default_factory=list)
239
+ memories: list[Memory] = field(default_factory=list)
240
+ conflicts: list[Conflict] = field(default_factory=list)
241
+ snapshots: list[StateSnapshot] = field(default_factory=list)
242
+ # 【新增】锚点关系
243
+ relations: list[AnchorRelation] = field(default_factory=list)
244
+ # 【新增】审计链哈希(每次 save 自动更新)
245
+ audit_chain_hash: str = "genesis"
246
+ audit_prev_hash: str = ""
247
+ version: str = "0.3.0"
248
+ updated_at: str = field(default_factory=now)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liquid-loop
3
- Version: 0.1.2
3
+ Version: 0.3.0
4
4
  Summary: Self-Organizing Cognitive Memory for AI Agents — Liquid Loop theory implementation
5
5
  Author: fishbook0001
6
6
  Maintainer: fishbook0001
@@ -123,27 +123,24 @@ save(state, Path("."))
123
123
  # 初始化工作区(创建 .liquid/state.json)
124
124
  liquid-loop init
125
125
 
126
- # 添加锚点
126
+ # 添加锚点(支持自动四维分类)
127
127
  liquid-loop anchor_add "项目目标" "完成液环论文与开源"
128
128
 
129
129
  # 注入证据
130
130
  liquid-loop evidence_add "项目目标" "已完成 11 轮实验与 4 个实证包"
131
131
 
132
- # 查看状态
132
+ # 查看状态(含审计链哈希)
133
133
  liquid-loop status
134
- # 输出:
135
- # ╭──────────────────────────────────────────────╮
136
- # │ Liquid Loop 认知状态 │
137
- # ├──────────┬──────┬────────┬────────┬────────┬──┤
138
- # │ 锚点 │ 证据 │ 结晶 │ 冲突 │ 熵值 │ │
139
- # ├──────────┼──────┼────────┼────────┼────────┼──┤
140
- # │ 项目目标 │ 3 │ 1 │ 0 │ 0.2760 │ 🟢│
141
- # ╰──────────┴──────┴────────┴────────┴────────┴──╯
142
- # 锚点稳定性: 项目目标=0.88
143
134
 
144
135
  # 列出所有记忆结晶
145
136
  liquid-loop memory_list
146
137
 
138
+ # 审计:验证链式哈希完整性
139
+ liquid-loop audit
140
+
141
+ # 查看审计日志(最近 20 条)
142
+ liquid-loop audit-log --tail 20
143
+
147
144
  # 快照(记录当前认知基线)
148
145
  liquid-loop snapshot
149
146
  ```
@@ -194,10 +191,10 @@ Liquid Loop 是唯一完全自组织 + 零 LLM 管理的系统。
194
191
  liquid-loop/
195
192
  ├── liquid_loop/
196
193
  │ ├── __init__.py # 公共 API 导出
197
- │ ├── workspace.py # 核心数据模型
198
- │ ├── storage.py # JSON 持久化
194
+ │ ├── workspace.py # 核心数据模型 + AuditChain + auto_classify + decay
195
+ │ ├── storage.py # JSON 持久化 + 审计链写入
199
196
  │ ├── entropy.py # 四维熵值计算
200
- │ └── cli.py # Click CLI (9 命令)
197
+ │ └── cli.py # Click CLI (11 命令)
201
198
  ├── examples/
202
199
  │ └── quickstart.py
203
200
  ├── tests/ # 待补充
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "liquid-loop"
7
- version = "0.1.2"
7
+ version = "0.3.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"}
@@ -1,72 +0,0 @@
1
- """
2
- Liquid Loop — Self-Organizing Cognitive Memory for AI Agents
3
-
4
- A zero-LLM-dependency cognitive runtime implementing the Liquid Loop theory:
5
- Anchor → Evidence → Memory Nucleation with four-dimensional entropy monitoring.
6
-
7
- Core Concepts:
8
- - Anchor: Cognitive focus points with stability tracking
9
- - Evidence: Observations that accumulate under anchors (exponential decay)
10
- - Memory: Crystallized knowledge from 2+ consistent evidences
11
- - Entropy: Four-dimensional cognitive health metric (drift/conflict/fragmentation/gap)
12
-
13
- Usage:
14
- from liquid_loop import WorkspaceState, Anchor, Evidence, Memory
15
- from liquid_loop import load, save, calculate_entropy
16
- from liquid_loop.cli import main as cli_main
17
-
18
- # Quick start
19
- state = WorkspaceState()
20
- anchor_id = state.add_anchor("核心使命", "系统的核心目标")
21
- state.add_evidence(anchor_id, "用户偏好简洁输出")
22
- state.add_evidence(anchor_id, "用户偏好简洁输出") # 2次一致 -> 结晶
23
- print(f"结晶记忆: {len(state.memories)} 条")
24
-
25
- CLI:
26
- python -m liquid_loop init
27
- python -m liquid_loop anchor_add "项目目标" "完成液环论文"
28
- python -m liquid_loop evidence_add "项目目标" "已完成实证数据收集"
29
- python -m liquid_loop status
30
- """
31
-
32
- from liquid_loop.workspace import (
33
- WorkspaceState,
34
- Anchor,
35
- Evidence,
36
- Memory,
37
- Conflict,
38
- StateSnapshot,
39
- )
40
-
41
- from liquid_loop.storage import load, save, LIQUID_DIR, STATE_FILE
42
-
43
- from liquid_loop.entropy import calculate_entropy
44
-
45
- __version__ = "0.1.0"
46
- __author__ = "Fei Ge"
47
- __license__ = "MIT"
48
-
49
- __all__ = [
50
- # Core data models
51
- "WorkspaceState",
52
- "Anchor",
53
- "Evidence",
54
- "Memory",
55
- "Conflict",
56
- "StateSnapshot",
57
- # Persistence
58
- "load",
59
- "save",
60
- "LIQUID_DIR",
61
- "STATE_FILE",
62
- # Entropy
63
- "calculate_entropy",
64
- "EntropyComponents",
65
- # CLI
66
- "cli_main",
67
- ]
68
-
69
- # Lazy import CLI to avoid click dependency at import time
70
- def cli_main():
71
- from liquid_loop.cli import main
72
- return main()
@@ -1,182 +0,0 @@
1
- import click
2
- from pathlib import Path
3
- from .workspace import (
4
- WorkspaceState, Anchor, Evidence, Memory, StateSnapshot, now,
5
- _nucleate, _decay_evidence, _recalc_stability,
6
- )
7
- from .storage import load, save
8
- from .entropy import calculate as calculate_entropy
9
-
10
-
11
- WORKSPACE = Path.cwd()
12
-
13
-
14
- def _load():
15
- return load(WORKSPACE)
16
-
17
-
18
- def _save(state: WorkspaceState):
19
- state.updated_at = now()
20
- save(state, WORKSPACE)
21
-
22
-
23
- # --- CLI ---
24
-
25
- @click.group()
26
- def main():
27
- """Liquid Loop — Workspace Cognitive Runtime"""
28
- pass
29
-
30
-
31
- @main.command()
32
- def init():
33
- """初始化 Liquid Loop 工作区"""
34
- s = _load()
35
- if s.anchors or s.evidences:
36
- click.echo("工作区已初始化,无需重复操作。")
37
- return
38
- s.version = "0.1.0"
39
- _save(s)
40
- click.echo(f"✓ Liquid Loop 工作区已初始化: {WORKSPACE}/.liquid/")
41
-
42
-
43
- @main.command()
44
- def status():
45
- """显示当前认知状态"""
46
- s = _load()
47
- ent = calculate_entropy(s)
48
- level = "GREEN" if ent < 0.3 else ("YELLOW" if ent < 0.6 else "RED")
49
- latest_ev = max((e.timestamp for e in s.evidences), default="无活动")
50
- click.echo(f"锚点: {len(s.anchors)} | 证据: {len(s.evidences)} | 记忆: {len(s.memories)} | 冲突: {len(s.conflicts)}")
51
- click.echo(f"熵值: {ent:.4f} [{level}] | 最新活动: {latest_ev}")
52
-
53
-
54
- @main.command()
55
- @click.argument("name")
56
- @click.argument("description")
57
- def anchor_add(name, description):
58
- """添加锚点"""
59
- s = _load()
60
- # 同名检查
61
- if any(a.name == name for a in s.anchors):
62
- click.echo(f"锚点 '{name}' 已存在。")
63
- return
64
- anchor = Anchor(name=name, description=description)
65
- s.anchors.append(anchor)
66
- _save(s)
67
- click.echo(f"✓ 锚点已添加: {name} ({anchor.id})")
68
-
69
-
70
- @main.command()
71
- def anchor_list():
72
- """列出所有锚点"""
73
- s = _load()
74
- if not s.anchors:
75
- click.echo("暂无锚点。使用 liquid anchor add <名称> <描述> 添加。")
76
- return
77
- for a in s.anchors:
78
- bar = "█" * int(a.stability * 10) + "░" * (10 - int(a.stability * 10))
79
- click.echo(f"[{a.stability:.2f}] {bar} {a.name}: {a.description}")
80
-
81
-
82
- @main.command()
83
- @click.argument("anchor_name")
84
- @click.argument("content")
85
- def evidence_add(anchor_name, content):
86
- """为锚点添加证据"""
87
- s = _load()
88
- anchor = next((a for a in s.anchors if a.name == anchor_name), None)
89
- if not anchor:
90
- click.echo(f"锚点 '{anchor_name}' 不存在。请先创建。")
91
- return
92
- evidence = Evidence(anchor_id=anchor.id, content=content)
93
- s.evidences.append(evidence)
94
- anchor.evidence_ids.append(evidence.id)
95
- # 衰减 + 重算 + 成核
96
- _decay_evidence(s, anchor.id)
97
- _recalc_stability(s, anchor.id)
98
- _nucleate(s, anchor.id)
99
- _save(s)
100
- click.echo(f"✓ 证据已添加: [{anchor_name}] {content[:40]}... ({evidence.id})")
101
-
102
-
103
- @main.command()
104
- @click.option("--anchor", "-a", default=None, help="按锚点名称过滤")
105
- def evidence_list(anchor):
106
- """列出证据"""
107
- s = _load()
108
- evs = s.evidences
109
- if anchor:
110
- a = next((x for x in s.anchors if x.name == anchor), None)
111
- if not a:
112
- click.echo(f"锚点 '{anchor}' 不存在。")
113
- return
114
- evs = [e for e in evs if e.anchor_id == a.id]
115
- click.echo(f"--- {anchor} ---")
116
- if not evs:
117
- click.echo("暂无证据。")
118
- return
119
- for e in sorted(evs, key=lambda x: x.timestamp, reverse=True):
120
- anchor_name = next((a.name for a in s.anchors if a.id == e.anchor_id), "?")
121
- click.echo(f"[{e.weight:.2f}] {e.timestamp[:19]} [{anchor_name}] {e.content}")
122
-
123
-
124
- @main.command()
125
- def memory_list():
126
- """列出已形成的记忆"""
127
- s = _load()
128
- if not s.memories:
129
- click.echo("暂无记忆。当同一锚点下有 2 条以上一致证据时自动成核。")
130
- return
131
- for m in sorted(s.memories, key=lambda x: x.confidence, reverse=True):
132
- click.echo(f"[conf={m.confidence:.2f}] {m.formed_at[:19]} {m.content}")
133
-
134
-
135
- @main.command()
136
- def check():
137
- """检查工作区熵值"""
138
- s = _load()
139
- ent = calculate_entropy(s)
140
- if ent < 0.3:
141
- level, icon = "GREEN", "✓"
142
- elif ent < 0.6:
143
- level, icon = "YELLOW", "⚠"
144
- else:
145
- level, icon = "RED", "✗"
146
- click.echo(f"{icon} 熵值: {ent:.4f} [{level}]")
147
- if ent >= 0.6:
148
- click.echo("建议: 检查锚点漂移、添加新证据或解决冲突。")
149
-
150
-
151
- @main.command()
152
- def snapshot():
153
- """保存当前状态快照"""
154
- s = _load()
155
- ent = calculate_entropy(s)
156
- snap = StateSnapshot(
157
- entropy=ent,
158
- anchor_count=len(s.anchors),
159
- evidence_count=len(s.evidences),
160
- memory_count=len(s.memories),
161
- conflict_count=len(s.conflicts),
162
- )
163
- s.snapshots.append(snap)
164
- _save(s)
165
- click.echo(f"✓ 快照已保存 (熵值: {ent:.4f})")
166
-
167
-
168
- @main.command()
169
- def snapshots():
170
- """列出历史快照"""
171
- s = _load()
172
- if not s.snapshots:
173
- click.echo("暂无快照。使用 liquid snapshot 保存。")
174
- return
175
- for i, snap in enumerate(s.snapshots):
176
- click.echo(f"[{i}] {snap.timestamp[:19]} 熵={snap.entropy:.4f} "
177
- f"A:{snap.anchor_count} E:{snap.evidence_count} "
178
- f"M:{snap.memory_count} C:{snap.conflict_count}")
179
-
180
-
181
- if __name__ == "__main__":
182
- main()
@@ -1,44 +0,0 @@
1
- import json
2
- import os
3
- from pathlib import Path
4
- from dataclasses import asdict
5
- from .workspace import WorkspaceState, Anchor, Evidence, Memory, Conflict, StateSnapshot
6
-
7
-
8
- LIQUID_DIR = ".liquid"
9
- STATE_FILE = "state.json"
10
-
11
-
12
- def _ensure_dir(workspace_root) -> Path:
13
- if isinstance(workspace_root, str):
14
- workspace_root = Path(workspace_root)
15
- d = workspace_root / LIQUID_DIR
16
- d.mkdir(exist_ok=True)
17
- return d
18
-
19
-
20
- def load(workspace_root) -> WorkspaceState:
21
- path = _ensure_dir(workspace_root) / STATE_FILE
22
- if not path.exists():
23
- return WorkspaceState()
24
- with open(path, "r", encoding="utf-8") as f:
25
- data = json.load(f)
26
- return _from_dict(data)
27
-
28
-
29
- def save(state: WorkspaceState, workspace_root):
30
- path = _ensure_dir(workspace_root) / STATE_FILE
31
- with open(path, "w", encoding="utf-8") as f:
32
- json.dump(asdict(state), f, indent=2, ensure_ascii=False)
33
-
34
-
35
- def _from_dict(data: dict) -> WorkspaceState:
36
- return WorkspaceState(
37
- anchors=[Anchor(**a) for a in data.get("anchors", [])],
38
- evidences=[Evidence(**e) for e in data.get("evidences", [])],
39
- memories=[Memory(**m) for m in data.get("memories", [])],
40
- conflicts=[Conflict(**c) for c in data.get("conflicts", [])],
41
- snapshots=[StateSnapshot(**s) for s in data.get("snapshots", [])],
42
- version=data.get("version", "0.1.0"),
43
- updated_at=data.get("updated_at", ""),
44
- )
@@ -1,130 +0,0 @@
1
- from dataclasses import dataclass, field
2
- from datetime import datetime, timezone
3
- from typing import Optional
4
- import uuid
5
- from collections import Counter
6
-
7
-
8
- def now() -> str:
9
- return datetime.now(timezone.utc).isoformat()
10
-
11
-
12
- def uid() -> str:
13
- return uuid.uuid4().hex[:12]
14
-
15
-
16
- # ── Liquid Loop Core Chain ──────────────────────────────────
17
-
18
- def _nucleate(state: "WorkspaceState", anchor_id: str):
19
- """检查指定 Anchor 下的 Evidence,2+ 条则成核为 Memory"""
20
- group = [e for e in state.evidences if e.anchor_id == anchor_id]
21
- if len(group) < 2:
22
- return
23
- content_counts = Counter(e.content for e in group)
24
- for content, count in content_counts.items():
25
- if count >= 2:
26
- existing = [m for m in state.memories if m.content == content]
27
- if existing:
28
- continue
29
- evidence_ids = [e.id for e in group if e.content == content]
30
- confidence = min(count / len(group), 1.0)
31
- memory = Memory(
32
- content=content,
33
- evidence_ids=evidence_ids,
34
- confidence=confidence,
35
- )
36
- state.memories.append(memory)
37
-
38
-
39
- def _decay_evidence(state: "WorkspaceState", anchor_id: str):
40
- """Stability decay: 每次添加 Evidence 时,同 Anchor 下的旧 Evidence 权重衰减"""
41
- for e in state.evidences:
42
- if e.anchor_id == anchor_id:
43
- e.weight = max(e.weight * 0.95, 0.1)
44
-
45
-
46
- def _recalc_stability(state: "WorkspaceState", anchor_id: str):
47
- """基于证据权重更新 Anchor 稳定性"""
48
- anchor = next((a for a in state.anchors if a.id == anchor_id), None)
49
- if not anchor:
50
- return
51
- evs = [e for e in state.evidences if e.anchor_id == anchor_id]
52
- if not evs:
53
- anchor.stability = 1.0
54
- return
55
- # 稳定性 = 平均权重(权重越高越稳定)
56
- anchor.stability = sum(e.weight for e in evs) / len(evs)
57
-
58
-
59
- @dataclass
60
- class Anchor:
61
- id: str = field(default_factory=uid)
62
- name: str = ""
63
- description: str = ""
64
- created_at: str = field(default_factory=now)
65
- stability: float = 1.0 # 0.0=完全漂移, 1.0=完全稳定
66
- evidence_ids: list[str] = field(default_factory=list)
67
-
68
-
69
- @dataclass
70
- class Evidence:
71
- id: str = field(default_factory=uid)
72
- anchor_id: str = ""
73
- content: str = ""
74
- timestamp: str = field(default_factory=now)
75
- weight: float = 1.0 # 证据权重, 默认1.0
76
-
77
-
78
- @dataclass
79
- class Memory:
80
- id: str = field(default_factory=uid)
81
- content: str = ""
82
- formed_at: str = field(default_factory=now)
83
- evidence_ids: list[str] = field(default_factory=list) # 成核来源
84
- confidence: float = 0.0 # 0.0-1.0, 基于证据一致性
85
-
86
-
87
- @dataclass
88
- class Conflict:
89
- anchor_a: str = ""
90
- anchor_b: str = ""
91
- description: str = ""
92
- detected_at: str = field(default_factory=now)
93
- severity: float = 0.0 # 0.0-1.0
94
-
95
-
96
- @dataclass
97
- class StateSnapshot:
98
- timestamp: str = field(default_factory=now)
99
- entropy: float = 0.0
100
- anchor_count: int = 0
101
- evidence_count: int = 0
102
- memory_count: int = 0
103
- conflict_count: int = 0
104
-
105
-
106
- @dataclass
107
- class WorkspaceState:
108
- anchors: list[Anchor] = field(default_factory=list)
109
- evidences: list[Evidence] = field(default_factory=list)
110
- memories: list[Memory] = field(default_factory=list)
111
- conflicts: list[Conflict] = field(default_factory=list)
112
- snapshots: list[StateSnapshot] = field(default_factory=list)
113
- version: str = "0.1.0"
114
- updated_at: str = field(default_factory=now)
115
-
116
- def add_anchor(self, name: str, description: str = "") -> str:
117
- """添加锚点,返回 anchor_id"""
118
- anchor = Anchor(name=name, description=description)
119
- self.anchors.append(anchor)
120
- return anchor.id
121
-
122
- def add_evidence(self, anchor_id: str, content: str) -> str:
123
- """添加证据到指定锚点,触发液环自动链:成核→衰减→稳定性重算"""
124
- evidence = Evidence(anchor_id=anchor_id, content=content)
125
- self.evidences.append(evidence)
126
- # Liquid Loop 自动链
127
- _nucleate(self, anchor_id)
128
- _decay_evidence(self, anchor_id)
129
- _recalc_stability(self, anchor_id)
130
- return evidence.id
File without changes
File without changes