superlocalmemory 3.4.1 → 3.4.3
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/package.json +1 -1
- package/pyproject.toml +11 -2
- package/scripts/postinstall.js +26 -7
- package/src/superlocalmemory/cli/commands.py +42 -60
- package/src/superlocalmemory/cli/daemon.py +107 -47
- package/src/superlocalmemory/cli/main.py +10 -0
- package/src/superlocalmemory/cli/setup_wizard.py +137 -9
- package/src/superlocalmemory/core/config.py +28 -0
- package/src/superlocalmemory/core/consolidation_engine.py +38 -1
- package/src/superlocalmemory/core/engine.py +9 -0
- package/src/superlocalmemory/core/health_monitor.py +313 -0
- package/src/superlocalmemory/core/reranker_worker.py +19 -5
- package/src/superlocalmemory/ingestion/__init__.py +13 -0
- package/src/superlocalmemory/ingestion/adapter_manager.py +234 -0
- package/src/superlocalmemory/ingestion/base_adapter.py +177 -0
- package/src/superlocalmemory/ingestion/calendar_adapter.py +340 -0
- package/src/superlocalmemory/ingestion/credentials.py +118 -0
- package/src/superlocalmemory/ingestion/gmail_adapter.py +369 -0
- package/src/superlocalmemory/ingestion/parsers.py +100 -0
- package/src/superlocalmemory/ingestion/transcript_adapter.py +156 -0
- package/src/superlocalmemory/learning/consolidation_worker.py +47 -1
- package/src/superlocalmemory/learning/entity_compiler.py +377 -0
- package/src/superlocalmemory/mesh/__init__.py +12 -0
- package/src/superlocalmemory/mesh/broker.py +344 -0
- package/src/superlocalmemory/retrieval/entity_channel.py +12 -6
- package/src/superlocalmemory/server/api.py +6 -7
- package/src/superlocalmemory/server/routes/entity.py +95 -0
- package/src/superlocalmemory/server/routes/ingest.py +110 -0
- package/src/superlocalmemory/server/routes/mesh.py +186 -0
- package/src/superlocalmemory/server/unified_daemon.py +691 -0
- package/src/superlocalmemory/storage/schema_v343.py +229 -0
- package/src/superlocalmemory.egg-info/PKG-INFO +0 -597
- package/src/superlocalmemory.egg-info/SOURCES.txt +0 -287
- package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
- package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
- package/src/superlocalmemory.egg-info/requires.txt +0 -47
- package/src/superlocalmemory.egg-info/top_level.txt +0 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under the Elastic License 2.0 - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
|
|
5
|
+
"""SLM Mesh — FastAPI routes for P2P agent communication.
|
|
6
|
+
|
|
7
|
+
Mounted at /mesh/* in the unified daemon. Uses MeshBroker for all operations.
|
|
8
|
+
|
|
9
|
+
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
from fastapi import APIRouter, HTTPException, Request
|
|
17
|
+
from pydantic import BaseModel
|
|
18
|
+
|
|
19
|
+
router = APIRouter(prefix="/mesh", tags=["mesh"])
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# -- Request models --
|
|
23
|
+
|
|
24
|
+
class RegisterRequest(BaseModel):
|
|
25
|
+
session_id: str
|
|
26
|
+
summary: str = ""
|
|
27
|
+
host: str = "127.0.0.1"
|
|
28
|
+
port: int = 0
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DeregisterRequest(BaseModel):
|
|
32
|
+
peer_id: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class HeartbeatRequest(BaseModel):
|
|
36
|
+
peer_id: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SummaryRequest(BaseModel):
|
|
40
|
+
peer_id: str
|
|
41
|
+
summary: str
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SendRequest(BaseModel):
|
|
45
|
+
from_peer: str = ""
|
|
46
|
+
to: str
|
|
47
|
+
content: str
|
|
48
|
+
type: str = "text"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ReadRequest(BaseModel):
|
|
52
|
+
message_ids: list[int]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class StateSetRequest(BaseModel):
|
|
56
|
+
key: str
|
|
57
|
+
value: str
|
|
58
|
+
set_by: str
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class LockRequest(BaseModel):
|
|
62
|
+
file_path: str
|
|
63
|
+
locked_by: str
|
|
64
|
+
action: str # acquire, release, query
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# -- Helpers --
|
|
68
|
+
|
|
69
|
+
def _get_broker(request: Request):
|
|
70
|
+
broker = getattr(request.app.state, 'mesh_broker', None)
|
|
71
|
+
if broker is None:
|
|
72
|
+
raise HTTPException(503, detail="Mesh broker not initialized")
|
|
73
|
+
# Check if mesh is enabled
|
|
74
|
+
config = getattr(request.app.state, 'config', None)
|
|
75
|
+
if config and not getattr(config, 'mesh_enabled', True):
|
|
76
|
+
raise HTTPException(503, detail="Mesh disabled in config")
|
|
77
|
+
return broker
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# -- Routes --
|
|
81
|
+
|
|
82
|
+
@router.post("/register")
|
|
83
|
+
async def register(req: RegisterRequest, request: Request):
|
|
84
|
+
broker = _get_broker(request)
|
|
85
|
+
if not req.session_id:
|
|
86
|
+
raise HTTPException(400, detail="session_id required")
|
|
87
|
+
return broker.register_peer(req.session_id, req.summary, req.host, req.port)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@router.post("/deregister")
|
|
91
|
+
async def deregister(req: DeregisterRequest, request: Request):
|
|
92
|
+
broker = _get_broker(request)
|
|
93
|
+
result = broker.deregister_peer(req.peer_id)
|
|
94
|
+
if not result.get("ok"):
|
|
95
|
+
raise HTTPException(404, detail=result.get("error", "peer not found"))
|
|
96
|
+
return result
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@router.get("/peers")
|
|
100
|
+
async def peers(request: Request):
|
|
101
|
+
broker = _get_broker(request)
|
|
102
|
+
return {"peers": broker.list_peers()}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@router.post("/heartbeat")
|
|
106
|
+
async def heartbeat(req: HeartbeatRequest, request: Request):
|
|
107
|
+
broker = _get_broker(request)
|
|
108
|
+
result = broker.heartbeat(req.peer_id)
|
|
109
|
+
if not result.get("ok"):
|
|
110
|
+
raise HTTPException(404, detail=result.get("error", "peer not found"))
|
|
111
|
+
return result
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@router.post("/summary")
|
|
115
|
+
async def summary(req: SummaryRequest, request: Request):
|
|
116
|
+
broker = _get_broker(request)
|
|
117
|
+
result = broker.update_summary(req.peer_id, req.summary)
|
|
118
|
+
if not result.get("ok"):
|
|
119
|
+
raise HTTPException(404, detail=result.get("error", "peer not found"))
|
|
120
|
+
return result
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@router.post("/send")
|
|
124
|
+
async def send(req: SendRequest, request: Request):
|
|
125
|
+
broker = _get_broker(request)
|
|
126
|
+
result = broker.send_message(req.from_peer, req.to, req.content, req.type)
|
|
127
|
+
if not result.get("ok"):
|
|
128
|
+
raise HTTPException(404, detail=result.get("error", ""))
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@router.get("/inbox/{peer_id}")
|
|
133
|
+
async def inbox(peer_id: str, request: Request):
|
|
134
|
+
broker = _get_broker(request)
|
|
135
|
+
return {"messages": broker.get_inbox(peer_id)}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@router.post("/inbox/{peer_id}/read")
|
|
139
|
+
async def mark_read(peer_id: str, req: ReadRequest, request: Request):
|
|
140
|
+
broker = _get_broker(request)
|
|
141
|
+
return broker.mark_read(peer_id, req.message_ids)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@router.get("/state")
|
|
145
|
+
async def state_all(request: Request):
|
|
146
|
+
broker = _get_broker(request)
|
|
147
|
+
return {"state": broker.get_state()}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@router.post("/state")
|
|
151
|
+
async def state_set(req: StateSetRequest, request: Request):
|
|
152
|
+
broker = _get_broker(request)
|
|
153
|
+
if not req.key:
|
|
154
|
+
raise HTTPException(400, detail="key required")
|
|
155
|
+
return broker.set_state(req.key, req.value, req.set_by)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@router.get("/state/{key}")
|
|
159
|
+
async def state_get(key: str, request: Request):
|
|
160
|
+
broker = _get_broker(request)
|
|
161
|
+
result = broker.get_state_key(key)
|
|
162
|
+
if result is None:
|
|
163
|
+
raise HTTPException(404, detail="key not found")
|
|
164
|
+
return result
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@router.post("/lock")
|
|
168
|
+
async def lock(req: LockRequest, request: Request):
|
|
169
|
+
broker = _get_broker(request)
|
|
170
|
+
if not req.file_path or not req.locked_by:
|
|
171
|
+
raise HTTPException(400, detail="file_path and locked_by required")
|
|
172
|
+
if req.action not in ("acquire", "release", "query"):
|
|
173
|
+
raise HTTPException(400, detail="action must be acquire, release, or query")
|
|
174
|
+
return broker.lock_action(req.file_path, req.locked_by, req.action)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@router.get("/events")
|
|
178
|
+
async def events(request: Request):
|
|
179
|
+
broker = _get_broker(request)
|
|
180
|
+
return {"events": broker.get_events()}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@router.get("/status")
|
|
184
|
+
async def status(request: Request):
|
|
185
|
+
broker = _get_broker(request)
|
|
186
|
+
return broker.get_status()
|