Skip to main content
Glama
utils.py3.8 kB
"""Utilities for converting between markdown and entity models.""" from pathlib import Path from typing import Any, Optional import logfire from frontmatter import Post from basic_memory.file_utils import has_frontmatter, remove_frontmatter, parse_frontmatter from basic_memory.markdown import EntityMarkdown from basic_memory.models import Entity from basic_memory.models import Observation as ObservationModel @logfire.instrument() def entity_model_from_markdown( file_path: Path, markdown: EntityMarkdown, entity: Optional[Entity] = None, project_id: Optional[int] = None, ) -> Entity: """ Convert markdown entity to model. Does not include relations. Args: file_path: Path to the markdown file markdown: Parsed markdown entity entity: Optional existing entity to update project_id: Project ID for new observations (uses entity.project_id if not provided) Returns: Entity model populated from markdown Raises: ValueError: If required datetime fields are missing from markdown """ if not markdown.created or not markdown.modified: # pragma: no cover raise ValueError("Both created and modified dates are required in markdown") # Create or update entity model = entity or Entity() # Update basic fields model.title = markdown.frontmatter.title model.entity_type = markdown.frontmatter.type # Only update permalink if it exists in frontmatter, otherwise preserve existing if markdown.frontmatter.permalink is not None: model.permalink = markdown.frontmatter.permalink model.file_path = file_path.as_posix() model.content_type = "text/markdown" model.created_at = markdown.created model.updated_at = markdown.modified # Handle metadata - ensure all values are strings and filter None metadata = markdown.frontmatter.metadata or {} model.entity_metadata = {k: str(v) for k, v in metadata.items() if v is not None} # Get project_id from entity if not provided obs_project_id = project_id or (model.project_id if hasattr(model, "project_id") else None) # Convert observations model.observations = [ ObservationModel( project_id=obs_project_id, content=obs.content, category=obs.category, context=obs.context, tags=obs.tags, ) for obs in markdown.observations ] return model @logfire.instrument() async def schema_to_markdown(schema: Any) -> Post: """ Convert schema to markdown Post object. Args: schema: Schema to convert (must have title, entity_type, and permalink attributes) Returns: Post object with frontmatter metadata """ # Extract content and metadata content = schema.content or "" entity_metadata = dict(schema.entity_metadata or {}) # if the content contains frontmatter, remove it and merge if has_frontmatter(content): content_frontmatter = parse_frontmatter(content) content = remove_frontmatter(content) # Merge content frontmatter with entity metadata # (entity_metadata takes precedence for conflicts) content_frontmatter.update(entity_metadata) entity_metadata = content_frontmatter # Remove special fields for ordered frontmatter for field in ["type", "title", "permalink"]: entity_metadata.pop(field, None) # Create Post with fields ordered by insert order post = Post( content, title=schema.title, type=schema.entity_type, ) # set the permalink if passed in if schema.permalink: post.metadata["permalink"] = schema.permalink if entity_metadata: post.metadata.update(entity_metadata) return post

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/basicmachines-co/basic-memory'

If you have feedback or need assistance with the MCP directory API, please join our Discord server