feat: Add enhanced prompts and resources (#15)

## Summary
- Add comprehensive documentation to all MCP prompt modules
- Enhance search prompt with detailed contextual output formatting
- Implement consistent logging and docstring patterns across prompt
utilities
- Fix type checking in prompt modules

## Prompts Added/Enhanced
- `search.py`: New formatted output with relevance scores, excerpts, and
next steps
- `recent_activity.py`: Enhanced with better metadata handling and
documentation
- `continue_conversation.py`: Improved context management

## Resources Added/Enhanced
- `ai_assistant_guide`: Resource with description to give to LLM to
understand how to use the tools

## Technical improvements
- Added detailed docstrings to all prompt modules explaining their
purpose and usage
- Enhanced the search prompt with rich contextual output that helps LLMs
understand results
- Created a consistent pattern for formatting output across prompts
- Improved error handling in metadata extraction
- Standardized import organization and naming conventions
- Fixed various type checking issues across the codebase

This PR is part of our ongoing effort to improve the MCP's interaction
quality with LLMs, making the system more helpful and intuitive for AI
assistants to navigate knowledge bases.

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: phernandez <phernandez@basicmachines.co>
This commit is contained in:
Paul Hernandez
2025-02-27 20:48:56 -06:00
committed by GitHub
parent 0d7b0b3d7e
commit 093dab5f03
36 changed files with 1756 additions and 356 deletions
+1 -1
View File
@@ -196,7 +196,7 @@ def sync(
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
logger.exception("Sync failed")
logger.exception("Sync failed", e)
typer.echo(f"Error during sync: {e}", err=True)
raise typer.Exit(1)
raise
+32 -9
View File
@@ -1,9 +1,10 @@
"""Database management commands."""
"""CLI tool commands for Basic Memory."""
import asyncio
from typing import Optional, List, Annotated
import typer
from loguru import logger
from rich import print as rprint
from basic_memory.cli.app import app
@@ -13,9 +14,15 @@ from basic_memory.mcp.tools import read_note as mcp_read_note
from basic_memory.mcp.tools import recent_activity as mcp_recent_activity
from basic_memory.mcp.tools import search as mcp_search
from basic_memory.mcp.tools import write_note as mcp_write_note
# Import prompts
from basic_memory.mcp.prompts.continue_conversation import (
continue_conversation as mcp_continue_conversation,
)
from basic_memory.schemas.base import TimeFrame
from basic_memory.schemas.memory import MemoryUrl
from basic_memory.schemas.search import SearchQuery
from basic_memory.schemas.search import SearchQuery, SearchItemType
tool_app = typer.Typer()
app.add_typer(tool_app, name="tools", help="cli versions mcp tools")
@@ -82,18 +89,13 @@ def build_context(
@tool_app.command()
def recent_activity(
type: Annotated[Optional[List[str]], typer.Option()] = ["entity", "observation", "relation"],
type: Annotated[Optional[List[SearchItemType]], typer.Option()] = None,
depth: Optional[int] = 1,
timeframe: Optional[TimeFrame] = "7d",
page: int = 1,
page_size: int = 10,
max_related: int = 10,
):
assert type is not None, "type is required"
if any(t not in ["entity", "observation", "relation"] for t in type): # pragma: no cover
print("type must be one of ['entity', 'observation', 'relation']")
raise typer.Abort()
try:
context = asyncio.run(
mcp_recent_activity(
@@ -132,7 +134,7 @@ def search(
try:
search_query = SearchQuery(
permalink_match=query if permalink else None,
text=query if query else None,
text=query if not (permalink or title) else None,
title=query if title else None,
after_date=after_date,
)
@@ -140,6 +142,7 @@ def search(
rprint(results.model_dump_json(indent=2))
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
logger.exception("Error during search", e)
typer.echo(f"Error during search: {e}", err=True)
raise typer.Exit(1)
raise
@@ -155,3 +158,23 @@ def get_entity(identifier: str):
typer.echo(f"Error during get_entity: {e}", err=True)
raise typer.Exit(1)
raise
@tool_app.command(name="continue-conversation")
def continue_conversation(
topic: Annotated[Optional[str], typer.Option(help="Topic or keyword to search for")] = None,
timeframe: Annotated[
Optional[str], typer.Option(help="How far back to look for activity")
] = None,
):
"""Continue a previous conversation or work session."""
try:
# Prompt functions return formatted strings directly
session = asyncio.run(mcp_continue_conversation(topic=topic, timeframe=timeframe))
rprint(session)
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
logger.exception("Error continuing conversation", e)
typer.echo(f"Error continuing conversation: {e}", err=True)
raise typer.Exit(1)
raise