@geravant/sinain 1.13.0 → 1.15.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.
Files changed (78) hide show
  1. package/.env.example +33 -27
  2. package/cli.js +30 -14
  3. package/config-shared.js +173 -30
  4. package/launcher.js +38 -21
  5. package/onboard.js +36 -20
  6. package/package.json +4 -1
  7. package/sinain-agent/run.sh +600 -127
  8. package/sinain-core/src/agents-loader.ts +254 -0
  9. package/sinain-core/src/buffers/feed-buffer.ts +6 -4
  10. package/sinain-core/src/config.ts +77 -15
  11. package/sinain-core/src/escalation/escalator.ts +178 -18
  12. package/sinain-core/src/index.ts +218 -31
  13. package/sinain-core/src/learning/local-curation.ts +81 -27
  14. package/sinain-core/src/overlay/commands.ts +25 -0
  15. package/sinain-core/src/overlay/ws-handler.ts +3 -0
  16. package/sinain-core/src/server.ts +101 -10
  17. package/sinain-core/src/types.ts +29 -3
  18. package/sinain-memory/graph_query.py +12 -3
  19. package/sinain-memory/knowledge_integrator.py +194 -10
  20. package/sinain-memory/__pycache__/common.cpython-312.pyc +0 -0
  21. package/sinain-memory/__pycache__/embed_client.cpython-312.pyc +0 -0
  22. package/sinain-memory/__pycache__/graph_query.cpython-312.pyc +0 -0
  23. package/sinain-memory/__pycache__/knowledge_integrator.cpython-312.pyc +0 -0
  24. package/sinain-memory/__pycache__/session_distiller.cpython-312.pyc +0 -0
  25. package/sinain-memory/__pycache__/triplestore.cpython-312.pyc +0 -0
  26. package/sinain-memory/eval/__init__.py +0 -0
  27. package/sinain-memory/eval/__pycache__/__init__.cpython-312.pyc +0 -0
  28. package/sinain-memory/eval/assertions.py +0 -267
  29. package/sinain-memory/eval/benchmarks/__init__.py +0 -0
  30. package/sinain-memory/eval/benchmarks/__pycache__/__init__.cpython-312.pyc +0 -0
  31. package/sinain-memory/eval/benchmarks/__pycache__/base_adapter.cpython-312.pyc +0 -0
  32. package/sinain-memory/eval/benchmarks/__pycache__/config.cpython-312.pyc +0 -0
  33. package/sinain-memory/eval/benchmarks/__pycache__/evaluate.cpython-312.pyc +0 -0
  34. package/sinain-memory/eval/benchmarks/__pycache__/ingest.cpython-312.pyc +0 -0
  35. package/sinain-memory/eval/benchmarks/__pycache__/longmemeval_adapter.cpython-312.pyc +0 -0
  36. package/sinain-memory/eval/benchmarks/__pycache__/meeting_adapter.cpython-312.pyc +0 -0
  37. package/sinain-memory/eval/benchmarks/__pycache__/meeting_runner.cpython-312.pyc +0 -0
  38. package/sinain-memory/eval/benchmarks/__pycache__/query.cpython-312.pyc +0 -0
  39. package/sinain-memory/eval/benchmarks/__pycache__/report.cpython-312.pyc +0 -0
  40. package/sinain-memory/eval/benchmarks/__pycache__/runner.cpython-312.pyc +0 -0
  41. package/sinain-memory/eval/benchmarks/base_adapter.py +0 -43
  42. package/sinain-memory/eval/benchmarks/config.py +0 -23
  43. package/sinain-memory/eval/benchmarks/evaluate.py +0 -146
  44. package/sinain-memory/eval/benchmarks/ingest.py +0 -152
  45. package/sinain-memory/eval/benchmarks/judges/__init__.py +0 -0
  46. package/sinain-memory/eval/benchmarks/judges/__pycache__/__init__.cpython-312.pyc +0 -0
  47. package/sinain-memory/eval/benchmarks/judges/__pycache__/qa_judge.cpython-312.pyc +0 -0
  48. package/sinain-memory/eval/benchmarks/judges/qa_judge.py +0 -81
  49. package/sinain-memory/eval/benchmarks/longmemeval_adapter.py +0 -177
  50. package/sinain-memory/eval/benchmarks/meeting_adapter.py +0 -81
  51. package/sinain-memory/eval/benchmarks/meeting_runner.py +0 -230
  52. package/sinain-memory/eval/benchmarks/query.py +0 -193
  53. package/sinain-memory/eval/benchmarks/report.py +0 -87
  54. package/sinain-memory/eval/benchmarks/run_meeting_bench.sh +0 -318
  55. package/sinain-memory/eval/benchmarks/runner.py +0 -283
  56. package/sinain-memory/eval/judges/__init__.py +0 -0
  57. package/sinain-memory/eval/judges/base_judge.py +0 -61
  58. package/sinain-memory/eval/judges/curation_judge.py +0 -46
  59. package/sinain-memory/eval/judges/insight_judge.py +0 -48
  60. package/sinain-memory/eval/judges/mining_judge.py +0 -42
  61. package/sinain-memory/eval/judges/signal_judge.py +0 -45
  62. package/sinain-memory/eval/retrieval_benchmark.jsonl +0 -12
  63. package/sinain-memory/eval/retrieval_evaluator.py +0 -186
  64. package/sinain-memory/eval/schemas.py +0 -247
  65. package/sinain-memory/tests/__init__.py +0 -0
  66. package/sinain-memory/tests/conftest.py +0 -189
  67. package/sinain-memory/tests/test_curator_helpers.py +0 -94
  68. package/sinain-memory/tests/test_embedder.py +0 -210
  69. package/sinain-memory/tests/test_extract_json.py +0 -124
  70. package/sinain-memory/tests/test_feedback_computation.py +0 -121
  71. package/sinain-memory/tests/test_miner_helpers.py +0 -71
  72. package/sinain-memory/tests/test_module_management.py +0 -458
  73. package/sinain-memory/tests/test_parsers.py +0 -96
  74. package/sinain-memory/tests/test_tick_evaluator.py +0 -430
  75. package/sinain-memory/tests/test_triple_extractor.py +0 -255
  76. package/sinain-memory/tests/test_triple_ingest.py +0 -191
  77. package/sinain-memory/tests/test_triple_migrate.py +0 -138
  78. package/sinain-memory/tests/test_triplestore.py +0 -248
