basic-memory 0.23.1.dev20__py3-none-any.whl → 0.23.1.dev27__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.
@@ -22,6 +22,62 @@ def upgrade() -> None:
22
22
  """Index complete note bodies as bounded PostgreSQL FTS chunks."""
23
23
  connection = op.get_bind()
24
24
  if connection.dialect.name == "postgresql":
25
+ # --- Repair: recreate search_index if a destructive reindex removed it ---
26
+ # Trigger: search_index does not exist. Through v0.23.0, the per-project
27
+ # search reindex ran DROP TABLE IF EXISTS search_index, and on Postgres
28
+ # nothing outside migrations recreates that table.
29
+ # Why: the chunk backfill below reads search_index and the chunks table
30
+ # declares a foreign key to it, so without repair this migration fails
31
+ # permanently and blocks the database from ever reaching head.
32
+ # Outcome: healthy databases no-op on IF NOT EXISTS; a repaired database
33
+ # gets an empty index that the next full reindex repopulates. The DDL
34
+ # mirrors the current schema in models/search.py.
35
+ op.execute("""
36
+ CREATE TABLE IF NOT EXISTS search_index (
37
+ id INTEGER NOT NULL,
38
+ project_id INTEGER NOT NULL,
39
+ title TEXT,
40
+ content_stems TEXT,
41
+ content_snippet TEXT,
42
+ permalink VARCHAR,
43
+ file_path VARCHAR,
44
+ type VARCHAR,
45
+ from_id INTEGER,
46
+ to_id INTEGER,
47
+ relation_type VARCHAR,
48
+ entity_id INTEGER,
49
+ category VARCHAR,
50
+ metadata JSONB,
51
+ created_at TIMESTAMP WITH TIME ZONE,
52
+ updated_at TIMESTAMP WITH TIME ZONE,
53
+ textsearchable_index_col tsvector GENERATED ALWAYS AS (
54
+ to_tsvector(
55
+ 'english',
56
+ coalesce(title, '') || ' ' ||
57
+ coalesce(content_stems, '')
58
+ )
59
+ ) STORED,
60
+ PRIMARY KEY (id, type, project_id),
61
+ FOREIGN KEY (project_id) REFERENCES project(id) ON DELETE CASCADE
62
+ )
63
+ """)
64
+ op.execute("""
65
+ CREATE INDEX IF NOT EXISTS ix_search_index_project_id
66
+ ON search_index (project_id)
67
+ """)
68
+ op.execute("""
69
+ CREATE INDEX IF NOT EXISTS idx_search_index_fts
70
+ ON search_index USING gin(textsearchable_index_col)
71
+ """)
72
+ op.execute("""
73
+ CREATE INDEX IF NOT EXISTS idx_search_index_metadata_gin
74
+ ON search_index USING gin(metadata jsonb_path_ops)
75
+ """)
76
+ op.execute("""
77
+ CREATE UNIQUE INDEX IF NOT EXISTS uix_search_index_permalink_project
78
+ ON search_index (permalink, project_id)
79
+ WHERE permalink IS NOT NULL
80
+ """)
25
81
  op.execute("""
26
82
  CREATE TABLE search_index_fts_chunks (
27
83
  project_id INTEGER NOT NULL,
@@ -221,6 +221,28 @@ async def add_project(
221
221
  raise HTTPException(status_code=400, detail=str(e))
222
222
 
223
223
 
224
+ @router.post("/doctor", response_model=ProjectStatusResponse, status_code=201)
225
+ async def add_doctor_project(project_service: ProjectServiceDep) -> ProjectStatusResponse:
226
+ """Create a server-generated disposable project for the local doctor check."""
227
+ try:
228
+ new_project = await project_service.add_doctor_project()
229
+ except ValueError as e:
230
+ raise HTTPException(status_code=400, detail=str(e))
231
+
232
+ return ProjectStatusResponse(
233
+ message=f"Project '{new_project.name}' added successfully",
234
+ status="success",
235
+ default=new_project.is_default or False,
236
+ new_project=ProjectItem(
237
+ id=new_project.id,
238
+ external_id=new_project.external_id,
239
+ name=new_project.name,
240
+ path=new_project.path,
241
+ is_default=new_project.is_default or False,
242
+ ),
243
+ )
244
+
245
+
224
246
  @router.post("/config/sync", response_model=ProjectStatusResponse)
225
247
  async def synchronize_projects(
226
248
  project_service: ProjectServiceDep,
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import tempfile
6
6
  import uuid
7
7
  from pathlib import Path
8
+ from typing import Protocol
8
9
 
9
10
  from loguru import logger
10
11
  from rich.console import Console
@@ -23,6 +24,14 @@ from basic_memory.schemas import ProjectIndexRunResponse
23
24
  console = Console()
24
25
 
25
26
 
27
+ class DoctorProjectClient(Protocol):
28
+ """Project-client capability required to clean up doctor state."""
29
+
30
+ async def delete_project(
31
+ self, project_external_id: str, delete_notes: bool = False
32
+ ) -> object: ...
33
+
34
+
26
35
  def _is_default_project_delete_error(error: Exception) -> bool:
27
36
  """Return True only for the API guard that blocks deleting the default project."""
28
37
  error_text = str(error)
@@ -61,14 +70,14 @@ async def _delete_doctor_project_locally(project_name: str, project_id: str) ->
61
70
 
62
71
 
63
72
  async def _delete_doctor_project(
64
- project_client: ProjectClient, project_name: str, project_id: str
73
+ project_client: DoctorProjectClient, project_name: str, project_id: str
65
74
  ) -> None:
66
75
  """Delete the generated doctor project without weakening the public API guard."""
67
76
  # Deferred: ToolError lives in FastMCP's runtime, which must not load at CLI startup (#886).
68
77
  from fastmcp.exceptions import ToolError
69
78
 
70
79
  try:
71
- await project_client.delete_project(project_id)
80
+ await project_client.delete_project(project_id, delete_notes=True)
72
81
  except ToolError as exc:
73
82
  if not _is_default_project_delete_error(exc):
74
83
  raise
@@ -127,9 +136,16 @@ async def run_doctor() -> None:
127
136
  project_id: str | None = None
128
137
 
129
138
  try:
130
- status = await project_client.create_project(project_request.model_dump())
139
+ from basic_memory.config import ConfigManager
140
+
141
+ status = (
142
+ await project_client.create_doctor_project()
143
+ if ConfigManager().config.project_root
144
+ else await project_client.create_project(project_request.model_dump())
145
+ )
131
146
  if not status.new_project:
132
147
  raise ValueError("Failed to create doctor project")
148
+ project_name = status.new_project.name
133
149
  project_id = status.new_project.external_id
134
150
  # Use the resolved path from the server — when project_root is configured,
135
151
  # the actual project directory differs from the requested temp_path
@@ -78,6 +78,13 @@ class ProjectClient:
78
78
  )
79
79
  return ProjectStatusResponse.model_validate(response.json())
80
80
 
81
+ async def create_doctor_project(self) -> ProjectStatusResponse:
82
+ """Create the server-generated disposable project used by doctor."""
83
+ from basic_memory.mcp.tools.utils import call_post
84
+
85
+ response = await call_post(self.http_client, "/v2/projects/doctor")
86
+ return ProjectStatusResponse.model_validate(response.json())
87
+
81
88
  async def delete_project(
82
89
  self, project_external_id: str, delete_notes: bool = False
83
90
  ) -> ProjectStatusResponse:
@@ -129,6 +129,10 @@ class SearchRepository(Protocol):
129
129
  """Delete item by permalink."""
130
130
  ...
131
131
 
132
+ async def delete_project_search_rows(self) -> None:
133
+ """Delete every full-text search row owned by this project."""
134
+ ...
135
+
132
136
  async def delete_by_entity_id(self, entity_id: int) -> None:
133
137
  """Delete items by entity ID."""
134
138
  ...
@@ -1143,6 +1143,21 @@ class SearchRepositoryBase(ABC):
1143
1143
  )
1144
1144
  await session.commit()
1145
1145
 
1146
+ async def delete_project_search_rows(self) -> None:
1147
+ """Delete every full-text search row owned by this repository's project.
1148
+
1149
+ Shared across backends: both store rows in `search_index` keyed by
1150
+ project_id, and a project-scoped DELETE leaves sibling projects in the
1151
+ same database untouched. On Postgres the bounded FTS chunk rows follow
1152
+ via their ON DELETE CASCADE foreign key.
1153
+ """
1154
+ async with db.scoped_session(self.session_maker) as session:
1155
+ await session.execute(
1156
+ text("DELETE FROM search_index WHERE project_id = :project_id"),
1157
+ {"project_id": self.project_id},
1158
+ )
1159
+ await session.commit()
1160
+
1146
1161
  async def execute_query(
1147
1162
  self,
1148
1163
  query: Executable,
@@ -4,6 +4,7 @@ import asyncio
4
4
  import json
5
5
  import os
6
6
  import shutil
7
+ import uuid
7
8
  from collections.abc import Callable
8
9
  from datetime import datetime
9
10
  from pathlib import Path
@@ -190,7 +191,9 @@ class ProjectService:
190
191
  # Not nested in either direction
191
192
  return False
192
193
 
193
- async def add_project(self, name: str, path: str, set_default: bool = False) -> None:
194
+ async def add_project(
195
+ self, name: str, path: str, set_default: bool = False, *, allow_nested: bool = False
196
+ ) -> None:
194
197
  """Add a new project to the configuration and database.
195
198
 
196
199
  Args:
@@ -240,27 +243,25 @@ class ProjectService:
240
243
  f"In cloud mode, paths are normalized to lowercase to prevent case-sensitivity issues."
241
244
  ) # pragma: no cover
