synapsemem-ai 0.1.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.
- synapsemem_ai-0.1.0/LICENSE +0 -0
- synapsemem_ai-0.1.0/PKG-INFO +36 -0
- synapsemem_ai-0.1.0/README.md +19 -0
- synapsemem_ai-0.1.0/pyproject.toml +26 -0
- synapsemem_ai-0.1.0/setup.cfg +4 -0
- synapsemem_ai-0.1.0/synapsemem/__init__.py +3 -0
- synapsemem_ai-0.1.0/synapsemem/bridge.py +119 -0
- synapsemem_ai-0.1.0/synapsemem/engine.py +140 -0
- synapsemem_ai-0.1.0/synapsemem_ai.egg-info/PKG-INFO +36 -0
- synapsemem_ai-0.1.0/synapsemem_ai.egg-info/SOURCES.txt +11 -0
- synapsemem_ai-0.1.0/synapsemem_ai.egg-info/dependency_links.txt +1 -0
- synapsemem_ai-0.1.0/synapsemem_ai.egg-info/requires.txt +1 -0
- synapsemem_ai-0.1.0/synapsemem_ai.egg-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: synapsemem-ai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A zero-overhead, temporal belief-graph memory engine for local AI agents.
|
|
5
|
+
Author: Rohan Dhar
|
|
6
|
+
Project-URL: Homepage, https://github.com/rohandhar6824/SynapseMem
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/rohandhar6824/SynapseMem/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: ollama>=0.1.0
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# ⚡ SynapseMem
|
|
19
|
+
|
|
20
|
+
[](https://opensource.org/licenses/MIT)
|
|
21
|
+
[](https://www.python.org/downloads/)
|
|
22
|
+
[](#benchmarks)
|
|
23
|
+
|
|
24
|
+
**SynapseMem** is a lightweight, zero-dependency, temporal belief-graph memory engine designed to eliminate **chronological amnesia** and context bloat in small, local language models (SLMs).
|
|
25
|
+
|
|
26
|
+
Traditional Vector RAG dumps conflicting raw chunks into the prompt context, degrading accuracy and slowing down CPU inference. SynapseMem converts interactions into atomic beliefs, deterministically resolves state transitions over time, and injects clean, conflict-free context into edge models.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 🔬 The Problem: Chronological Amnesia in RAG
|
|
31
|
+
|
|
32
|
+
When an autonomous agent runs over days or weeks, states drift:
|
|
33
|
+
* **Monday:** `"The production server is on port 8000."`
|
|
34
|
+
* **Friday:** `"We migrated the server to port 9090."`
|
|
35
|
+
|
|
36
|
+
Standard vector similarity retrieves **both** chunks with equal semantic weight. A 3B parameter model given both inputs often hallucinates stale data.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# ⚡ SynapseMem
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](#benchmarks)
|
|
6
|
+
|
|
7
|
+
**SynapseMem** is a lightweight, zero-dependency, temporal belief-graph memory engine designed to eliminate **chronological amnesia** and context bloat in small, local language models (SLMs).
|
|
8
|
+
|
|
9
|
+
Traditional Vector RAG dumps conflicting raw chunks into the prompt context, degrading accuracy and slowing down CPU inference. SynapseMem converts interactions into atomic beliefs, deterministically resolves state transitions over time, and injects clean, conflict-free context into edge models.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🔬 The Problem: Chronological Amnesia in RAG
|
|
14
|
+
|
|
15
|
+
When an autonomous agent runs over days or weeks, states drift:
|
|
16
|
+
* **Monday:** `"The production server is on port 8000."`
|
|
17
|
+
* **Friday:** `"We migrated the server to port 9090."`
|
|
18
|
+
|
|
19
|
+
Standard vector similarity retrieves **both** chunks with equal semantic weight. A 3B parameter model given both inputs often hallucinates stale data.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "synapsemem-ai"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Rohan Dhar" }
|
|
10
|
+
]
|
|
11
|
+
description = "A zero-overhead, temporal belief-graph memory engine for local AI agents."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"ollama>=0.1.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
"Homepage" = "https://github.com/rohandhar6824/SynapseMem"
|
|
26
|
+
"Bug Tracker" = "https://github.com/rohandhar6824/SynapseMem/issues"
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import ollama
|
|
2
|
+
import json
|
|
3
|
+
import time
|
|
4
|
+
import re
|
|
5
|
+
from synapse_core import SynapseMemoryEngine
|
|
6
|
+
|
|
7
|
+
memory = SynapseMemoryEngine()
|
|
8
|
+
MODEL = "qwen2.5:3b"
|
|
9
|
+
|
|
10
|
+
QUESTION_STARTERS = (
|
|
11
|
+
"what", "when", "where", "which", "who", "whom", "whose",
|
|
12
|
+
"why", "how", "is", "are", "was", "were", "do", "does",
|
|
13
|
+
"did", "can", "could", "should", "would", "tell me"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def is_query_only(text: str) -> bool:
|
|
17
|
+
"""Detects if an input is purely a question to avoid state poisoning."""
|
|
18
|
+
cleaned = text.strip().lower()
|
|
19
|
+
if cleaned.endswith("?"):
|
|
20
|
+
return True
|
|
21
|
+
return any(cleaned.startswith(w + " ") or cleaned == w for w in QUESTION_STARTERS)
|
|
22
|
+
|
|
23
|
+
def extract_triplets(user_text: str) -> list:
|
|
24
|
+
"""Extracts facts only from declarative statements."""
|
|
25
|
+
system_prompt = (
|
|
26
|
+
"Extract new factual declarations from the user text as JSON: {\"facts\": [{\"subject\": ..., \"predicate\": ..., \"object\": ...}]}.\n"
|
|
27
|
+
"RULES:\n"
|
|
28
|
+
"- Only extract facts if the user is making a clear, declarative statement.\n"
|
|
29
|
+
"- If the text is a question, query, or lacks concrete statements, return {\"facts\": []}.\n"
|
|
30
|
+
"- Keep predicates short (e.g., 'uses_port', 'has_status')."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
response = ollama.chat(
|
|
35
|
+
model=MODEL,
|
|
36
|
+
messages=[
|
|
37
|
+
{'role': 'system', 'content': system_prompt},
|
|
38
|
+
{'role': 'user', 'content': user_text}
|
|
39
|
+
],
|
|
40
|
+
format='json'
|
|
41
|
+
)
|
|
42
|
+
data = json.loads(response['message']['content'])
|
|
43
|
+
|
|
44
|
+
if isinstance(data, dict):
|
|
45
|
+
for key in ['facts', 'triplets', 'data', 'items']:
|
|
46
|
+
if key in data and isinstance(data[key], list):
|
|
47
|
+
return data[key]
|
|
48
|
+
if 'subject' in data and 'predicate' in data and 'object' in data:
|
|
49
|
+
return [data]
|
|
50
|
+
return []
|
|
51
|
+
elif isinstance(data, list):
|
|
52
|
+
return data
|
|
53
|
+
return []
|
|
54
|
+
except Exception as e:
|
|
55
|
+
print(f"[Extractor Debug] Parse error: {e}")
|
|
56
|
+
return []
|
|
57
|
+
|
|
58
|
+
def chat_with_memory():
|
|
59
|
+
print(f"SynapseMem Agent Online using {MODEL}. Type 'exit' to quit.\n" + "="*55)
|
|
60
|
+
|
|
61
|
+
while True:
|
|
62
|
+
user_input = input("\nYou: ").strip()
|
|
63
|
+
if not user_input:
|
|
64
|
+
continue
|
|
65
|
+
if user_input.lower() in ['exit', 'quit']:
|
|
66
|
+
break
|
|
67
|
+
|
|
68
|
+
t_now = time.time()
|
|
69
|
+
|
|
70
|
+
# 1. State Mutation Gate: Only extract if it is NOT a read-only query
|
|
71
|
+
if is_query_only(user_input):
|
|
72
|
+
print("[Read-Only Query: Memory ingestion skipped]")
|
|
73
|
+
else:
|
|
74
|
+
triplets = extract_triplets(user_input)
|
|
75
|
+
if triplets:
|
|
76
|
+
print(f"[Extracted {len(triplets)} fact(s)]")
|
|
77
|
+
for t in triplets:
|
|
78
|
+
if isinstance(t, dict) and all(k in t for k in ['subject', 'predicate', 'object']):
|
|
79
|
+
print(" " + memory.ingest_belief(str(t['subject']), str(t['predicate']), str(t['object']), now=t_now))
|
|
80
|
+
else:
|
|
81
|
+
print("[Extracted 0 facts]")
|
|
82
|
+
|
|
83
|
+
# 2. Context Retrieval (Strip punctuation)
|
|
84
|
+
tokens = re.findall(r'\b[a-zA-Z0-9_]+\b', user_input.lower())
|
|
85
|
+
retrieved_segments = []
|
|
86
|
+
for token in tokens:
|
|
87
|
+
if len(token) >= 3:
|
|
88
|
+
ctx = memory.retrieve_active_context(token, now=t_now)
|
|
89
|
+
if "(None)" not in ctx:
|
|
90
|
+
retrieved_segments.append(ctx)
|
|
91
|
+
|
|
92
|
+
injected_context = "\n\n".join(sorted(set(retrieved_segments)))
|
|
93
|
+
|
|
94
|
+
# 3. Prompt Construction
|
|
95
|
+
if injected_context:
|
|
96
|
+
prompt = (
|
|
97
|
+
f"Use this verified system memory to answer the user query.\n\n"
|
|
98
|
+
f"{injected_context}\n\n"
|
|
99
|
+
f"User Question: {user_input}"
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
prompt = user_input
|
|
103
|
+
|
|
104
|
+
print("\n[Thinking with Context...]")
|
|
105
|
+
response = ollama.chat(
|
|
106
|
+
model=MODEL,
|
|
107
|
+
messages=[
|
|
108
|
+
{
|
|
109
|
+
'role': 'system',
|
|
110
|
+
'content': "You are an accurate technical assistant. Rely strictly on the provided verified system memory for factual questions."
|
|
111
|
+
},
|
|
112
|
+
{'role': 'user', 'content': prompt}
|
|
113
|
+
]
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
print(f"\nAgent: {response['message']['content']}")
|
|
117
|
+
|
|
118
|
+
if __name__ == "__main__":
|
|
119
|
+
chat_with_memory()
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import math
|
|
3
|
+
import sqlite3
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Dict, List, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class BeliefNode:
|
|
9
|
+
subject: str
|
|
10
|
+
predicate: str
|
|
11
|
+
obj: str
|
|
12
|
+
created_at: float
|
|
13
|
+
last_accessed: float
|
|
14
|
+
strength: float = 1.0
|
|
15
|
+
is_active: bool = True
|
|
16
|
+
superseded_by: Optional[str] = None
|
|
17
|
+
|
|
18
|
+
def retention_score(self, current_time: float, decay_rate: float = 0.05) -> float:
|
|
19
|
+
if not self.is_active:
|
|
20
|
+
return 0.0
|
|
21
|
+
elapsed_hours = max(0.0, (current_time - self.last_accessed) / 3600.0)
|
|
22
|
+
effective_stability = self.strength / decay_rate
|
|
23
|
+
return math.exp(-elapsed_hours / effective_stability)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SynapseMemoryEngine:
|
|
27
|
+
def __init__(self, db_path: str = "synapse_memory.db", plural_predicates: Optional[set] = None):
|
|
28
|
+
self.db_path = db_path
|
|
29
|
+
self.plural_predicates = plural_predicates or {
|
|
30
|
+
"has_tag", "contains", "includes", "depends_on", "has_member", "features"
|
|
31
|
+
}
|
|
32
|
+
self._init_db()
|
|
33
|
+
|
|
34
|
+
def _init_db(self):
|
|
35
|
+
"""Initializes the persistent SQLite schema."""
|
|
36
|
+
with sqlite3.connect(self.db_path) as conn:
|
|
37
|
+
cursor = conn.cursor()
|
|
38
|
+
cursor.execute("""
|
|
39
|
+
CREATE TABLE IF NOT EXISTS beliefs (
|
|
40
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
41
|
+
subject TEXT NOT NULL,
|
|
42
|
+
predicate TEXT NOT NULL,
|
|
43
|
+
object TEXT NOT NULL,
|
|
44
|
+
created_at REAL NOT NULL,
|
|
45
|
+
last_accessed REAL NOT NULL,
|
|
46
|
+
strength REAL NOT NULL,
|
|
47
|
+
is_active INTEGER NOT NULL,
|
|
48
|
+
superseded_by TEXT
|
|
49
|
+
)
|
|
50
|
+
""")
|
|
51
|
+
cursor.execute("CREATE INDEX IF NOT EXISTS idx_subj_pred ON beliefs(subject, predicate)")
|
|
52
|
+
conn.commit()
|
|
53
|
+
|
|
54
|
+
def _is_singular(self, predicate: str) -> bool:
|
|
55
|
+
if predicate in self.plural_predicates:
|
|
56
|
+
return False
|
|
57
|
+
state_prefixes = ("is", "has_", "uses_", "deployed_", "current_", "set_")
|
|
58
|
+
return predicate.startswith(state_prefixes) or predicate.endswith(("_status", "_port", "_id"))
|
|
59
|
+
|
|
60
|
+
def ingest_belief(self, subject: str, predicate: str, obj: str, now: Optional[float] = None) -> str:
|
|
61
|
+
now = now or time.time()
|
|
62
|
+
subj_norm = subject.strip().lower()
|
|
63
|
+
pred_norm = predicate.strip().lower()
|
|
64
|
+
obj_norm = obj.strip()
|
|
65
|
+
is_singular = self._is_singular(pred_norm)
|
|
66
|
+
|
|
67
|
+
with sqlite3.connect(self.db_path) as conn:
|
|
68
|
+
cursor = conn.cursor()
|
|
69
|
+
|
|
70
|
+
# Check for existing active beliefs
|
|
71
|
+
cursor.execute("""
|
|
72
|
+
SELECT id, object, strength FROM beliefs
|
|
73
|
+
WHERE subject = ? AND predicate = ? AND is_active = 1
|
|
74
|
+
""", (subj_norm, pred_norm))
|
|
75
|
+
active_rows = cursor.fetchall()
|
|
76
|
+
|
|
77
|
+
for row_id, existing_obj, strength in active_rows:
|
|
78
|
+
# Reinforce exact match
|
|
79
|
+
if existing_obj.lower() == obj_norm.lower():
|
|
80
|
+
new_strength = strength + 1.0
|
|
81
|
+
cursor.execute("""
|
|
82
|
+
UPDATE beliefs SET last_accessed = ?, strength = ? WHERE id = ?
|
|
83
|
+
""", (now, new_strength, row_id))
|
|
84
|
+
conn.commit()
|
|
85
|
+
return f"[REINFORCED] ({subj_norm}, {pred_norm}, {existing_obj}) | Strength: {new_strength:.1f}"
|
|
86
|
+
|
|
87
|
+
# Supersede old value if singular
|
|
88
|
+
elif is_singular:
|
|
89
|
+
cursor.execute("""
|
|
90
|
+
UPDATE beliefs SET is_active = 0, superseded_by = ? WHERE id = ?
|
|
91
|
+
""", (obj_norm, row_id))
|
|
92
|
+
|
|
93
|
+
# Insert new active belief
|
|
94
|
+
cursor.execute("""
|
|
95
|
+
INSERT INTO beliefs (subject, predicate, object, created_at, last_accessed, strength, is_active, superseded_by)
|
|
96
|
+
VALUES (?, ?, ?, ?, ?, 1.0, 1, NULL)
|
|
97
|
+
""", (subj_norm, pred_norm, obj_norm, now, now))
|
|
98
|
+
conn.commit()
|
|
99
|
+
return f"[COMMITTED] ({subj_norm}, {pred_norm}, {obj_norm})"
|
|
100
|
+
|
|
101
|
+
def retrieve_active_context(self, entity_query: str, min_retention: float = 0.2, now: Optional[float] = None) -> str:
|
|
102
|
+
now = now or time.time()
|
|
103
|
+
query_norm = entity_query.strip().lower()
|
|
104
|
+
active_facts = []
|
|
105
|
+
historical_shifts = []
|
|
106
|
+
|
|
107
|
+
with sqlite3.connect(self.db_path) as conn:
|
|
108
|
+
cursor = conn.cursor()
|
|
109
|
+
# Find any records touching this entity
|
|
110
|
+
cursor.execute("""
|
|
111
|
+
SELECT id, subject, predicate, object, created_at, last_accessed, strength, is_active, superseded_by
|
|
112
|
+
FROM beliefs
|
|
113
|
+
WHERE subject LIKE ? OR object LIKE ?
|
|
114
|
+
""", (f"%{query_norm}%", f"%{query_norm}%"))
|
|
115
|
+
rows = cursor.fetchall()
|
|
116
|
+
|
|
117
|
+
for row in rows:
|
|
118
|
+
r_id, subj, pred, obj_val, c_at, l_acc, strength, is_active, superseded = row
|
|
119
|
+
node = BeliefNode(subj, pred, obj_val, c_at, l_acc, strength, bool(is_active), superseded)
|
|
120
|
+
|
|
121
|
+
if node.is_active:
|
|
122
|
+
score = node.retention_score(now)
|
|
123
|
+
if score >= min_retention:
|
|
124
|
+
# Touch access time in DB
|
|
125
|
+
cursor.execute("UPDATE beliefs SET last_accessed = ? WHERE id = ?", (now, r_id))
|
|
126
|
+
active_facts.append(f"- {subj} {pred} {obj_val}")
|
|
127
|
+
elif node.superseded_by:
|
|
128
|
+
historical_shifts.append(f"- [PAST] {subj} {pred} was '{obj_val}' (now '{node.superseded_by}')")
|
|
129
|
+
conn.commit()
|
|
130
|
+
|
|
131
|
+
context_lines = ["### VERIFIED ACTIVE MEMORY:"] + (active_facts or ["(None)"])
|
|
132
|
+
if historical_shifts:
|
|
133
|
+
context_lines += ["\n### RESOLVED STATE CHANGES (DO NOT USE OLD VALUES):"] + historical_shifts[-4:]
|
|
134
|
+
return "\n".join(context_lines)
|
|
135
|
+
|
|
136
|
+
def reset_memory(self):
|
|
137
|
+
"""Utility to wipe database for clean benchmarking."""
|
|
138
|
+
with sqlite3.connect(self.db_path) as conn:
|
|
139
|
+
conn.cursor().execute("DROP TABLE IF EXISTS beliefs")
|
|
140
|
+
self._init_db()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: synapsemem-ai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A zero-overhead, temporal belief-graph memory engine for local AI agents.
|
|
5
|
+
Author: Rohan Dhar
|
|
6
|
+
Project-URL: Homepage, https://github.com/rohandhar6824/SynapseMem
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/rohandhar6824/SynapseMem/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: ollama>=0.1.0
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# ⚡ SynapseMem
|
|
19
|
+
|
|
20
|
+
[](https://opensource.org/licenses/MIT)
|
|
21
|
+
[](https://www.python.org/downloads/)
|
|
22
|
+
[](#benchmarks)
|
|
23
|
+
|
|
24
|
+
**SynapseMem** is a lightweight, zero-dependency, temporal belief-graph memory engine designed to eliminate **chronological amnesia** and context bloat in small, local language models (SLMs).
|
|
25
|
+
|
|
26
|
+
Traditional Vector RAG dumps conflicting raw chunks into the prompt context, degrading accuracy and slowing down CPU inference. SynapseMem converts interactions into atomic beliefs, deterministically resolves state transitions over time, and injects clean, conflict-free context into edge models.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 🔬 The Problem: Chronological Amnesia in RAG
|
|
31
|
+
|
|
32
|
+
When an autonomous agent runs over days or weeks, states drift:
|
|
33
|
+
* **Monday:** `"The production server is on port 8000."`
|
|
34
|
+
* **Friday:** `"We migrated the server to port 9090."`
|
|
35
|
+
|
|
36
|
+
Standard vector similarity retrieves **both** chunks with equal semantic weight. A 3B parameter model given both inputs often hallucinates stale data.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
synapsemem/__init__.py
|
|
5
|
+
synapsemem/bridge.py
|
|
6
|
+
synapsemem/engine.py
|
|
7
|
+
synapsemem_ai.egg-info/PKG-INFO
|
|
8
|
+
synapsemem_ai.egg-info/SOURCES.txt
|
|
9
|
+
synapsemem_ai.egg-info/dependency_links.txt
|
|
10
|
+
synapsemem_ai.egg-info/requires.txt
|
|
11
|
+
synapsemem_ai.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ollama>=0.1.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
synapsemem
|