mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
improve validation for memory:// urls, add examples to build_context
Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
@@ -13,7 +13,6 @@ from basic_memory.schemas.memory import (
|
||||
GraphContext,
|
||||
MemoryUrl,
|
||||
memory_url_path,
|
||||
normalize_memory_url,
|
||||
)
|
||||
|
||||
|
||||
@@ -21,12 +20,17 @@ from basic_memory.schemas.memory import (
|
||||
description="""Build context from a memory:// URI to continue conversations naturally.
|
||||
|
||||
Use this to follow up on previous discussions or explore related topics.
|
||||
|
||||
Memory URL Format:
|
||||
- Use paths like "folder/note" or "memory://folder/note"
|
||||
- Pattern matching: "folder/*" matches all notes in folder
|
||||
- Valid characters: letters, numbers, hyphens, underscores, forward slashes
|
||||
- Avoid: double slashes (//), angle brackets (<>), quotes, pipes (|)
|
||||
- Examples: "specs/search", "projects/basic-memory", "notes/*"
|
||||
|
||||
Timeframes support natural language like:
|
||||
- "2 days ago"
|
||||
- "last week"
|
||||
- "today"
|
||||
- "3 months ago"
|
||||
Or standard formats like "7d", "24h"
|
||||
- "2 days ago", "last week", "today", "3 months ago"
|
||||
- Or standard formats like "7d", "24h"
|
||||
""",
|
||||
)
|
||||
async def build_context(
|
||||
@@ -76,7 +80,7 @@ async def build_context(
|
||||
build_context("memory://specs/search", project="work-project")
|
||||
"""
|
||||
logger.info(f"Building context from {url}")
|
||||
url = normalize_memory_url(url)
|
||||
# URL is already validated and normalized by MemoryUrl type annotation
|
||||
|
||||
active_project = get_active_project(project)
|
||||
project_url = active_project.project_url
|
||||
|
||||
@@ -35,7 +35,8 @@ async def canvas(
|
||||
nodes: List of node objects following JSON Canvas 1.0 spec
|
||||
edges: List of edge objects following JSON Canvas 1.0 spec
|
||||
title: The title of the canvas (will be saved as title.canvas)
|
||||
folder: The folder where the file should be saved
|
||||
folder: Folder path relative to project root where the canvas should be saved.
|
||||
Use forward slashes (/) as separators. Examples: "diagrams", "projects/2025", "visual/maps"
|
||||
project: Optional project name to create canvas in. If not provided, uses current active project.
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -54,7 +54,8 @@ async def write_note(
|
||||
Args:
|
||||
title: The title of the note
|
||||
content: Markdown content for the note, can include observations and relations
|
||||
folder: the folder where the file should be saved
|
||||
folder: Folder path relative to project root where the file should be saved.
|
||||
Use forward slashes (/) as separators. Examples: "notes", "projects/2025", "research/ml"
|
||||
tags: Tags to categorize the note. Can be a list of strings, a comma-separated string, or None.
|
||||
Note: If passing from external MCP clients, use a string format (e.g. "tag1,tag2,tag3")
|
||||
project: Optional project name to write to. If not provided, uses current active project.
|
||||
|
||||
@@ -9,8 +9,44 @@ from pydantic import BaseModel, Field, BeforeValidator, TypeAdapter
|
||||
from basic_memory.schemas.search import SearchItemType
|
||||
|
||||
|
||||
def validate_memory_url_path(path: str) -> bool:
|
||||
"""Validate that a memory URL path is well-formed.
|
||||
|
||||
Args:
|
||||
path: The path part of a memory URL (without memory:// prefix)
|
||||
|
||||
Returns:
|
||||
True if the path is valid, False otherwise
|
||||
|
||||
Examples:
|
||||
>>> validate_memory_url_path("specs/search")
|
||||
True
|
||||
>>> validate_memory_url_path("memory//test") # Double slash
|
||||
False
|
||||
>>> validate_memory_url_path("invalid://test") # Contains protocol
|
||||
False
|
||||
"""
|
||||
if not path or not path.strip():
|
||||
return False
|
||||
|
||||
# Check for invalid protocol schemes within the path first (more specific)
|
||||
if "://" in path:
|
||||
return False
|
||||
|
||||
# Check for double slashes (except at the beginning for absolute paths)
|
||||
if "//" in path:
|
||||
return False
|
||||
|
||||
# Check for invalid characters (excluding * which is used for pattern matching)
|
||||
invalid_chars = {"<", ">", '"', "|", "?"}
|
||||
if any(char in path for char in invalid_chars):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def normalize_memory_url(url: str | None) -> str:
|
||||
"""Normalize a MemoryUrl string.
|
||||
"""Normalize a MemoryUrl string with validation.
|
||||
|
||||
Args:
|
||||
url: A path like "specs/search" or "memory://specs/search"
|
||||
@@ -18,22 +54,43 @@ def normalize_memory_url(url: str | None) -> str:
|
||||
Returns:
|
||||
Normalized URL starting with memory://
|
||||
|
||||
Raises:
|
||||
ValueError: If the URL path is malformed
|
||||
|
||||
Examples:
|
||||
>>> normalize_memory_url("specs/search")
|
||||
'memory://specs/search'
|
||||
>>> normalize_memory_url("memory://specs/search")
|
||||
'memory://specs/search'
|
||||
>>> normalize_memory_url("memory//test")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Invalid memory URL path: 'memory//test' contains double slashes
|
||||
"""
|
||||
if not url:
|
||||
return ""
|
||||
|
||||
clean_path = url.removeprefix("memory://")
|
||||
|
||||
# Validate the extracted path
|
||||
if not validate_memory_url_path(clean_path):
|
||||
# Provide specific error messages for common issues
|
||||
if "://" in clean_path:
|
||||
raise ValueError(f"Invalid memory URL path: '{clean_path}' contains protocol scheme")
|
||||
elif "//" in clean_path:
|
||||
raise ValueError(f"Invalid memory URL path: '{clean_path}' contains double slashes")
|
||||
elif not clean_path.strip():
|
||||
raise ValueError("Memory URL path cannot be empty or whitespace")
|
||||
else:
|
||||
raise ValueError(f"Invalid memory URL path: '{clean_path}' contains invalid characters")
|
||||
|
||||
return f"memory://{clean_path}"
|
||||
|
||||
|
||||
MemoryUrl = Annotated[
|
||||
str,
|
||||
BeforeValidator(str.strip), # Clean whitespace
|
||||
BeforeValidator(normalize_memory_url), # Validate and normalize the URL
|
||||
MinLen(1),
|
||||
MaxLen(2028),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user