242
245
 
243
- # Check for nested paths with existing projects
244
- for existing in existing_projects:
245
- if self._check_nested_paths(resolved_path, existing.path):
246
- # Determine which path is nested within which for appropriate error message
247
- p_new = Path(resolved_path).resolve()
248
- p_existing = Path(existing.path).resolve()
249
-
250
- # Check if new path is nested under existing project
251
- if p_new.is_relative_to(p_existing):
252
- raise ValueError(
253
- f"Cannot create project at '{resolved_path}': "
254
- f"path is nested within existing project '{existing.name}' at '{existing.path}'. "
255
- f"Projects cannot share directory trees."
256
- )
257
- else:
258
- # Existing project is nested under new path
259
- raise ValueError(
260
- f"Cannot create project at '{resolved_path}': "
261
- f"existing project '{existing.name}' at '{existing.path}' is nested within this path. "
262
- f"Projects cannot share directory trees."
263
- )
246
+ # Doctor creates a disposable project inside the configured project root.
247
+ # It must be allowed to coexist with the existing root project.
248
+ if not allow_nested:
249
+ for existing in existing_projects:
250
+ if self._check_nested_paths(resolved_path, existing.path):
251
+ p_new = Path(resolved_path).resolve()
252
+ p_existing = Path(existing.path).resolve()
253
+ if p_new.is_relative_to(p_existing):
254
+ raise ValueError(
255
+ f"Cannot create project at '{resolved_path}': "
256
+ f"path is nested within existing project '{existing.name}' at '{existing.path}'. "
257
+ f"Projects cannot share directory trees."
258
+ )
259
+ else:
260
+ raise ValueError(
261
+ f"Cannot create project at '{resolved_path}': "
262
+ f"existing project '{existing.name}' at '{existing.path}' is nested within this path. "
263
+ f"Projects cannot share directory trees."
264
+ )
264
265
 
