@geravant/sinain 1.12.0 → 1.13.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 (27) hide show
  1. package/package.json +1 -1
  2. package/sinain-core/package-lock.json +963 -0
  3. package/sinain-core/package.json +1 -0
  4. package/sinain-core/src/buffers/feed-buffer.ts +32 -0
  5. package/sinain-core/src/embedding/service.ts +66 -0
  6. package/sinain-core/src/index.ts +19 -2
  7. package/sinain-core/src/learning/local-curation.ts +137 -7
  8. package/sinain-core/src/server.ts +31 -0
  9. package/sinain-memory/README.md +105 -0
  10. package/sinain-memory/__pycache__/embed_client.cpython-312.pyc +0 -0
  11. package/sinain-memory/__pycache__/graph_query.cpython-312.pyc +0 -0
  12. package/sinain-memory/__pycache__/triplestore.cpython-312.pyc +0 -0
  13. package/sinain-memory/embed_client.py +117 -0
  14. package/sinain-memory/eval/benchmarks/__pycache__/meeting_adapter.cpython-312.pyc +0 -0
  15. package/sinain-memory/eval/benchmarks/__pycache__/meeting_runner.cpython-312.pyc +0 -0
  16. package/sinain-memory/eval/benchmarks/__pycache__/query.cpython-312.pyc +0 -0
  17. package/sinain-memory/eval/benchmarks/__pycache__/runner.cpython-312.pyc +0 -0
  18. package/sinain-memory/eval/benchmarks/meeting_adapter.py +81 -0
  19. package/sinain-memory/eval/benchmarks/meeting_runner.py +230 -0
  20. package/sinain-memory/eval/benchmarks/query.py +37 -16
  21. package/sinain-memory/eval/benchmarks/run_meeting_bench.sh +318 -0
  22. package/sinain-memory/eval/benchmarks/runner.py +10 -3
  23. package/sinain-memory/graph_query.py +257 -15
  24. package/sinain-memory/knowledge_integrator.py +365 -72
  25. package/sinain-memory/memory-config.json +1 -1
  26. package/sinain-memory/session_distiller.py +43 -19
  27. package/sinain-memory/triplestore.py +60 -0
@@ -79,6 +79,40 @@ CREATE INDEX IF NOT EXISTS idx_avet
79
79
  ON triples(attribute, value, entity_id, tx_id);
80
80
  """
81
81
 
82
+ _FTS_SQL = """
83
+ -- Full-text search on fact values (for hybrid retrieval)
84
+ CREATE VIRTUAL TABLE IF NOT EXISTS triples_fts
85
+ USING fts5(entity_id, value, content=triples, content_rowid=id);
86
+
87
+ -- Triggers to keep FTS in sync with triples table
88
+ CREATE TRIGGER IF NOT EXISTS triples_ai AFTER INSERT ON triples BEGIN
89
+ INSERT INTO triples_fts(rowid, entity_id, value) VALUES (new.id, new.entity_id, new.value);
90
+ END;
91
+
92
+ CREATE TRIGGER IF NOT EXISTS triples_ad AFTER DELETE ON triples BEGIN
93
+ INSERT INTO triples_fts(triples_fts, rowid, entity_id, value) VALUES ('delete', old.id, old.entity_id, old.value);
94
+ END;
95
+
96
+ CREATE TRIGGER IF NOT EXISTS triples_au AFTER UPDATE ON triples BEGIN
97
+ INSERT INTO triples_fts(triples_fts, rowid, entity_id, value) VALUES ('delete', old.id, old.entity_id, old.value);
98
+ INSERT INTO triples_fts(rowid, entity_id, value) VALUES (new.id, new.entity_id, new.value);
99
+ END;
100
+ """
101
+
102
+ _TOUCHED_SQL = """
103
+ -- Track which entities are modified per transaction (for fast novelty checks)
104
+ CREATE TABLE IF NOT EXISTS touched_entities (
105
+ tx_id INTEGER NOT NULL,
106
+ entity_id TEXT NOT NULL,
107
+ PRIMARY KEY (tx_id, entity_id)
108
+ );
109
+
110
+ CREATE TRIGGER IF NOT EXISTS track_touched AFTER INSERT ON triples BEGIN
111
+ INSERT OR IGNORE INTO touched_entities (tx_id, entity_id)
112
+ VALUES (new.tx_id, new.entity_id);
113
+ END;
114
+ """
115
+
82
116
 
83
117
  def _now_iso() -> str:
84
118
  return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
@@ -119,6 +153,14 @@ class TripleStore:
119
153
  self._conn.execute("PRAGMA journal_mode=WAL")
120
154
  self._conn.execute("PRAGMA busy_timeout=10000")
121
155
  self._conn.executescript(_SCHEMA_SQL)
156
+ try:
157
+ self._conn.executescript(_FTS_SQL)
158
+ except sqlite3.OperationalError:
159
+ pass # FTS5 not available on this Python build — degrade gracefully
160
+ try:
161
+ self._conn.executescript(_TOUCHED_SQL)
162
+ except sqlite3.OperationalError:
163
+ pass
122
164
  self._migrate()
123
165
  self._conn.commit()
124
166
 
@@ -409,6 +451,24 @@ class TripleStore:
409
451
  ).fetchall()
410
452
  return [dict(r) for r in rows]
411
453
 
454
+ # ----- Touched entities (fast novelty check) -----
455
+
456
+ def was_touched(self, entity_id: str, since_tx: int) -> bool:
457
+ """Check if entity was modified since a given transaction. O(1) via index."""
458
+ row = self._conn.execute(
459
+ "SELECT 1 FROM touched_entities WHERE entity_id = ? AND tx_id > ? LIMIT 1",
460
+ (entity_id, since_tx),
461
+ ).fetchone()
462
+ return row is not None
463
+
464
+ def touched_entities_since(self, since_tx: int) -> list[str]:
465
+ """Return entity_ids modified since a transaction."""
466
+ rows = self._conn.execute(
467
+ "SELECT DISTINCT entity_id FROM touched_entities WHERE tx_id > ?",
468
+ (since_tx,),
469
+ ).fetchall()
470
+ return [r[0] for r in rows]
471
+
412
472
  # ----- Stats -----
413
473
 
414
474
  def stats(self) -> dict: