feat: Incremental sync on watch (#13)

- incremental sync on watch
- sync non-markdown files in knowledge base
- experimental `read_resource` tool for reading non-markdown files in raw form (pdf, image)
This commit is contained in:
Paul Hernandez
2025-02-24 22:13:15 -06:00
committed by GitHub
parent 6b8cefcd45
commit 37a01b806d
51 changed files with 2085 additions and 920 deletions
-4
View File
@@ -7,18 +7,14 @@ from fastapi import FastAPI, HTTPException
from fastapi.exception_handlers import http_exception_handler
from loguru import logger
import basic_memory
from basic_memory import db
from basic_memory.config import config as app_config
from basic_memory.api.routers import knowledge, search, memory, resource
from basic_memory.utils import setup_logging
@asynccontextmanager
async def lifespan(app: FastAPI): # pragma: no cover
"""Lifecycle manager for the FastAPI app."""
setup_logging(log_file=".basic-memory/basic-memory.log")
logger.info(f"Starting Basic Memory API {basic_memory.__version__}")
await db.run_migrations(app_config)
yield
logger.info("Shutting down Basic Memory API")
@@ -133,7 +133,7 @@ async def delete_entity(
return DeleteEntitiesResponse(deleted=False)
# Delete the entity
deleted = await entity_service.delete_entity(entity.permalink)
deleted = await entity_service.delete_entity(entity.permalink or entity.id)
# Remove from search index
background_tasks.add_task(search_service.delete_by_permalink, entity.permalink)
@@ -41,17 +41,19 @@ async def to_graph_context(context, entity_repository: EntityRepository, page: i
case SearchItemType.OBSERVATION:
assert item.category is not None
assert item.content is not None
assert item.permalink is not None
return ObservationSummary(
category=item.category, content=item.content, permalink=item.permalink
)
case SearchItemType.RELATION:
assert item.from_id is not None
assert item.permalink is not None
from_entity = await entity_repository.find_by_id(item.from_id)
assert from_entity is not None
assert from_entity.permalink is not None
to_entity = await entity_repository.find_by_id(item.to_id) if item.to_id else None
return RelationSummary(
permalink=item.permalink,
relation_type=item.type,
@@ -104,9 +106,11 @@ async def recent(
context = await context_service.build_context(
types=types, depth=depth, since=since, limit=limit, offset=offset, max_related=max_related
)
return await to_graph_context(
recent_context = await to_graph_context(
context, entity_repository=entity_repository, page=page, page_size=page_size
)
logger.debug(f"Recent context: {recent_context.model_dump_json()}")
return recent_context
# get_memory_context needs to be declared last so other paths can match