265
266
  # Ensure the project directory exists on disk.
266
267
  # Trigger: project_root not set means local filesystem mode (not S3/cloud)
@@ -332,6 +333,19 @@ class ProjectService:
332
333
 
333
334
  logger.info(f"Project '{name}' added at {resolved_path}")
334
335
 
336
+ async def add_doctor_project(self) -> Project:
337
+ """Create a server-generated disposable project under the configured root."""
338
+ project_root = self.config_manager.config.project_root
339
+ if not project_root:
340
+ raise ValueError("Doctor projects require BASIC_MEMORY_PROJECT_ROOT")
341
+
342
+ project_name = f"doctor-{uuid.uuid4().hex[:8]}"
343
+ await self.add_project(project_name, project_root, allow_nested=True)
344
+ project = await self.get_project(project_name)
345
+ if project is None: # pragma: no cover
346
+ raise ValueError("Failed to retrieve doctor project")
347
+ return project
348
+
335
349
  async def remove_project(self, name: str, delete_notes: bool = False) -> None:
336
350
  """Remove a project from configuration and database.
337
351
 
@@ -11,7 +11,6 @@ from typing import Any, List, Optional, Set, Dict
11
11
  from dateparser import parse
12
12
  from fastapi import BackgroundTasks
13
13
  from loguru import logger
14
- from sqlalchemy import text
15
14
  from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
16
15
 
17
16
  import logfire
@@ -152,11 +151,20 @@ class SearchService:
152
151
  logger.info("Starting full reindex")
153
152
  # Trigger: a full search rebuild removes every derived row.
154
153
  # Why: vector storage may live outside SQL, so cleanup must cross the
155
- # repository boundary before the full-text table is recreated.
154
+ # repository boundary before the full-text rows are rebuilt.
156
155
  # Outcome: built-in and extension indexes follow the same lifecycle.
157
156
  await self.repository.delete_project_vector_rows()
158
- await self.repository.execute_query(text("DROP TABLE IF EXISTS search_index"), params={})
157
+ # Trigger: this service reindexes exactly one project, but search_index
158
+ # is shared by every project in the database (local SQLite consolidated
159
+ # into one memory.db; cloud tenants share one Postgres DB across
160
+ # projects). The historical DROP TABLE here dated from the one-database-
161
+ # per-project era and destroyed sibling projects' rows — on Postgres it
162
+ # also left nothing behind, since only migrations recreate the table.
163
+ # Why: a project-scoped DELETE clears only rows this rebuild will
164
+ # repopulate, and on Postgres the FTS chunk rows cascade with them.
165
+ # Outcome: sibling projects keep serving search while this one rebuilds.
159
166
  await self.init_search_index()
167
+ await self.repository.delete_project_search_rows()
160
168
 
161
169
  # Reindex all entities
162
170
  logger.debug("Indexing entities")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: basic-memory
3
- Version: 0.23.1.dev20
3
+ Version: 0.23.1.dev27
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
@@ -23,7 +23,7 @@ basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink
23
23
  basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py,sha256=xTSVvB-caYl_CdVfzhj-eqdQEOxQ12NIHOc8dBSqCMQ,4779
24
24
  basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py,sha256=oFtjzJd37HUMezuCUonK-yRc867_9L5zxd4CnLhFIi4,4655
25
25
  basic_memory/alembic/versions/6830751f5fb6_merge_multiple_heads.py,sha256=8bO4yg_v6klCJz0E15sDI2pDtsmAL2nNO5ACpKGLYQo,499
26
- basic_memory/alembic/versions/7f6a2b8c9d10_index_full_postgres_note_content.py,sha256=Kf4-_uBKe28MbpbKPsxZEKQzCYpIxv79iWxbKUZI91w,2857
26
+ basic_memory/alembic/versions/7f6a2b8c9d10_index_full_postgres_note_content.py,sha256=0Ipk-T-7LiA8-ExBr-mz-zqKHvH9QI0G33zdWtnREHo,5414
27
27
  basic_memory/alembic/versions/9d9c1cb7d8f5_add_mtime_and_size_columns_to_entity_.py,sha256=DYlXlRYO3Ms6x9GbrFGWgj1QEzsdKHx-4AA4lSVM7y0,1587
28
28
  basic_memory/alembic/versions/a1b2c3d4e5f6_fix_project_foreign_keys.py,sha256=i42eQyO08RWf4exnH1q1PKw_EJFsHAG-T4pdLTMSpiA,1818
29
29
  basic_memory/alembic/versions/a2b3c4d5e6f7_add_search_index_entity_cascade.py,sha256=Oh_J5Jw85J3LvknfizFP7_1SoelZM_A7IjBau8lRpfk,1671
@@ -56,7 +56,7 @@ basic_memory/api/v2/routers/importer_router.py,sha256=LHdi0q7FKKTeynMl4qg4itOw51
56
56
  basic_memory/api/v2/routers/inspect_router.py,sha256=4QDM89AzWShF1UTE6CDjX1R8_4aNs3DIm4SpUUsbWzA,8637
57
57
  basic_memory/api/v2/routers/knowledge_router.py,sha256=-irLLXtYTUtlbqjHUwN6OhWn1jG8SN9mbeUp3uOUpwk,49572
58
58
  basic_memory/api/v2/routers/memory_router.py,sha256=2BvV7zA_39Ld3ySjY5twy7AzaMncn70fUVN7IdhGX_o,7308
59
- basic_memory/api/v2/routers/project_router.py,sha256=8pHBw3UmVx0CPWr1eCJWHquK0oV3LzTOGTYBtohzFi4,24886
59
+ basic_memory/api/v2/routers/project_router.py,sha256=LGXW0ijvz68jZw0I5AWpXKfAOUgu2egDQymMFGJql88,25737
60
60
  basic_memory/api/v2/routers/prompt_router.py,sha256=QE69XMKE6MB-yhzvr1mONkkeBZwKA_Ui9Kt-5ZVKvdY,10449
61
61
  basic_memory/api/v2/routers/resource_router.py,sha256=t_tXxqGgxYJqcPFKU9jbFBhJzSIjTnfzo6SQMGFV2Mo,7571
62
62
  basic_memory/api/v2/routers/schema_router.py,sha256=B_T2OXXFKvC-VaBzzDa2IbBmIHnJr_fPN43_8n9rMYo,22254
@@ -77,7 +77,7 @@ basic_memory/cli/commands/ci.py,sha256=MW4pepm9472iMzbryA4p-r-SG-OPnFftshB-0S8LB
77
77
  basic_memory/cli/commands/command_utils.py,sha256=9_xUeeg1-nsnUw3MdNXOc_rhVROqhXqEDcTD3E_ga3A,5008
78
78
  basic_memory/cli/commands/config.py,sha256=8IBqPrcgklhvHkVFG8v9laO0PqZkvfLsZ_jgbPkFCb4,8700
79
79
  basic_memory/cli/commands/db.py,sha256=aQcjHpff15pfpDTKKpV-zz38TIJNfkOFQsCWggqbbU8,22596
80
- basic_memory/cli/commands/doctor.py,sha256=84AifKWTxcCibUOkZvJQ8P7PKuPK_P36KLy5d6aNvsQ,10755
80
+ basic_memory/cli/commands/doctor.py,sha256=51fp0Keazaid-KPaIKaR9xKU9ELSALxFurvXKNuVnVo,11324
81
81
  basic_memory/cli/commands/format.py,sha256=pgXkk0ptU2quN0XzjURuapA5AqrIBu1y4j6J1t52ovI,6753
82
82
  basic_memory/cli/commands/hook.py,sha256=tNtGzf4E40bhZQL6-SJwQpq8ehQmxm7EIae7O7-3jJg,60641
83
83
  basic_memory/cli/commands/import_chatgpt.py,sha256=7SUGG_mmme0BuL4ov0lhb98VkTUldunCv-ehQirtwZE,3870
@@ -224,7 +224,7 @@ basic_memory/mcp/clients/directory.py,sha256=C_fY7xo300ceF-heRBAktv7OffEnNAuPWx1
224
224
  basic_memory/mcp/clients/inspect.py,sha256=TtiEOiJITDuFLtrdwMcoY-XBNuCK4C3NobzpQHdHoRU,2311
225
225
  basic_memory/mcp/clients/knowledge.py,sha256=DtEsAkqCtZFc-v93KIuPyOFCRLFbbOQGPqEwOSMJytw,13757
226
226
  basic_memory/mcp/clients/memory.py,sha256=qKSjKS7jJOKu7y-Lldsm561KU0G9OpRzA0tLf7l9FmI,4794
227
- basic_memory/mcp/clients/project.py,sha256=rYYtw58rSwuie_JIwWZ6Wdx2Y6JCQ70NNb79UNcf6hw,7604
227
+ basic_memory/mcp/clients/project.py,sha256=0er3M6QMjepuKpbn4G6oz7IuVf4veQhDTHJL6iUE09c,7955
228
228
  basic_memory/mcp/clients/resource.py,sha256=_FI7bOBAQwlEuv24wU1tsGIFR-riHcemgZSMJqOLBN4,2218
229
229
  basic_memory/mcp/clients/schema.py,sha256=OnLDJnh-8OkELdMVDRBObjOsGfgaDzroryjzSP8aWyc,3618
230
230
  basic_memory/mcp/clients/search.py,sha256=I7mJxVaQ8-igJzuMzxYaZgHGCwJAkjMHf2QIgYuZBjI,3030
@@ -317,8 +317,8 @@ basic_memory/repository/rerank_provider.py,sha256=JnMXexhMOv93gJ3UQkkUE6tQyJWdph
317
317
  basic_memory/repository/rerank_provider_factory.py,sha256=JlPHD0YdAWSima7gGkheiTnGhEn2j5JPB09MZDuhoj0,4735
318
318
  basic_memory/repository/search_index_row.py,sha256=bTF7-tiz91HySchZfdP1dZbUNW7WU2KNgG1s1mnRBWc,5335
319
319
  basic_memory/repository/search_query.py,sha256=0Kh1IDMXCUza-uTKej5wCu-TjHKhA8j-MCzQ0-abvpA,13949
320
- basic_memory/repository/search_repository.py,sha256=U6okrNaxDqEHYIwLNYyZPPtDimiiqmZO1U6CPrXgrHQ,9555
321
- basic_memory/repository/search_repository_base.py,sha256=GUEI39CYuAai87m6woEhCyYKrMZ9THuTdEqhoLB02DU,119986
320
+ basic_memory/repository/search_repository.py,sha256=Cpgn1feacMtxbm7BhaWf_FMS__Gn7WiIAnovYJX7-Ao,9695
321
+ basic_memory/repository/search_repository_base.py,sha256=7olsUTL0nI-4vkspTViJZbvqIfDPxGho34D3vmILpdo,120702
322
322
  basic_memory/repository/search_trace.py,sha256=OLcUJ-4GBva1zgNPBlNA1BThpUJo77YsW5H-0j3zqy4,20613
323
323
  basic_memory/repository/semantic_chunking.py,sha256=7xTmL7vt_6vBSYJYeio6s7nTkvW8AdQ9sok1HIY5GWE,8427
324
324
  basic_memory/repository/semantic_errors.py,sha256=1v0jz9aBkephpVc4FcX3xIQvgk5jnkO9VpZhPM7AdIc,996
@@ -385,14 +385,14 @@ basic_memory/services/note_content_reads.py,sha256=3o6GI2VJFkA5PScQD4IlZDO_4rcXL
385
385
  basic_memory/services/note_content_writes.py,sha256=wqnPnaUII2k_xlTBYMZAVlrc7zGX13M3el334F6z6hY,20530
386
386
  basic_memory/services/note_preparation.py,sha256=POGmk0L_9a-eLIMmXmuKtN81QRabF0JyipZiIz0eNqY,38262
387
387
  basic_memory/services/project_deletes.py,sha256=bnq8la1ZKsZEkcAg3Ew2onXHku9CWChr-BWDZA6lvuI,6010
388
- basic_memory/services/project_service.py,sha256=JB-pNRZfRhVGIRUlSt7IiI-BllxgFs8A7xtGK3klFcA,61803
388
+ basic_memory/services/project_service.py,sha256=E6rpEwKz6ihynZjXxBlvxUbG69YqE8jxOgBI3zT1XWQ,62460
389
389
  basic_memory/services/retrieval_inspect.py,sha256=gJq94oYV6ISeh-JeUAB8srMw8K3oGeMgzVXEOWAEzxA,23844
390
- basic_memory/services/search_service.py,sha256=OcT2wMn7rN1GQ_0l8OH8KKcoTG4D7-EvfqPulss01NA,39618
390
+ basic_memory/services/search_service.py,sha256=8A1vXo5IIpKXL2gxEsCEP_tcKyRcnz4R5xb6zijRuW0,40254
391
391
  basic_memory/services/service.py,sha256=V-d_8gOV07zGIQDpL-Ksqs3ZN9l3qf3HZOK1f_YNTag,336
392
392
  basic_memory/templates/prompts/continue_conversation.hbs,sha256=trrDHSXA5S0JCbInMoUJL04xvCGRB_ku1RHNQHtl6ZI,3076
393
393
  basic_memory/templates/prompts/search.hbs,sha256=H1cCIsHKp4VC1GrH2KeUB8pGe5vXFPqb2VPotypmeCA,3098
394
- basic_memory-0.23.1.dev20.dist-info/METADATA,sha256=kS21fqv6k0zvFoXQ3KaKUgv6UWpoDs_APp8C7FjTpqs,26848
395
- basic_memory-0.23.1.dev20.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
396
- basic_memory-0.23.1.dev20.dist-info/entry_points.txt,sha256=wvE2mRF6-Pg4weIYcfQ-86NOLZD4WJg7F7TIsRVFLb8,90
397
- basic_memory-0.23.1.dev20.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
398
- basic_memory-0.23.1.dev20.dist-info/RECORD,,
394
+ basic_memory-0.23.1.dev27.dist-info/METADATA,sha256=j0HNhCqLZhDGmlKdwxHIf7eWLNDXeKyhOgF8UEzKrPI,26848
395
+ basic_memory-0.23.1.dev27.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
396
+ basic_memory-0.23.1.dev27.dist-info/entry_points.txt,sha256=wvE2mRF6-Pg4weIYcfQ-86NOLZD4WJg7F7TIsRVFLb8,90
397
+ basic_memory-0.23.1.dev27.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
398
+ basic_memory-0.23.1.dev27.dist-info/RECORD,,