dsh-biocore 0.3.3 → 0.5.0
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/lib/index.js +30 -1
- package/lib/modules/standby.js +61 -0
- package/lib/modules/state.js +22 -3
- package/package.json +1 -1
- package/python/biocore_memory/core/config.py +7 -3
- package/python/biocore_memory/engine.py +91 -6
- package/python/biocore_memory/recall/embedding.py +0 -51
- package/python/biocore_memory/recall/feedback.py +34 -7
- package/python/biocore_memory/recall/fusion.py +5 -1
- package/python/biocore_memory/scoring.py +203 -0
- package/python/biocore_memory/space.py +355 -0
- package/python/biocore_memory/store/dedupe.py +1 -0
- package/python/biocore_memory/store/tiering.py +14 -3
- package/python/biocore_model/affective_labor.py +14 -1
- package/python/biocore_model/appraisal.py +172 -3
- package/python/biocore_model/bio_tick.py +43 -13
- package/python/biocore_model/emotion_geometry.py +9 -0
- package/python/biocore_model/envy.py +21 -0
- package/python/biocore_model/feedback_memory.py +53 -0
- package/python/biocore_model/needs_events.py +32 -11
- package/python/biocore_model/regulation_strategies.py +5 -0
- package/python/biocore_model/repair_after_boundary.py +1 -0
- package/python/biocore_model/self_esteem.py +14 -2
- package/python/biocore_model/self_intent.py +6 -4
- package/python/biocore_model/tests/test_autonomy_self.py +153 -153
- package/python/biocore_model/tests/test_cache_series.py +137 -0
- package/python/biocore_model/tests/test_core_state.py +240 -240
- package/python/biocore_model/tests/test_extensions.py +167 -167
- package/python/biocore_model/tests/test_field_arbiter.py +444 -0
- package/python/biocore_model/tests/test_governance.py +181 -181
- package/python/biocore_model/tests/test_lifecycle.py +153 -0
- package/python/biocore_model/tests/test_memory_inject.py +211 -211
- package/python/biocore_model/tests/test_retrieval_plus.py +143 -0
- package/python/biocore_model/tests/test_signals.py +106 -106
- package/python/biocore_model/tests/test_standby.py +199 -0
- package/python/biocore_runtime/__init__.py +3 -0
- package/python/biocore_runtime/arbiter.py +307 -0
- package/python/biocore_runtime/batch_b.py +724 -0
- package/python/biocore_runtime/batch_c.py +186 -0
- package/python/biocore_runtime/batch_d.py +659 -0
- package/python/biocore_runtime/batch_e.py +328 -0
- package/python/biocore_runtime/batch_registry.py +446 -0
- package/python/biocore_runtime/cache_stats.py +161 -0
- package/python/biocore_runtime/core_state.py +106 -3
- package/python/biocore_runtime/dimensions.py +419 -0
- package/python/biocore_runtime/expression.py +261 -0
- package/python/biocore_runtime/field.py +440 -0
- package/python/biocore_runtime/lifecycle.py +233 -0
- package/python/biocore_runtime/perception.py +1045 -0
- package/python/biocore_runtime/pipeline.py +4458 -2974
- package/python/biocore_runtime/priority.py +210 -0
- package/python/biocore_runtime/retrieval_plus.py +352 -0
- package/python/biocore_runtime/standby.py +581 -472
- package/python/biocore_runtime/timescales.py +263 -0
- package/python/data/signals.json +3266 -206
- package/ui/panel-layout.js +32 -29
- package/ui/panel.css +563 -974
- package/ui/panel.html +427 -401
- package/ui/panel.js +543 -450
|
@@ -1,167 +1,167 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""task-225 (5b): P0 memory extensions + expression modules."""
|
|
3
|
-
import json
|
|
4
|
-
import tempfile
|
|
5
|
-
import time
|
|
6
|
-
import unittest
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
from biocore_model import (entity_graph, entity_resolve, expr_template,
|
|
10
|
-
graph_extract, graph_recall, layered_memory,
|
|
11
|
-
memory_dual, prompt_rules, prospective,
|
|
12
|
-
reconstruction, template_expr, topic_control,
|
|
13
|
-
turn_memory, voice_bank)
|
|
14
|
-
from biocore_runtime import extensions, pipeline
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def entry(i, text, ts=1700000000.0):
|
|
18
|
-
return {"id": i, "text": text, "role": "user", "ts": ts,
|
|
19
|
-
"importance": 0.5, "hits": 1}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class Case(unittest.TestCase):
|
|
23
|
-
def setUp(self):
|
|
24
|
-
self.tmp = tempfile.TemporaryDirectory()
|
|
25
|
-
self.data_dir = Path(self.tmp.name) / "data"
|
|
26
|
-
self.store = self.data_dir / "memory"
|
|
27
|
-
(self.store / "sessions" / "s1").mkdir(parents=True)
|
|
28
|
-
|
|
29
|
-
def tearDown(self):
|
|
30
|
-
self.tmp.cleanup()
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class GraphTest(Case):
|
|
34
|
-
def test_entity_graph_build_search(self):
|
|
35
|
-
graph, _ = extensions._entity_graph([
|
|
36
|
-
entry("a", "苹果 很甜"), entry("b", "苹果 咖啡")])
|
|
37
|
-
self.assertGreaterEqual(len(graph.get("entities") or []), 1)
|
|
38
|
-
hits = entity_graph.search(graph, "苹果", limit=4)
|
|
39
|
-
self.assertTrue(hits)
|
|
40
|
-
|
|
41
|
-
def test_entity_resolve(self):
|
|
42
|
-
self.assertEqual(entity_resolve.normalize("苹果 甜"), "苹果甜")
|
|
43
|
-
self.assertGreaterEqual(entity_resolve.similarity("苹果", "苹果"), 0.9)
|
|
44
|
-
|
|
45
|
-
def test_graph_extract(self):
|
|
46
|
-
self.assertEqual(graph_extract.canonical_type("人物"), "person")
|
|
47
|
-
self.assertGreater(graph_extract.when_to_ts("明天", 1000.0), 1000.0)
|
|
48
|
-
|
|
49
|
-
def test_graph_recall_window(self):
|
|
50
|
-
window = graph_recall.detect_window("上周")
|
|
51
|
-
self.assertNotEqual(window, None)
|
|
52
|
-
|
|
53
|
-
def test_graph_hits_extra(self):
|
|
54
|
-
rows = [entry("a", "苹果 很甜"), entry("b", "苹果 咖啡"),
|
|
55
|
-
entry("c", "香蕉")]
|
|
56
|
-
hits, stats = extensions.graph_hits(rows, "苹果")
|
|
57
|
-
self.assertGreaterEqual(stats["hits"], 0)
|
|
58
|
-
self.assertIsInstance(hits, list)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class MemoryExtTest(Case):
|
|
62
|
-
def test_layered_select(self):
|
|
63
|
-
result = layered_memory.select([entry("a", "早上的事"), entry("b", "刚才的事")],
|
|
64
|
-
recalled_ids=["b"])
|
|
65
|
-
self.assertIn("resident", result)
|
|
66
|
-
self.assertIn("retrieval", result)
|
|
67
|
-
self.assertTrue(result["resident"] or result["retrieval"])
|
|
68
|
-
|
|
69
|
-
def test_memory_dual_score(self):
|
|
70
|
-
e = memory_dual.encode("苹果", 1700000000.0, arousal=0.5)
|
|
71
|
-
self.assertGreater(memory_dual.score(e, 1700000100.0), 0)
|
|
72
|
-
self.assertTrue(memory_dual.select([e], 1700000100.0, limit=2))
|
|
73
|
-
|
|
74
|
-
def test_prospective_due(self):
|
|
75
|
-
now = time.time()
|
|
76
|
-
rec = prospective.entry("his_event", "体检", now - 10)
|
|
77
|
-
items, changed = prospective.add([], rec)
|
|
78
|
-
self.assertTrue(changed)
|
|
79
|
-
due = prospective.due_now(items, now, window_s=60)
|
|
80
|
-
self.assertEqual(len(due), 1)
|
|
81
|
-
self.assertTrue(prospective.build_hint(due[0], now))
|
|
82
|
-
self.assertEqual(prospective.stats(items)["by_status"]["pending"], 1)
|
|
83
|
-
|
|
84
|
-
def test_reconstruction(self):
|
|
85
|
-
out = reconstruction.conserve([entry("a", "旧的记忆")])
|
|
86
|
-
self.assertIn("total", out)
|
|
87
|
-
|
|
88
|
-
def test_turn_memory(self):
|
|
89
|
-
rows = turn_memory.build([{"entry_id": "a", "text": "记得喝水",
|
|
90
|
-
"source": "recall"}])
|
|
91
|
-
self.assertEqual(len(rows), 1)
|
|
92
|
-
record = turn_memory.build_record(rows, reply="好", ts=10.0)
|
|
93
|
-
self.assertTrue(turn_memory.render_receipt(record))
|
|
94
|
-
|
|
95
|
-
def test_recall_graph_expansion(self):
|
|
96
|
-
rows = [entry("a", "苹果 很甜", 1700000001.0),
|
|
97
|
-
entry("b", "苹果 咖啡", 1700000002.0),
|
|
98
|
-
entry("c", "香蕉 黄", 1700000003.0)]
|
|
99
|
-
(self.store / "sessions" / "s1" / "memory.json").write_text(
|
|
100
|
-
json.dumps({"entries": rows}), encoding="utf-8")
|
|
101
|
-
out = pipeline.inject_block("s1", str(self.store), query="苹果 咖啡",
|
|
102
|
-
mode="query", top_k=3)
|
|
103
|
-
self.assertGreaterEqual(len(out["ids"]), 2)
|
|
104
|
-
self.assertIn("b", out["ids"])
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
class ExpressionTest(Case):
|
|
108
|
-
def test_expr_template(self):
|
|
109
|
-
out = expr_template.build_reply({"v": 0.2}, {"trust": 0.5})
|
|
110
|
-
self.assertIsInstance(out, dict)
|
|
111
|
-
|
|
112
|
-
def test_prompt_rules(self):
|
|
113
|
-
text = prompt_rules.render_rules(affect={"valence": -0.4, "stress": 0.7},
|
|
114
|
-
relation={"closeness": 0.5},
|
|
115
|
-
certainty=0.7, soft_target=12,
|
|
116
|
-
soft_max=30)
|
|
117
|
-
self.assertIsInstance(text, str)
|
|
118
|
-
self.assertTrue(text)
|
|
119
|
-
|
|
120
|
-
def test_template_expr(self):
|
|
121
|
-
self.assertEqual(template_expr.render("你好 {{name}}", {"name": "主管"}),
|
|
122
|
-
"你好 主管")
|
|
123
|
-
|
|
124
|
-
def test_topic_control(self):
|
|
125
|
-
result = topic_control.topic_control(turns=[], state={"v": 0.0},
|
|
126
|
-
relationship={"trust": 0.5})
|
|
127
|
-
self.assertIsInstance(result, dict)
|
|
128
|
-
self.assertTrue("tendency" in result or "holder" in result)
|
|
129
|
-
|
|
130
|
-
def test_voice_bank(self):
|
|
131
|
-
bank = [{"id": "v1", "phrase": "嗯。", "weight": 1.0,
|
|
132
|
-
"when": {"v_min": -1, "v_max": 1, "tension_min": 0,
|
|
133
|
-
"tension_max": 1}, "cooldown_s": 0}]
|
|
134
|
-
picked = voice_bank.pick({"v": 0.1, "tension": 0.2},
|
|
135
|
-
{"stage": "normal"}, [], time.time(),
|
|
136
|
-
entries=bank)
|
|
137
|
-
self.assertTrue(picked)
|
|
138
|
-
|
|
139
|
-
def test_expression_block(self):
|
|
140
|
-
block = extensions.expression_block(
|
|
141
|
-
str(self.store), {"core": {"v": -0.2, "stress": 0.7}},
|
|
142
|
-
{"trust": 0.5, "closeness": 0.4, "stage": "normal"},
|
|
143
|
-
soft_target=12, soft_max=30)
|
|
144
|
-
self.assertTrue(block["rules"] or block["template"])
|
|
145
|
-
self.assertIn("template_name", block)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
class StateTest(Case):
|
|
149
|
-
def test_state_exposes_extensions(self):
|
|
150
|
-
rows = [entry("a", "苹果 很甜"), entry("b", "香蕉")]
|
|
151
|
-
(self.store / "sessions" / "s1" / "memory.json").write_text(
|
|
152
|
-
json.dumps({"entries": rows}), encoding="utf-8")
|
|
153
|
-
pipeline.dispatch("turn_end", {
|
|
154
|
-
"store": str(self.store), "session_id": "s1",
|
|
155
|
-
"user_text": "苹果很甜", "assistant_text": "嗯。",
|
|
156
|
-
"capture": False,
|
|
157
|
-
"persona_profile": str(Path(self.tmp.name) / "missing.json")})
|
|
158
|
-
body = pipeline.dispatch("state", {
|
|
159
|
-
"store": str(self.store), "session_id": "s1",
|
|
160
|
-
"persona_profile": str(Path(self.tmp.name) / "missing.json")})["state"]
|
|
161
|
-
self.assertIn("extensions", body)
|
|
162
|
-
self.assertIn("graph", body["extensions"])
|
|
163
|
-
self.assertIn("layered", body["extensions"])
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if __name__ == "__main__":
|
|
167
|
-
unittest.main()
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""task-225 (5b): P0 memory extensions + expression modules."""
|
|
3
|
+
import json
|
|
4
|
+
import tempfile
|
|
5
|
+
import time
|
|
6
|
+
import unittest
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from biocore_model import (entity_graph, entity_resolve, expr_template,
|
|
10
|
+
graph_extract, graph_recall, layered_memory,
|
|
11
|
+
memory_dual, prompt_rules, prospective,
|
|
12
|
+
reconstruction, template_expr, topic_control,
|
|
13
|
+
turn_memory, voice_bank)
|
|
14
|
+
from biocore_runtime import extensions, pipeline
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def entry(i, text, ts=1700000000.0):
|
|
18
|
+
return {"id": i, "text": text, "role": "user", "ts": ts,
|
|
19
|
+
"importance": 0.5, "hits": 1}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Case(unittest.TestCase):
|
|
23
|
+
def setUp(self):
|
|
24
|
+
self.tmp = tempfile.TemporaryDirectory()
|
|
25
|
+
self.data_dir = Path(self.tmp.name) / "data"
|
|
26
|
+
self.store = self.data_dir / "memory"
|
|
27
|
+
(self.store / "sessions" / "s1").mkdir(parents=True)
|
|
28
|
+
|
|
29
|
+
def tearDown(self):
|
|
30
|
+
self.tmp.cleanup()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class GraphTest(Case):
|
|
34
|
+
def test_entity_graph_build_search(self):
|
|
35
|
+
graph, _ = extensions._entity_graph([
|
|
36
|
+
entry("a", "苹果 很甜"), entry("b", "苹果 咖啡")])
|
|
37
|
+
self.assertGreaterEqual(len(graph.get("entities") or []), 1)
|
|
38
|
+
hits = entity_graph.search(graph, "苹果", limit=4)
|
|
39
|
+
self.assertTrue(hits)
|
|
40
|
+
|
|
41
|
+
def test_entity_resolve(self):
|
|
42
|
+
self.assertEqual(entity_resolve.normalize("苹果 甜"), "苹果甜")
|
|
43
|
+
self.assertGreaterEqual(entity_resolve.similarity("苹果", "苹果"), 0.9)
|
|
44
|
+
|
|
45
|
+
def test_graph_extract(self):
|
|
46
|
+
self.assertEqual(graph_extract.canonical_type("人物"), "person")
|
|
47
|
+
self.assertGreater(graph_extract.when_to_ts("明天", 1000.0), 1000.0)
|
|
48
|
+
|
|
49
|
+
def test_graph_recall_window(self):
|
|
50
|
+
window = graph_recall.detect_window("上周")
|
|
51
|
+
self.assertNotEqual(window, None)
|
|
52
|
+
|
|
53
|
+
def test_graph_hits_extra(self):
|
|
54
|
+
rows = [entry("a", "苹果 很甜"), entry("b", "苹果 咖啡"),
|
|
55
|
+
entry("c", "香蕉")]
|
|
56
|
+
hits, stats = extensions.graph_hits(rows, "苹果")
|
|
57
|
+
self.assertGreaterEqual(stats["hits"], 0)
|
|
58
|
+
self.assertIsInstance(hits, list)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class MemoryExtTest(Case):
|
|
62
|
+
def test_layered_select(self):
|
|
63
|
+
result = layered_memory.select([entry("a", "早上的事"), entry("b", "刚才的事")],
|
|
64
|
+
recalled_ids=["b"])
|
|
65
|
+
self.assertIn("resident", result)
|
|
66
|
+
self.assertIn("retrieval", result)
|
|
67
|
+
self.assertTrue(result["resident"] or result["retrieval"])
|
|
68
|
+
|
|
69
|
+
def test_memory_dual_score(self):
|
|
70
|
+
e = memory_dual.encode("苹果", 1700000000.0, arousal=0.5)
|
|
71
|
+
self.assertGreater(memory_dual.score(e, 1700000100.0), 0)
|
|
72
|
+
self.assertTrue(memory_dual.select([e], 1700000100.0, limit=2))
|
|
73
|
+
|
|
74
|
+
def test_prospective_due(self):
|
|
75
|
+
now = time.time()
|
|
76
|
+
rec = prospective.entry("his_event", "体检", now - 10)
|
|
77
|
+
items, changed = prospective.add([], rec)
|
|
78
|
+
self.assertTrue(changed)
|
|
79
|
+
due = prospective.due_now(items, now, window_s=60)
|
|
80
|
+
self.assertEqual(len(due), 1)
|
|
81
|
+
self.assertTrue(prospective.build_hint(due[0], now))
|
|
82
|
+
self.assertEqual(prospective.stats(items)["by_status"]["pending"], 1)
|
|
83
|
+
|
|
84
|
+
def test_reconstruction(self):
|
|
85
|
+
out = reconstruction.conserve([entry("a", "旧的记忆")])
|
|
86
|
+
self.assertIn("total", out)
|
|
87
|
+
|
|
88
|
+
def test_turn_memory(self):
|
|
89
|
+
rows = turn_memory.build([{"entry_id": "a", "text": "记得喝水",
|
|
90
|
+
"source": "recall"}])
|
|
91
|
+
self.assertEqual(len(rows), 1)
|
|
92
|
+
record = turn_memory.build_record(rows, reply="好", ts=10.0)
|
|
93
|
+
self.assertTrue(turn_memory.render_receipt(record))
|
|
94
|
+
|
|
95
|
+
def test_recall_graph_expansion(self):
|
|
96
|
+
rows = [entry("a", "苹果 很甜", 1700000001.0),
|
|
97
|
+
entry("b", "苹果 咖啡", 1700000002.0),
|
|
98
|
+
entry("c", "香蕉 黄", 1700000003.0)]
|
|
99
|
+
(self.store / "sessions" / "s1" / "memory.json").write_text(
|
|
100
|
+
json.dumps({"entries": rows}), encoding="utf-8")
|
|
101
|
+
out = pipeline.inject_block("s1", str(self.store), query="苹果 咖啡",
|
|
102
|
+
mode="query", top_k=3)
|
|
103
|
+
self.assertGreaterEqual(len(out["ids"]), 2)
|
|
104
|
+
self.assertIn("b", out["ids"])
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ExpressionTest(Case):
|
|
108
|
+
def test_expr_template(self):
|
|
109
|
+
out = expr_template.build_reply({"v": 0.2}, {"trust": 0.5})
|
|
110
|
+
self.assertIsInstance(out, dict)
|
|
111
|
+
|
|
112
|
+
def test_prompt_rules(self):
|
|
113
|
+
text = prompt_rules.render_rules(affect={"valence": -0.4, "stress": 0.7},
|
|
114
|
+
relation={"closeness": 0.5},
|
|
115
|
+
certainty=0.7, soft_target=12,
|
|
116
|
+
soft_max=30)
|
|
117
|
+
self.assertIsInstance(text, str)
|
|
118
|
+
self.assertTrue(text)
|
|
119
|
+
|
|
120
|
+
def test_template_expr(self):
|
|
121
|
+
self.assertEqual(template_expr.render("你好 {{name}}", {"name": "主管"}),
|
|
122
|
+
"你好 主管")
|
|
123
|
+
|
|
124
|
+
def test_topic_control(self):
|
|
125
|
+
result = topic_control.topic_control(turns=[], state={"v": 0.0},
|
|
126
|
+
relationship={"trust": 0.5})
|
|
127
|
+
self.assertIsInstance(result, dict)
|
|
128
|
+
self.assertTrue("tendency" in result or "holder" in result)
|
|
129
|
+
|
|
130
|
+
def test_voice_bank(self):
|
|
131
|
+
bank = [{"id": "v1", "phrase": "嗯。", "weight": 1.0,
|
|
132
|
+
"when": {"v_min": -1, "v_max": 1, "tension_min": 0,
|
|
133
|
+
"tension_max": 1}, "cooldown_s": 0}]
|
|
134
|
+
picked = voice_bank.pick({"v": 0.1, "tension": 0.2},
|
|
135
|
+
{"stage": "normal"}, [], time.time(),
|
|
136
|
+
entries=bank)
|
|
137
|
+
self.assertTrue(picked)
|
|
138
|
+
|
|
139
|
+
def test_expression_block(self):
|
|
140
|
+
block = extensions.expression_block(
|
|
141
|
+
str(self.store), {"core": {"v": -0.2, "stress": 0.7}},
|
|
142
|
+
{"trust": 0.5, "closeness": 0.4, "stage": "normal"},
|
|
143
|
+
soft_target=12, soft_max=30)
|
|
144
|
+
self.assertTrue(block["rules"] or block["template"])
|
|
145
|
+
self.assertIn("template_name", block)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class StateTest(Case):
|
|
149
|
+
def test_state_exposes_extensions(self):
|
|
150
|
+
rows = [entry("a", "苹果 很甜"), entry("b", "香蕉")]
|
|
151
|
+
(self.store / "sessions" / "s1" / "memory.json").write_text(
|
|
152
|
+
json.dumps({"entries": rows}), encoding="utf-8")
|
|
153
|
+
pipeline.dispatch("turn_end", {
|
|
154
|
+
"store": str(self.store), "session_id": "s1",
|
|
155
|
+
"user_text": "苹果很甜", "assistant_text": "嗯。",
|
|
156
|
+
"capture": False,
|
|
157
|
+
"persona_profile": str(Path(self.tmp.name) / "missing.json")})
|
|
158
|
+
body = pipeline.dispatch("state", {
|
|
159
|
+
"store": str(self.store), "session_id": "s1",
|
|
160
|
+
"persona_profile": str(Path(self.tmp.name) / "missing.json")})["state"]
|
|
161
|
+
self.assertIn("extensions", body)
|
|
162
|
+
self.assertIn("graph", body["extensions"])
|
|
163
|
+
self.assertIn("layered", body["extensions"])
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if __name__ == "__main__":
|
|
167
|
+
unittest.main()
|