feat(core): store block metadata as YAML frontmatter in .md files (#9365)
* feat(core): store block metadata as YAML frontmatter in .md files Block .md files in git repos now embed metadata (description, limit, read_only, metadata dict) as YAML frontmatter instead of a separate metadata/blocks.json file. Only non-default values are rendered. Format: --- description: "Who I am" limit: 5000 --- Block value content here... Changes: - New block_markdown.py utility (serialize_block / parse_block_markdown) - Updated all three write/read paths: manager.py, memfs_client.py, memfs_client_base.py - block_manager_git.py now passes description/limit/read_only/metadata through to git commits - Post-push sync (git_http.py) parses frontmatter and syncs metadata fields to Postgres - Removed metadata/blocks.json reads/writes entirely - Backward compat: files without frontmatter treated as raw value - Integration test verifies frontmatter in cloned files and metadata sync via git push 🐾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta <noreply@letta.com> * fix: derive frontmatter defaults from BaseBlock schema, not hardcoded dict Remove _DEFAULTS dict from block_markdown.py. The core version now imports BaseBlock and reads field defaults via model_fields. This fixes the limit default (was 5000, should be CORE_MEMORY_BLOCK_CHAR_LIMIT=20000). Also: - memfs-py copy simplified to parse-only (no serialize, no letta imports) - All hardcoded limit=5000 fallbacks replaced with CORE_MEMORY_BLOCK_CHAR_LIMIT - Test updated: blocks with all-default metadata correctly have no frontmatter; frontmatter verified after setting non-default description via API 🐾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta <noreply@letta.com> * fix: always include description and limit in frontmatter description and limit are always rendered in the YAML frontmatter, even when at their default values. Only read_only and metadata are conditional (omitted when at defaults). 🐾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta <noreply@letta.com> * fix: resolve read_only from block_update before git commit read_only was using the old Postgres value instead of the update value when committing to git. Also adds integration test coverage for read_only: true appearing in frontmatter after API PATCH, and verifying it's omitted when false (default). 🐾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta <noreply@letta.com> * test: add API→git round-trip coverage for description and limit Verifies that PATCH description/limit via API is reflected in frontmatter after git pull. Combined with the existing push→API test (step 6), this gives full bidirectional coverage: - API edit description/limit → pull → frontmatter updated - Push frontmatter with description/limit → API reflects changes 🐾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta <noreply@letta.com> --------- Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
committed by
Caren Thomas
parent
9dee331e6c
commit
369cdf72c7
@@ -494,6 +494,8 @@ async def _sync_after_push(actor_id: str, agent_id: str) -> None:
|
||||
logger.exception("Failed to read repo files after %d retries (agent=%s)", max_retries, agent_id)
|
||||
|
||||
expected_labels = set()
|
||||
from letta.services.memory_repo.block_markdown import parse_block_markdown
|
||||
|
||||
synced = 0
|
||||
for file_path, content in files.items():
|
||||
if not file_path.startswith("memory/") or not file_path.endswith(".md"):
|
||||
@@ -501,12 +503,20 @@ async def _sync_after_push(actor_id: str, agent_id: str) -> None:
|
||||
|
||||
label = file_path[len("memory/") : -3]
|
||||
expected_labels.add(label)
|
||||
|
||||
# Parse frontmatter to extract metadata alongside value
|
||||
parsed = parse_block_markdown(content)
|
||||
|
||||
try:
|
||||
await _server_instance.block_manager._sync_block_to_postgres(
|
||||
agent_id=agent_id,
|
||||
label=label,
|
||||
value=content,
|
||||
value=parsed["value"],
|
||||
actor=actor,
|
||||
description=parsed.get("description"),
|
||||
limit=parsed.get("limit"),
|
||||
read_only=parsed.get("read_only"),
|
||||
metadata=parsed.get("metadata"),
|
||||
)
|
||||
synced += 1
|
||||
logger.info("Synced block %s to PostgreSQL", label)
|
||||
|
||||
Reference in New Issue
Block a user