basic-memory 0.6.0__py3-none-any.whl → 0.8.0__py3-none-any.whl
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.
Potentially problematic release.
This version of basic-memory might be problematic. Click here for more details.
- basic_memory/__init__.py +1 -1
- basic_memory/alembic/alembic.ini +119 -0
- basic_memory/alembic/env.py +23 -1
- basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py +51 -0
- basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py +44 -0
- basic_memory/api/app.py +0 -4
- basic_memory/api/routers/knowledge_router.py +1 -9
- basic_memory/api/routers/memory_router.py +41 -25
- basic_memory/api/routers/resource_router.py +119 -12
- basic_memory/api/routers/search_router.py +17 -9
- basic_memory/cli/app.py +0 -2
- basic_memory/cli/commands/db.py +11 -8
- basic_memory/cli/commands/import_chatgpt.py +31 -27
- basic_memory/cli/commands/import_claude_conversations.py +29 -27
- basic_memory/cli/commands/import_claude_projects.py +30 -29
- basic_memory/cli/commands/import_memory_json.py +28 -26
- basic_memory/cli/commands/status.py +16 -26
- basic_memory/cli/commands/sync.py +11 -12
- basic_memory/cli/commands/tools.py +180 -0
- basic_memory/cli/main.py +1 -1
- basic_memory/config.py +16 -2
- basic_memory/db.py +1 -0
- basic_memory/deps.py +5 -1
- basic_memory/file_utils.py +6 -4
- basic_memory/markdown/entity_parser.py +3 -3
- basic_memory/mcp/async_client.py +1 -1
- basic_memory/mcp/main.py +25 -0
- basic_memory/mcp/prompts/__init__.py +15 -0
- basic_memory/mcp/prompts/ai_assistant_guide.py +28 -0
- basic_memory/mcp/prompts/continue_conversation.py +172 -0
- basic_memory/mcp/prompts/json_canvas_spec.py +25 -0
- basic_memory/mcp/prompts/recent_activity.py +46 -0
- basic_memory/mcp/prompts/search.py +127 -0
- basic_memory/mcp/prompts/utils.py +98 -0
- basic_memory/mcp/server.py +3 -7
- basic_memory/mcp/tools/__init__.py +6 -4
- basic_memory/mcp/tools/canvas.py +99 -0
- basic_memory/mcp/tools/knowledge.py +26 -14
- basic_memory/mcp/tools/memory.py +57 -31
- basic_memory/mcp/tools/notes.py +65 -72
- basic_memory/mcp/tools/resource.py +192 -0
- basic_memory/mcp/tools/search.py +13 -4
- basic_memory/mcp/tools/utils.py +2 -1
- basic_memory/models/knowledge.py +27 -11
- basic_memory/repository/repository.py +1 -1
- basic_memory/repository/search_repository.py +17 -4
- basic_memory/schemas/__init__.py +0 -11
- basic_memory/schemas/base.py +4 -1
- basic_memory/schemas/memory.py +14 -2
- basic_memory/schemas/request.py +1 -1
- basic_memory/schemas/search.py +4 -1
- basic_memory/services/context_service.py +14 -6
- basic_memory/services/entity_service.py +19 -12
- basic_memory/services/file_service.py +69 -2
- basic_memory/services/link_resolver.py +12 -9
- basic_memory/services/search_service.py +59 -13
- basic_memory/sync/__init__.py +3 -2
- basic_memory/sync/sync_service.py +287 -107
- basic_memory/sync/watch_service.py +125 -129
- basic_memory/utils.py +27 -15
- {basic_memory-0.6.0.dist-info → basic_memory-0.8.0.dist-info}/METADATA +3 -2
- basic_memory-0.8.0.dist-info/RECORD +91 -0
- basic_memory/alembic/README +0 -1
- basic_memory/schemas/discovery.py +0 -28
- basic_memory/sync/file_change_scanner.py +0 -158
- basic_memory/sync/utils.py +0 -31
- basic_memory-0.6.0.dist-info/RECORD +0 -81
- {basic_memory-0.6.0.dist-info → basic_memory-0.8.0.dist-info}/WHEEL +0 -0
- {basic_memory-0.6.0.dist-info → basic_memory-0.8.0.dist-info}/entry_points.txt +0 -0
- {basic_memory-0.6.0.dist-info → basic_memory-0.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
"""Watch service for Basic Memory."""
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
|
|
5
|
-
from loguru import logger
|
|
6
|
-
from pydantic import BaseModel
|
|
4
|
+
import os
|
|
7
5
|
from datetime import datetime
|
|
8
6
|
from pathlib import Path
|
|
9
|
-
from typing import List, Optional
|
|
7
|
+
from typing import List, Optional, Set
|
|
10
8
|
|
|
9
|
+
from loguru import logger
|
|
10
|
+
from pydantic import BaseModel
|
|
11
11
|
from rich.console import Console
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from watchfiles import awatch, Change
|
|
15
|
-
import os
|
|
12
|
+
from watchfiles import awatch
|
|
13
|
+
from watchfiles.main import FileChange, Change
|
|
16
14
|
|
|
17
15
|
from basic_memory.config import ProjectConfig
|
|
18
|
-
from basic_memory.sync.sync_service import SyncService
|
|
19
16
|
from basic_memory.services.file_service import FileService
|
|
17
|
+
from basic_memory.sync.sync_service import SyncService
|
|
20
18
|
|
|
21
19
|
|
|
22
20
|
class WatchEvent(BaseModel):
|
|
@@ -81,138 +79,136 @@ class WatchService:
|
|
|
81
79
|
self.status_path.parent.mkdir(parents=True, exist_ok=True)
|
|
82
80
|
self.console = Console()
|
|
83
81
|
|
|
84
|
-
def
|
|
85
|
-
"""Generate status display table"""
|
|
86
|
-
table = Table()
|
|
87
|
-
|
|
88
|
-
# Add status row
|
|
89
|
-
table.add_column("Status", style="cyan")
|
|
90
|
-
table.add_column("Last Scan", style="cyan")
|
|
91
|
-
table.add_column("Files", style="cyan")
|
|
92
|
-
table.add_column("Errors", style="red")
|
|
93
|
-
|
|
94
|
-
# Add main status row
|
|
95
|
-
table.add_row(
|
|
96
|
-
"✓ Running" if self.state.running else "✗ Stopped",
|
|
97
|
-
self.state.last_scan.strftime("%H:%M:%S") if self.state.last_scan else "-",
|
|
98
|
-
str(self.state.synced_files),
|
|
99
|
-
f"{self.state.error_count} ({self.state.last_error.strftime('%H:%M:%S') if self.state.last_error else 'none'})",
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
if self.state.recent_events:
|
|
103
|
-
# Add recent events
|
|
104
|
-
table.add_section()
|
|
105
|
-
table.add_row("Recent Events", "", "", "")
|
|
106
|
-
|
|
107
|
-
for event in self.state.recent_events[:5]: # Show last 5 events
|
|
108
|
-
color = {
|
|
109
|
-
"new": "green",
|
|
110
|
-
"modified": "yellow",
|
|
111
|
-
"moved": "blue",
|
|
112
|
-
"deleted": "red",
|
|
113
|
-
"error": "red",
|
|
114
|
-
}.get(event.action, "white")
|
|
115
|
-
|
|
116
|
-
icon = {
|
|
117
|
-
"new": "✚",
|
|
118
|
-
"modified": "✎",
|
|
119
|
-
"moved": "→",
|
|
120
|
-
"deleted": "✖",
|
|
121
|
-
"error": "!",
|
|
122
|
-
}.get(event.action, "*")
|
|
123
|
-
|
|
124
|
-
table.add_row(
|
|
125
|
-
f"[{color}]{icon} {event.action}[/{color}]",
|
|
126
|
-
event.timestamp.strftime("%H:%M:%S"),
|
|
127
|
-
f"[{color}]{event.path}[/{color}]",
|
|
128
|
-
f"[dim]{event.checksum[:8] if event.checksum else ''}[/dim]",
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
return table
|
|
132
|
-
|
|
133
|
-
async def run(self, console_status: bool = False): # pragma: no cover
|
|
82
|
+
async def run(self): # pragma: no cover
|
|
134
83
|
"""Watch for file changes and sync them"""
|
|
135
84
|
logger.info("Watching for sync changes")
|
|
136
85
|
self.state.running = True
|
|
137
86
|
self.state.start_time = datetime.now()
|
|
138
87
|
await self.write_status()
|
|
88
|
+
try:
|
|
89
|
+
async for changes in awatch(
|
|
90
|
+
self.config.home,
|
|
91
|
+
debounce=self.config.sync_delay,
|
|
92
|
+
watch_filter=self.filter_changes,
|
|
93
|
+
recursive=True,
|
|
94
|
+
):
|
|
95
|
+
await self.handle_changes(self.config.home, changes)
|
|
96
|
+
|
|
97
|
+
except Exception as e:
|
|
98
|
+
self.state.record_error(str(e))
|
|
99
|
+
await self.write_status()
|
|
100
|
+
raise
|
|
101
|
+
finally:
|
|
102
|
+
self.state.running = False
|
|
103
|
+
await self.write_status()
|
|
104
|
+
|
|
105
|
+
def filter_changes(self, change: Change, path: str) -> bool:
|
|
106
|
+
"""Filter to only watch non-hidden files and directories.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
True if the file should be watched, False if it should be ignored
|
|
110
|
+
"""
|
|
111
|
+
# Skip if path is invalid
|
|
112
|
+
try:
|
|
113
|
+
relative_path = Path(path).relative_to(self.config.home)
|
|
114
|
+
except ValueError:
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
# Skip hidden directories and files
|
|
118
|
+
path_parts = relative_path.parts
|
|
119
|
+
for part in path_parts:
|
|
120
|
+
if part.startswith("."):
|
|
121
|
+
return False
|
|
139
122
|
|
|
140
|
-
|
|
141
|
-
with Live(self.generate_table(), refresh_per_second=4, console=self.console) as live:
|
|
142
|
-
try:
|
|
143
|
-
async for changes in awatch(
|
|
144
|
-
self.config.home,
|
|
145
|
-
watch_filter=self.filter_changes,
|
|
146
|
-
debounce=self.config.sync_delay,
|
|
147
|
-
recursive=True,
|
|
148
|
-
):
|
|
149
|
-
# Process changes
|
|
150
|
-
await self.handle_changes(self.config.home)
|
|
151
|
-
# Update display
|
|
152
|
-
live.update(self.generate_table())
|
|
153
|
-
|
|
154
|
-
except Exception as e:
|
|
155
|
-
self.state.record_error(str(e))
|
|
156
|
-
await self.write_status()
|
|
157
|
-
raise
|
|
158
|
-
finally:
|
|
159
|
-
self.state.running = False
|
|
160
|
-
await self.write_status()
|
|
161
|
-
|
|
162
|
-
else:
|
|
163
|
-
try:
|
|
164
|
-
async for changes in awatch(
|
|
165
|
-
self.config.home,
|
|
166
|
-
watch_filter=self.filter_changes,
|
|
167
|
-
debounce=self.config.sync_delay,
|
|
168
|
-
recursive=True,
|
|
169
|
-
):
|
|
170
|
-
# Process changes
|
|
171
|
-
await self.handle_changes(self.config.home)
|
|
172
|
-
# Update display
|
|
173
|
-
|
|
174
|
-
except Exception as e:
|
|
175
|
-
self.state.record_error(str(e))
|
|
176
|
-
await self.write_status()
|
|
177
|
-
raise
|
|
178
|
-
finally:
|
|
179
|
-
self.state.running = False
|
|
180
|
-
await self.write_status()
|
|
123
|
+
return True
|
|
181
124
|
|
|
182
125
|
async def write_status(self):
|
|
183
126
|
"""Write current state to status file"""
|
|
184
127
|
self.status_path.write_text(WatchServiceState.model_dump_json(self.state, indent=2))
|
|
185
128
|
|
|
186
|
-
def
|
|
187
|
-
"""Filter to only watch markdown files"""
|
|
188
|
-
return path.endswith(".md") and not Path(path).name.startswith(".")
|
|
189
|
-
|
|
190
|
-
async def handle_changes(self, directory: Path):
|
|
129
|
+
async def handle_changes(self, directory: Path, changes: Set[FileChange]):
|
|
191
130
|
"""Process a batch of file changes"""
|
|
131
|
+
logger.debug(f"handling {len(changes)} changes in directory: {directory} ...")
|
|
132
|
+
|
|
133
|
+
# Group changes by type
|
|
134
|
+
adds = []
|
|
135
|
+
deletes = []
|
|
136
|
+
modifies = []
|
|
137
|
+
|
|
138
|
+
for change, path in changes:
|
|
139
|
+
# convert to relative path
|
|
140
|
+
relative_path = str(Path(path).relative_to(directory))
|
|
141
|
+
if change == Change.added:
|
|
142
|
+
adds.append(relative_path)
|
|
143
|
+
elif change == Change.deleted:
|
|
144
|
+
deletes.append(relative_path)
|
|
145
|
+
elif change == Change.modified:
|
|
146
|
+
modifies.append(relative_path)
|
|
147
|
+
|
|
148
|
+
# Track processed files to avoid duplicates
|
|
149
|
+
processed = set()
|
|
150
|
+
|
|
151
|
+
# First handle potential moves
|
|
152
|
+
for added_path in adds:
|
|
153
|
+
if added_path in processed:
|
|
154
|
+
continue # pragma: no cover
|
|
155
|
+
|
|
156
|
+
for deleted_path in deletes:
|
|
157
|
+
if deleted_path in processed:
|
|
158
|
+
continue # pragma: no cover
|
|
159
|
+
|
|
160
|
+
if added_path != deleted_path:
|
|
161
|
+
# Compare checksums to detect moves
|
|
162
|
+
try:
|
|
163
|
+
added_checksum = await self.file_service.compute_checksum(added_path)
|
|
164
|
+
deleted_entity = await self.sync_service.entity_repository.get_by_file_path(
|
|
165
|
+
deleted_path
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
if deleted_entity and deleted_entity.checksum == added_checksum:
|
|
169
|
+
await self.sync_service.handle_move(deleted_path, added_path)
|
|
170
|
+
self.state.add_event(
|
|
171
|
+
path=f"{deleted_path} -> {added_path}",
|
|
172
|
+
action="moved",
|
|
173
|
+
status="success",
|
|
174
|
+
)
|
|
175
|
+
self.console.print(
|
|
176
|
+
f"[blue]→[/blue] Moved: {deleted_path} → {added_path}"
|
|
177
|
+
)
|
|
178
|
+
processed.add(added_path)
|
|
179
|
+
processed.add(deleted_path)
|
|
180
|
+
break
|
|
181
|
+
except Exception as e: # pragma: no cover
|
|
182
|
+
logger.warning(f"Error checking for move: {e}")
|
|
183
|
+
|
|
184
|
+
# Handle remaining changes
|
|
185
|
+
for path in deletes:
|
|
186
|
+
if path not in processed:
|
|
187
|
+
await self.sync_service.handle_delete(path)
|
|
188
|
+
self.state.add_event(path=path, action="deleted", status="success")
|
|
189
|
+
self.console.print(f"[red]✕[/red] Deleted: {path}")
|
|
190
|
+
processed.add(path)
|
|
191
|
+
|
|
192
|
+
for path in adds:
|
|
193
|
+
if path not in processed:
|
|
194
|
+
_, checksum = await self.sync_service.sync_file(path, new=True)
|
|
195
|
+
self.state.add_event(path=path, action="new", status="success", checksum=checksum)
|
|
196
|
+
self.console.print(f"[green]✓[/green] Added: {path}")
|
|
197
|
+
processed.add(path)
|
|
198
|
+
|
|
199
|
+
for path in modifies:
|
|
200
|
+
if path not in processed:
|
|
201
|
+
_, checksum = await self.sync_service.sync_file(path, new=False)
|
|
202
|
+
self.state.add_event(
|
|
203
|
+
path=path, action="modified", status="success", checksum=checksum
|
|
204
|
+
)
|
|
205
|
+
self.console.print(f"[yellow]✎[/yellow] Modified: {path}")
|
|
206
|
+
processed.add(path)
|
|
192
207
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
self.state.last_scan = datetime.now()
|
|
197
|
-
self.state.synced_files = report.total
|
|
198
|
-
|
|
199
|
-
# Update stats
|
|
200
|
-
for path in report.new:
|
|
201
|
-
self.state.add_event(
|
|
202
|
-
path=path, action="new", status="success", checksum=report.checksums[path]
|
|
203
|
-
)
|
|
204
|
-
for path in report.modified:
|
|
205
|
-
self.state.add_event(
|
|
206
|
-
path=path, action="modified", status="success", checksum=report.checksums[path]
|
|
207
|
-
)
|
|
208
|
-
for old_path, new_path in report.moves.items():
|
|
209
|
-
self.state.add_event(
|
|
210
|
-
path=f"{old_path} -> {new_path}",
|
|
211
|
-
action="moved",
|
|
212
|
-
status="success",
|
|
213
|
-
checksum=report.checksums[new_path],
|
|
214
|
-
)
|
|
215
|
-
for path in report.deleted:
|
|
216
|
-
self.state.add_event(path=path, action="deleted", status="success")
|
|
208
|
+
# Add a divider if we processed any files
|
|
209
|
+
if processed:
|
|
210
|
+
self.console.print("─" * 50, style="dim")
|
|
217
211
|
|
|
212
|
+
self.state.last_scan = datetime.now()
|
|
213
|
+
self.state.synced_files += len(processed)
|
|
218
214
|
await self.write_status()
|
basic_memory/utils.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Utility functions for basic-memory."""
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
import os
|
|
4
5
|
import re
|
|
5
6
|
import sys
|
|
@@ -10,7 +11,6 @@ from loguru import logger
|
|
|
10
11
|
from unidecode import unidecode
|
|
11
12
|
|
|
12
13
|
import basic_memory
|
|
13
|
-
from basic_memory.config import config
|
|
14
14
|
|
|
15
15
|
import logfire
|
|
16
16
|
|
|
@@ -65,45 +65,45 @@ def generate_permalink(file_path: Union[Path, str]) -> str:
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
def setup_logging(
|
|
68
|
-
|
|
68
|
+
env: str,
|
|
69
|
+
home_dir: Path,
|
|
70
|
+
log_file: Optional[str] = None,
|
|
71
|
+
log_level: str = "INFO",
|
|
72
|
+
console: bool = True,
|
|
69
73
|
) -> None: # pragma: no cover
|
|
70
74
|
"""
|
|
71
75
|
Configure logging for the application.
|
|
72
76
|
:param home_dir: the root directory for the application
|
|
73
77
|
:param log_file: the name of the log file to write to
|
|
74
78
|
:param app: the fastapi application instance
|
|
79
|
+
:param console: whether to log to the console
|
|
75
80
|
"""
|
|
76
81
|
|
|
77
82
|
# Remove default handler and any existing handlers
|
|
78
83
|
logger.remove()
|
|
79
84
|
|
|
80
85
|
# Add file handler if we are not running tests
|
|
81
|
-
if log_file and
|
|
86
|
+
if log_file and env != "test":
|
|
82
87
|
# enable pydantic logfire
|
|
83
88
|
logfire.configure(
|
|
84
89
|
code_source=logfire.CodeSource(
|
|
85
90
|
repository="https://github.com/basicmachines-co/basic-memory",
|
|
86
91
|
revision=basic_memory.__version__,
|
|
87
|
-
root_path="/src/basic_memory",
|
|
88
92
|
),
|
|
89
|
-
environment=
|
|
93
|
+
environment=env,
|
|
94
|
+
console=False,
|
|
90
95
|
)
|
|
91
96
|
logger.configure(handlers=[logfire.loguru_handler()])
|
|
92
97
|
|
|
93
98
|
# instrument code spans
|
|
94
99
|
logfire.instrument_sqlite3()
|
|
95
|
-
logfire.
|
|
96
|
-
|
|
97
|
-
from basic_memory.db import _engine as engine
|
|
98
|
-
|
|
99
|
-
if engine:
|
|
100
|
-
logfire.instrument_sqlalchemy(engine=engine)
|
|
100
|
+
logfire.instrument_httpx()
|
|
101
101
|
|
|
102
102
|
# setup logger
|
|
103
103
|
log_path = home_dir / log_file
|
|
104
104
|
logger.add(
|
|
105
105
|
str(log_path),
|
|
106
|
-
level=
|
|
106
|
+
level=log_level,
|
|
107
107
|
rotation="100 MB",
|
|
108
108
|
retention="10 days",
|
|
109
109
|
backtrace=True,
|
|
@@ -112,7 +112,19 @@ def setup_logging(
|
|
|
112
112
|
colorize=False,
|
|
113
113
|
)
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
if env == "test" or console:
|
|
116
|
+
# Add stderr handler
|
|
117
|
+
logger.add(sys.stderr, level=log_level, backtrace=True, diagnose=True, colorize=True)
|
|
118
|
+
|
|
119
|
+
logger.info(f"ENV: '{env}' Log level: '{log_level}' Logging to {log_file}")
|
|
120
|
+
|
|
121
|
+
# Get the logger for 'httpx'
|
|
122
|
+
httpx_logger = logging.getLogger("httpx")
|
|
123
|
+
# Set the logging level to WARNING to ignore INFO and DEBUG logs
|
|
124
|
+
httpx_logger.setLevel(logging.WARNING)
|
|
125
|
+
|
|
126
|
+
# turn watchfiles to WARNING
|
|
127
|
+
logging.getLogger("watchfiles.main").setLevel(logging.WARNING)
|
|
117
128
|
|
|
118
|
-
|
|
129
|
+
# disable open telemetry warning
|
|
130
|
+
logging.getLogger("instrumentor").setLevel(logging.ERROR)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basic-memory
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Local-first knowledge management combining Zettelkasten with knowledge graphs
|
|
5
5
|
Project-URL: Homepage, https://github.com/basicmachines-co/basic-memory
|
|
6
6
|
Project-URL: Repository, https://github.com/basicmachines-co/basic-memory
|
|
@@ -15,10 +15,11 @@ Requires-Dist: dateparser>=1.2.0
|
|
|
15
15
|
Requires-Dist: fastapi[standard]>=0.115.8
|
|
16
16
|
Requires-Dist: greenlet>=3.1.1
|
|
17
17
|
Requires-Dist: icecream>=2.1.3
|
|
18
|
-
Requires-Dist: logfire[fastapi,sqlalchemy,sqlite3]>=3.6.0
|
|
18
|
+
Requires-Dist: logfire[fastapi,httpx,sqlalchemy,sqlite3]>=3.6.0
|
|
19
19
|
Requires-Dist: loguru>=0.7.3
|
|
20
20
|
Requires-Dist: markdown-it-py>=3.0.0
|
|
21
21
|
Requires-Dist: mcp>=1.2.0
|
|
22
|
+
Requires-Dist: pillow>=11.1.0
|
|
22
23
|
Requires-Dist: pydantic-settings>=2.6.1
|
|
23
24
|
Requires-Dist: pydantic[email,timezone]>=2.10.3
|
|
24
25
|
Requires-Dist: pyright>=1.1.390
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
basic_memory/__init__.py,sha256=1Vkhl1i_QQpYLtQxxfrs_tJ3ZUbmJC0C4zxgmVy7C60,122
|
|
2
|
+
basic_memory/config.py,sha256=kh3LC9slFHoxfIufziyqafbI2tS9NXpEgJ8y3bH1Ixk,2129
|
|
3
|
+
basic_memory/db.py,sha256=EVX3pgA2rah4tZpxy5wKvZSN8vVcrvo5l-hKjAXBb0U,5284
|
|
4
|
+
basic_memory/deps.py,sha256=8LkcfppQEJpiflYZxLk-SmQuL04qknbsdfzIkM_ctuY,5530
|
|
5
|
+
basic_memory/file_utils.py,sha256=Kx2WVewno_SnLMnorHdiWwsZztY6esKRVirmDQSiv2w,5864
|
|
6
|
+
basic_memory/utils.py,sha256=2GOo14HUcnzpft6tkSCr8QTESlS5baxfm8oZJ6vdVds,3711
|
|
7
|
+
basic_memory/alembic/alembic.ini,sha256=IEZsnF8CbbZnkwBr67LzKKNobHuzTaQNUvM8Psop5xc,3733
|
|
8
|
+
basic_memory/alembic/env.py,sha256=GyQpEpQu84flqAdelxR0-H9nbkHrVoCboYGfmltBDoA,2737
|
|
9
|
+
basic_memory/alembic/migrations.py,sha256=CIbkMHEKZ60aDUhFGSQjv8kDNM7sazfvEYHGGcy1DBk,858
|
|
10
|
+
basic_memory/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
|
|
11
|
+
basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py,sha256=lTbWlAnd1es7xU99DoJgfaRe1_Kte8TL98riqeKGV80,4363
|
|
12
|
+
basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py,sha256=k6xYTmYPM9Ros-7CA7BwZBKYwoK_gmVdC-2n8FAjdoE,1840
|
|
13
|
+
basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py,sha256=RsGymQzfRXV1LSNKiyi0lMilTxW1NgwS9jR67ye2apI,1428
|
|
14
|
+
basic_memory/api/__init__.py,sha256=wCpj-21j1D0KzKl9Ql6unLBVFY0K1uGp_FeSZRKtqpk,72
|
|
15
|
+
basic_memory/api/app.py,sha256=Ma-kLPkwlHUQ1dutExIqedMiFurzgBcazusQDq7IDsE,1374
|
|
16
|
+
basic_memory/api/routers/__init__.py,sha256=iviQ1QVYobC8huUuyRhEjcA0BDjrOUm1lXHXhJkxP9A,239
|
|
17
|
+
basic_memory/api/routers/knowledge_router.py,sha256=2encEkZw7gKyfwa2HjFtTJh5aXhl96DFLrSB2pk-HfI,5291
|
|
18
|
+
basic_memory/api/routers/memory_router.py,sha256=wGoAWm1ehWSlDYI66eUtp99b7uPJtymh2RMaZiohh0Y,5371
|
|
19
|
+
basic_memory/api/routers/resource_router.py,sha256=WEJEqEaY_yTKj5-U-rW4kXQKUcJflykgwI6_g_R41ck,8058
|
|
20
|
+
basic_memory/api/routers/search_router.py,sha256=WCLuAkEZ-DpwHU8RsnZg63_LDiSYbbLLlBb9Avbc2fA,1164
|
|
21
|
+
basic_memory/cli/__init__.py,sha256=arcKLAWRDhPD7x5t80MlviZeYzwHZ0GZigyy3NKVoGk,33
|
|
22
|
+
basic_memory/cli/app.py,sha256=EyE-qactiI4QMGXZzmYcVNtn3-16zy1jT_G-a-yx2AU,324
|
|
23
|
+
basic_memory/cli/main.py,sha256=KH2JDvQNIwV7VRKnKZ2jTkMSlTECziUmk1xgmU6ezfw,433
|
|
24
|
+
basic_memory/cli/commands/__init__.py,sha256=OQGLaKTsOdPsp2INM_pHzmOlbVfdL0sytBNgvqTqCDY,159
|
|
25
|
+
basic_memory/cli/commands/db.py,sha256=BW3VmoTKNfzkl85m9lyrx8lkk1IRb6wuAmrPKFQxNE8,906
|
|
26
|
+
basic_memory/cli/commands/import_chatgpt.py,sha256=py3q9iMlB85olQBsBcEpUt0X03hHvAmRy8iQl2dbbuc,8394
|
|
27
|
+
basic_memory/cli/commands/import_claude_conversations.py,sha256=_7n-nn1tbsaarwR25QXjYxSC_K2M0cXBTzthnCZ_4-w,7030
|
|
28
|
+
basic_memory/cli/commands/import_claude_projects.py,sha256=fvXu6wwlmfA2wJCcp8IoJnz3INefkVcFhqAX8KhnCtc,6851
|
|
29
|
+
basic_memory/cli/commands/import_memory_json.py,sha256=cS-1rxGYUC0-QsETIbA0QqbB1Cl74YcnoJRNCkMkM-o,5395
|
|
30
|
+
basic_memory/cli/commands/mcp.py,sha256=BPdThcufdriIvrDskc87a0oCC1BkZ0PZsgNao_-oNKk,611
|
|
31
|
+
basic_memory/cli/commands/status.py,sha256=YEw6SA82Y8GbtTIn-h6m15zjX5bGMx5abAbu19LXVjs,5398
|
|
32
|
+
basic_memory/cli/commands/sync.py,sha256=uSzGPdjbMX7PKh8iA_Oo06zLc0tixX_cV6i_JWph95I,6766
|
|
33
|
+
basic_memory/cli/commands/tools.py,sha256=P5EMifFHDlaTFje97Yxp9GawoRlCOML5Dy6wBBjMnjo,6117
|
|
34
|
+
basic_memory/markdown/__init__.py,sha256=DdzioCWtDnKaq05BHYLgL_78FawEHLpLXnp-kPSVfIc,501
|
|
35
|
+
basic_memory/markdown/entity_parser.py,sha256=LnjG_wg38LVN8JndsZJV2UVGPIaoIV5sGs94iQ9PL6k,3781
|
|
36
|
+
basic_memory/markdown/markdown_processor.py,sha256=mV3pYoDTaQMEl1tA5n_XztBvNlYyH2SzKs4vnKdAet4,4952
|
|
37
|
+
basic_memory/markdown/plugins.py,sha256=gtIzKRjoZsyvBqLpVNnrmzl_cbTZ5ZGn8kcuXxQjRko,6639
|
|
38
|
+
basic_memory/markdown/schemas.py,sha256=mzVEDUhH98kwETMknjkKw5H697vg_zUapsJkJVi17ho,1894
|
|
39
|
+
basic_memory/markdown/utils.py,sha256=ZtHa-dG--ZwFEUC3jfl04KZGhM_ZWo5b-8d8KpJ90gY,2758
|
|
40
|
+
basic_memory/mcp/__init__.py,sha256=dsDOhKqjYeIbCULbHIxfcItTbqudEuEg1Np86eq0GEQ,35
|
|
41
|
+
basic_memory/mcp/async_client.py,sha256=Eo345wANiBRSM4u3j_Vd6Ax4YtMg7qbWd9PIoFfj61I,236
|
|
42
|
+
basic_memory/mcp/main.py,sha256=p_zjCDSeT9EsjNmlzDfEQ7xI8Y_bBLmMG0g-y-DakTA,703
|
|
43
|
+
basic_memory/mcp/server.py,sha256=vlhURihp7Ly1eVyI01J9zvYhbz7wgHkhoNLNq6KOGug,286
|
|
44
|
+
basic_memory/mcp/prompts/__init__.py,sha256=BsjRBgxYjS-JXK8RqJQQd1xPEoWWgQ4Hw3BynaYxGwA,670
|
|
45
|
+
basic_memory/mcp/prompts/ai_assistant_guide.py,sha256=e2DoP2Dv2HSDd00m6xGjGMWxUIqYJceJhw3RxuuJdeA,925
|
|
46
|
+
basic_memory/mcp/prompts/continue_conversation.py,sha256=tXE626Qay8aY4tDQhAmvZYO8nf7tTfAMRqE24JShTvc,6666
|
|
47
|
+
basic_memory/mcp/prompts/json_canvas_spec.py,sha256=yKO_9_ojF4tCEWSMuHn5YNHFkAibzPdOgluAKJ-K924,827
|
|
48
|
+
basic_memory/mcp/prompts/recent_activity.py,sha256=3b9_jxPQ-c4lQH05Ig2a6k4ApWW5d9WhcArhMU0S6BM,1552
|
|
49
|
+
basic_memory/mcp/prompts/search.py,sha256=1E8dHcPRCy19Emv7r4MWJ2ZYsuQNa4qRmIy2fnuWuoA,4496
|
|
50
|
+
basic_memory/mcp/prompts/utils.py,sha256=cPdlJl1D5bS36hQBoBgf0RACE2ToUy-HgHukO8eRkZ4,3734
|
|
51
|
+
basic_memory/mcp/tools/__init__.py,sha256=_MXdi0AJr5WB5C20WSQAwHhWOyhspyzbgWL9ijQh3to,953
|
|
52
|
+
basic_memory/mcp/tools/canvas.py,sha256=wbSg-NauRmz_reNH3SUY2kLWNUKMA5kPvSoz_6ec7uw,3162
|
|
53
|
+
basic_memory/mcp/tools/knowledge.py,sha256=JotFMQpMwidx0WLvOG4yWpwWwLmyp-PoO6bVjpQseYQ,2671
|
|
54
|
+
basic_memory/mcp/tools/memory.py,sha256=rteQJSXIUGsJbA-AzZN1dyHKr98EELHGc-rvMXlG2JI,6474
|
|
55
|
+
basic_memory/mcp/tools/notes.py,sha256=vAiQsJqJvxevYUPxVib10Jd5qvEMATeiSeu1sGe32nM,7415
|
|
56
|
+
basic_memory/mcp/tools/resource.py,sha256=Imbl8exE27qPmWEZ4DXIeCdpQXSYYv_ul8whTu3d_cE,6526
|
|
57
|
+
basic_memory/mcp/tools/search.py,sha256=UFPBDzfZ60SrvAgvISO3Jt6WdNwEQKsvibQdPxC7dOg,1511
|
|
58
|
+
basic_memory/mcp/tools/utils.py,sha256=h_iDGduofU4GyQyyARkI4L-OJ9Rwppkx48BDSEMYsLY,4866
|
|
59
|
+
basic_memory/models/__init__.py,sha256=Bf0xXV_ryndogvZDiVM_Wb6iV2fHUxYNGMZNWNcZi0s,307
|
|
60
|
+
basic_memory/models/base.py,sha256=4hAXJ8CE1RnjKhb23lPd-QM7G_FXIdTowMJ9bRixspU,225
|
|
61
|
+
basic_memory/models/knowledge.py,sha256=lbKd8VOOVPqXtIhNMY30bIokoQutFjLpHwLD5At90MY,6644
|
|
62
|
+
basic_memory/models/search.py,sha256=IB-ySJUqlQq9FqLGfWnraIFcB_brWa9eBwsQP1rVTeI,1164
|
|
63
|
+
basic_memory/repository/__init__.py,sha256=TnscLXARq2iOgQZFvQoT9X1Bn9SB_7s1xw2fOqRs3Jg,252
|
|
64
|
+
basic_memory/repository/entity_repository.py,sha256=VFLymzJ1W6AZru_s1S3U6nlqSprBrVV5Toy0-qysIfw,3524
|
|
65
|
+
basic_memory/repository/observation_repository.py,sha256=BOcy4wARqCXu-thYyt7mPxt2A2C8TW0le3s_X9wrK6I,1701
|
|
66
|
+
basic_memory/repository/relation_repository.py,sha256=DwpTcn9z_1sZQcyMOUABz1k1VSwo_AU63x2zR7aerTk,2933
|
|
67
|
+
basic_memory/repository/repository.py,sha256=X59h8JevRn9sEZz6R41NvtyXo9Gbq22mY-XxsoIEwrQ,11324
|
|
68
|
+
basic_memory/repository/search_repository.py,sha256=3AOrfTihzLKiXZTGerrKyRUpITNtXyLrp_XWEVpY3h0,10503
|
|
69
|
+
basic_memory/schemas/__init__.py,sha256=WXQ2okYPC-OFa2xmCWq-EP52lSuqFX9Sx-zMJUPv8to,1318
|
|
70
|
+
basic_memory/schemas/base.py,sha256=dwnaI5fJXsdp81mdH0ZpmJ-WICY-0M7ZPWeW5OUgBG8,5685
|
|
71
|
+
basic_memory/schemas/delete.py,sha256=UAR2JK99WMj3gP-yoGWlHD3eZEkvlTSRf8QoYIE-Wfw,1180
|
|
72
|
+
basic_memory/schemas/memory.py,sha256=ap8lKHxUfM6WTiAFlObs_rZWz3sQxhiGlcvc_NVA9f8,3094
|
|
73
|
+
basic_memory/schemas/request.py,sha256=58r9mPGc4Am9rR_zGzo-yqXcsrl5I6n3M5LjGK5gFFk,1626
|
|
74
|
+
basic_memory/schemas/response.py,sha256=lVYR31DTtSeFRddGWX_wQWnQgyiwX0LEpNJ4f4lKpTM,6440
|
|
75
|
+
basic_memory/schemas/search.py,sha256=riODPc4EWgXTM4QRBJZ9vZga9lP9lYRF7Nfbtlw_gjg,3344
|
|
76
|
+
basic_memory/services/__init__.py,sha256=oop6SKmzV4_NAYt9otGnupLGVCCKIVgxEcdRQWwh25I,197
|
|
77
|
+
basic_memory/services/context_service.py,sha256=y2Kd9YRPdQbJ6uWcY71z2qCZZUt8Sb2Dy52dh2OMJxo,9651
|
|
78
|
+
basic_memory/services/entity_service.py,sha256=cMas6BjtWJLt3QMUsR1U21Js_vpFFKz1SMwSnXD8Suk,12133
|
|
79
|
+
basic_memory/services/exceptions.py,sha256=VGlCLd4UD2w5NWKqC7QpG4jOM_hA7jKRRM-MqvEVMNk,288
|
|
80
|
+
basic_memory/services/file_service.py,sha256=Z81qnaIHEQd9M9SMCQwvo5Wga3R3hfP43hEllt5KTmc,8008
|
|
81
|
+
basic_memory/services/link_resolver.py,sha256=m1ycdKrU9tnVHaMn1vuEN4_2YJ5f912Us61PTB2O7QI,4708
|
|
82
|
+
basic_memory/services/search_service.py,sha256=OYnv15DVUZGI3WBVwdW3VARlWR377hwb5GH2eNts400,9336
|
|
83
|
+
basic_memory/services/service.py,sha256=V-d_8gOV07zGIQDpL-Ksqs3ZN9l3qf3HZOK1f_YNTag,336
|
|
84
|
+
basic_memory/sync/__init__.py,sha256=CVHguYH457h2u2xoM8KvOilJC71XJlZ-qUh8lHcjYj4,156
|
|
85
|
+
basic_memory/sync/sync_service.py,sha256=1lytLbJO1RxKhihv3n7zsuek4MpbJ_bc2aCcqGl7hh0,13724
|
|
86
|
+
basic_memory/sync/watch_service.py,sha256=FtamKOp_aTMdTdd8fNL60Bn3VU2IjHJJh8wzp3-T5DQ,7662
|
|
87
|
+
basic_memory-0.8.0.dist-info/METADATA,sha256=7z2Vt7lYowomq0uUxzNT6aHcwfz8IseOPcmYCbZcZfE,10885
|
|
88
|
+
basic_memory-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
89
|
+
basic_memory-0.8.0.dist-info/entry_points.txt,sha256=IDQa_VmVTzmvMrpnjhEfM0S3F--XsVGEj3MpdJfuo-Q,59
|
|
90
|
+
basic_memory-0.8.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
91
|
+
basic_memory-0.8.0.dist-info/RECORD,,
|
basic_memory/alembic/README
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Generic single-database configuration.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""Schemas for knowledge discovery and analytics endpoints."""
|
|
2
|
-
|
|
3
|
-
from typing import List, Optional
|
|
4
|
-
from pydantic import BaseModel, Field
|
|
5
|
-
|
|
6
|
-
from basic_memory.schemas.response import EntityResponse
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class EntityTypeList(BaseModel):
|
|
10
|
-
"""List of unique entity types in the system."""
|
|
11
|
-
|
|
12
|
-
types: List[str]
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class ObservationCategoryList(BaseModel):
|
|
16
|
-
"""List of unique observation categories in the system."""
|
|
17
|
-
|
|
18
|
-
categories: List[str]
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class TypedEntityList(BaseModel):
|
|
22
|
-
"""List of entities of a specific type."""
|
|
23
|
-
|
|
24
|
-
entity_type: str = Field(..., description="Type of entities in the list")
|
|
25
|
-
entities: List[EntityResponse]
|
|
26
|
-
total: int = Field(..., description="Total number of entities")
|
|
27
|
-
sort_by: Optional[str] = Field(None, description="Field used for sorting")
|
|
28
|
-
include_related: bool = Field(False, description="Whether related entities are included")
|