@@ -1,248 +0,0 @@
1
- """Tests for triplestore.py — EAV triple store."""
2
-
3
- import os
4
- import pytest
5
- from triplestore import TripleStore
6
-
7
-
8
- @pytest.fixture
9
- def store(tmp_path):
10
- """Create a fresh triple store in a temp directory."""
11
- db_path = tmp_path / "test.db"
12
- s = TripleStore(str(db_path))
13
- yield s
14
- s.close()
15
-
16
-
17
- @pytest.fixture
18
- def populated_store(store):
19
- """Store with sample data across two transactions."""
20
- tx1 = store.begin_tx("test", session_key="sess-1")
21
- store.assert_triple(tx1, "signal:2026-03-01T10:00", "description", "OCR stall")
22
- store.assert_triple(tx1, "signal:2026-03-01T10:00", "priority", "high")
23
- store.assert_triple(tx1, "signal:2026-03-01T10:00", "related_to", "concept:ocr", "ref")
24
- store.assert_triple(tx1, "concept:ocr", "name", "OCR")
25
- store.assert_triple(tx1, "pattern:frame-batch", "text", "Frame batching improves OCR")
26
- store.assert_triple(tx1, "pattern:frame-batch", "related_to", "concept:ocr", "ref")
27
- store.assert_triple(tx1, "session:2026-03-01T09:00", "summary", "Debugging OCR pipeline")
28
- store.assert_triple(tx1, "session:2026-03-01T09:00", "related_to", "concept:ocr", "ref")
29
- store._tx1 = tx1 # stash for tests
30
- return store
31
-
32
-
33
- class TestTransactions:
34
- def test_begin_tx_returns_positive_id(self, store):
35
- tx = store.begin_tx("test")
36
- assert tx > 0
37
-
38
- def test_latest_tx_empty_store(self, tmp_path):
39
- s = TripleStore(str(tmp_path / "empty.db"))
40
- assert s.latest_tx() == 0
41
- s.close()
42
-
43
- def test_latest_tx_after_writes(self, store):
44
- tx1 = store.begin_tx("a")
45
- tx2 = store.begin_tx("b")
46
- assert store.latest_tx() == tx2
47
- assert tx2 > tx1
48
-
49
- def test_tx_metadata(self, store):
50
- tx = store.begin_tx("test", metadata={"foo": "bar"})
51
- row = store._conn.execute(
52
- "SELECT metadata FROM transactions WHERE tx_id = ?", (tx,)
53
- ).fetchone()
54
- import json
55
- assert json.loads(row["metadata"]) == {"foo": "bar"}
56
-
57
- def test_tx_parent(self, store):
58
- tx1 = store.begin_tx("parent")
59
- tx2 = store.begin_tx("child", parent_tx=tx1)
60
- row = store._conn.execute(
61
- "SELECT parent_tx FROM transactions WHERE tx_id = ?", (tx2,)
62
- ).fetchone()
63
- assert row["parent_tx"] == tx1
64
-
65
-
66
- class TestAssertAndEntity:
67
- def test_assert_returns_id(self, store):
68
- tx = store.begin_tx("test")
69
- tid = store.assert_triple(tx, "e:1", "name", "Test")
70
- assert tid > 0
71
-
72
- def test_entity_returns_all_attrs(self, populated_store):
73
- ent = populated_store.entity("signal:2026-03-01T10:00")
74
- assert ent["description"] == ["OCR stall"]
75
- assert ent["priority"] == ["high"]
76
- assert ent["related_to"] == ["concept:ocr"]
77
-
78
- def test_entity_missing_returns_empty(self, store):
79
- assert store.entity("nonexistent:1") == {}
80
-
81
- def test_multiple_values_per_attr(self, store):
82
- tx = store.begin_tx("test")
83
- store.assert_triple(tx, "e:1", "tag", "alpha")
84
- store.assert_triple(tx, "e:1", "tag", "beta")
85
- ent = store.entity("e:1")
86
- assert set(ent["tag"]) == {"alpha", "beta"}
87
-
88
- def test_entity_type_auto_populated(self, store):
89
- tx = store.begin_tx("test")
90
- store.assert_triple(tx, "signal:abc", "x", "y")
91
- row = store._conn.execute(
92
- "SELECT entity_type FROM entity_types WHERE entity_id = ?",
93
- ("signal:abc",),
94
- ).fetchone()
95
- assert row["entity_type"] == "signal"
96
-
97
-
98
- class TestRetraction:
99
- def test_retract_by_attr(self, populated_store):
100
- tx2 = populated_store.begin_tx("retract")
101
- count = populated_store.retract_triple(tx2, "signal:2026-03-01T10:00", "priority")
102
- assert count == 1
103
- ent = populated_store.entity("signal:2026-03-01T10:00")
104
- assert "priority" not in ent
105
-
106
- def test_retract_by_attr_and_value(self, store):
107
- tx = store.begin_tx("test")
108
- store.assert_triple(tx, "e:1", "tag", "a")
109
- store.assert_triple(tx, "e:1", "tag", "b")
110
- tx2 = store.begin_tx("retract")
111
- count = store.retract_triple(tx2, "e:1", "tag", "a")
112
- assert count == 1
113
- ent = store.entity("e:1")
114
- assert ent["tag"] == ["b"]
115
-
116
- def test_retract_nonexistent_returns_zero(self, store):
117
- tx = store.begin_tx("test")
118
- count = store.retract_triple(tx, "e:nope", "attr")
119
- assert count == 0
120
-
121
-
122
- class TestEAVTAsOfTx:
123
- def test_as_of_tx_sees_old_state(self, populated_store):
124
- tx1 = populated_store._tx1
125
- tx2 = populated_store.begin_tx("change")
126
- populated_store.retract_triple(tx2, "signal:2026-03-01T10:00", "priority")
127
-
128
- # Current state: no priority
129
- assert "priority" not in populated_store.entity("signal:2026-03-01T10:00")
130
- # as_of tx1: has priority
131
- assert "priority" in populated_store.entity("signal:2026-03-01T10:00", as_of_tx=tx1)
132
-
133
-
134
- class TestAEVT:
135
- def test_entities_with_attr(self, populated_store):
136
- results = populated_store.entities_with_attr("name")
137
- assert ("concept:ocr", "OCR") in results
138
-
139
- def test_entities_with_attr_multiple(self, populated_store):
140
- results = populated_store.entities_with_attr("related_to")
141
- eids = [r[0] for r in results]
142
- assert "signal:2026-03-01T10:00" in eids
143
- assert "pattern:frame-batch" in eids
144
-
145
-
146
- class TestVAET:
147
- def test_backrefs(self, populated_store):
148
- refs = populated_store.backrefs("concept:ocr")
149
- eids = [r[0] for r in refs]
150
- assert "signal:2026-03-01T10:00" in eids
151
- assert "pattern:frame-batch" in eids
152
- assert "session:2026-03-01T09:00" in eids
153
-
154
- def test_backrefs_with_attribute_filter(self, populated_store):
155
- refs = populated_store.backrefs("concept:ocr", attribute="related_to")
156
- eids = [r[0] for r in refs]
157
- assert "signal:2026-03-01T10:00" in eids
158
-
159
- def test_backrefs_no_results(self, store):
160
- assert store.backrefs("nonexistent:1") == []
161
-
162
-
163
- class TestAVET:
164
- def test_lookup(self, populated_store):
165
- found = populated_store.lookup("name", "OCR")
166
- assert "concept:ocr" in found
167
-
168
- def test_lookup_no_match(self, populated_store):
169
- found = populated_store.lookup("name", "nonexistent")
170
- assert found == []
171
-
172
-
173
- class TestNeighbors:
174
- def test_neighbors_depth_1(self, populated_store):
175
- nbrs = populated_store.neighbors("concept:ocr", depth=1)
176
- assert "concept:ocr" in nbrs
177
- # Should find signal, pattern, and session via backrefs
178
- found_eids = set(nbrs.keys())
179
- assert "signal:2026-03-01T10:00" in found_eids or "pattern:frame-batch" in found_eids
180
-
181
- def test_neighbors_depth_0(self, populated_store):
182
- nbrs = populated_store.neighbors("concept:ocr", depth=0)
183
- assert "concept:ocr" in nbrs
184
- assert len(nbrs) == 1 # only the entity itself
185
-
186
-
187
- class TestNovelty:
188
- def test_novelty_after_tx(self, populated_store):
189
- tx1 = populated_store._tx1
190
- tx2 = populated_store.begin_tx("new")
191
- populated_store.assert_triple(tx2, "concept:new", "name", "New Concept")
192
- changes = populated_store.novelty(tx1)
193
- assert len(changes) >= 1
194
- assert any(c["entity_id"] == "concept:new" for c in changes)
195
-
196
- def test_novelty_bounded(self, populated_store):
197
- tx1 = populated_store._tx1
198
- tx2 = populated_store.begin_tx("a")
199
- populated_store.assert_triple(tx2, "concept:a", "name", "A")
200
- tx3 = populated_store.begin_tx("b")
201
- populated_store.assert_triple(tx3, "concept:b", "name", "B")
202
- # Only changes between tx1 and tx2
203
- changes = populated_store.novelty(tx1, until_tx=tx2)
204
- eids = [c["entity_id"] for c in changes]
205
- assert "concept:a" in eids
206
- assert "concept:b" not in eids
207
-
208
- def test_novelty_empty(self, store):
209
- tx = store.begin_tx("test")
210
- assert store.novelty(tx) == []
211
-
212
-
213
- class TestGC:
214
- def test_gc_deletes_old_retracted(self, store):
215
- tx = store.begin_tx("test")
216
- store.assert_triple(tx, "e:1", "x", "y")
217
- tx2 = store.begin_tx("retract")
218
- store.retract_triple(tx2, "e:1", "x")
219
- # GC with 0 days should delete it
220
- count = store.gc(older_than_days=0)
221
- assert count >= 1
222
-
223
- def test_gc_preserves_active(self, store):
224
- tx = store.begin_tx("test")
225
- store.assert_triple(tx, "e:1", "x", "y")
226
- count = store.gc(older_than_days=0)
227
- assert count == 0 # not retracted, shouldn't be deleted
228
-
229
-
230
- class TestStats:
231
- def test_stats_populated(self, populated_store):
232
- s = populated_store.stats()
233
- assert s["triples"] >= 8
234
- assert s["entities"] >= 4
235
- assert s["transactions"] >= 1
236
- assert s["db_size_bytes"] > 0
237
-
238
- def test_stats_empty(self, store):
239
- s = store.stats()
240
- assert s["triples"] == 0
241
- assert s["entities"] == 0
242
- assert s["transactions"] == 0
243
-
244
-
245
- class TestWALMode:
246
- def test_wal_mode_enabled(self, store):
247
- mode = store._conn.execute("PRAGMA journal_mode").fetchone()[0]
248
- assert mode == "wal"