fix: support partial UUID prefix matching in memory/edge lookups
Closes cal/claude-memory#3. All ID-based lookups now resolve partial UUID prefixes (git-style) instead of requiring exact full UUIDs. Affects _resolve_memory_path, _resolve_edge_path, edge_search, and related(). Ambiguous prefixes raise ValueError with candidates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5cfb91d65f
commit
471d8709f6
@ -662,11 +662,32 @@ class CognitiveMemoryClient:
|
|||||||
content = f"{fm_str}\n\n{body.strip()}\n" if body.strip() else f"{fm_str}\n"
|
content = f"{fm_str}\n\n{body.strip()}\n" if body.strip() else f"{fm_str}\n"
|
||||||
path.write_text(content, encoding="utf-8")
|
path.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _resolve_prefix(partial_id: str, keys) -> Optional[str]:
|
||||||
|
"""Resolve a partial UUID prefix to a full ID (git-style).
|
||||||
|
|
||||||
|
Returns the full key if exactly one match is found, None if zero
|
||||||
|
matches, or raises ValueError on ambiguous (multiple) matches.
|
||||||
|
"""
|
||||||
|
if partial_id in keys:
|
||||||
|
return partial_id
|
||||||
|
matches = [k for k in keys if k.startswith(partial_id)]
|
||||||
|
if len(matches) == 1:
|
||||||
|
return matches[0]
|
||||||
|
if len(matches) > 1:
|
||||||
|
raise ValueError(
|
||||||
|
f"Ambiguous ID prefix '{partial_id}' matches {len(matches)} "
|
||||||
|
f"entries: {', '.join(sorted(matches)[:5])}"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
def _resolve_memory_path(self, memory_id: str) -> Optional[Path]:
|
def _resolve_memory_path(self, memory_id: str) -> Optional[Path]:
|
||||||
"""Find the file path for a memory by ID using the index."""
|
"""Find the file path for a memory by ID using the index."""
|
||||||
index = self._load_index()
|
index = self._load_index()
|
||||||
entry = index.get("entries", {}).get(memory_id)
|
entries = index.get("entries", {})
|
||||||
if entry:
|
full_id = self._resolve_prefix(memory_id, entries)
|
||||||
|
if full_id:
|
||||||
|
entry = entries[full_id]
|
||||||
path = self.memory_dir / entry["path"]
|
path = self.memory_dir / entry["path"]
|
||||||
if path.exists():
|
if path.exists():
|
||||||
return path
|
return path
|
||||||
@ -834,8 +855,10 @@ class CognitiveMemoryClient:
|
|||||||
def _resolve_edge_path(self, edge_id: str) -> Optional[Path]:
|
def _resolve_edge_path(self, edge_id: str) -> Optional[Path]:
|
||||||
"""Find the file path for an edge by ID using the index."""
|
"""Find the file path for an edge by ID using the index."""
|
||||||
index = self._load_index()
|
index = self._load_index()
|
||||||
entry = index.get("edges", {}).get(edge_id)
|
edges = index.get("edges", {})
|
||||||
if entry:
|
full_id = self._resolve_prefix(edge_id, edges)
|
||||||
|
if full_id:
|
||||||
|
entry = edges[full_id]
|
||||||
path = self.memory_dir / entry["path"]
|
path = self.memory_dir / entry["path"]
|
||||||
if path.exists():
|
if path.exists():
|
||||||
return path
|
return path
|
||||||
@ -1243,6 +1266,16 @@ class CognitiveMemoryClient:
|
|||||||
results = []
|
results = []
|
||||||
query_lower = query.lower().strip() if query else ""
|
query_lower = query.lower().strip() if query else ""
|
||||||
|
|
||||||
|
# Resolve partial IDs to full UUIDs via prefix match
|
||||||
|
if from_id:
|
||||||
|
entries = index.get("entries", {})
|
||||||
|
resolved = self._resolve_prefix(from_id, entries)
|
||||||
|
from_id = resolved or from_id
|
||||||
|
if to_id:
|
||||||
|
entries = index.get("entries", {})
|
||||||
|
resolved = self._resolve_prefix(to_id, entries)
|
||||||
|
to_id = resolved or to_id
|
||||||
|
|
||||||
for eid, entry in index.get("edges", {}).items():
|
for eid, entry in index.get("edges", {}).items():
|
||||||
if types and entry.get("type") not in types:
|
if types and entry.get("type") not in types:
|
||||||
continue
|
continue
|
||||||
@ -1532,12 +1565,18 @@ class CognitiveMemoryClient:
|
|||||||
visited = set()
|
visited = set()
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
|
# Resolve partial ID prefix to full UUID
|
||||||
|
entries = index.get("entries", {})
|
||||||
|
resolved = self._resolve_prefix(memory_id, entries)
|
||||||
|
if resolved:
|
||||||
|
memory_id = resolved
|
||||||
|
|
||||||
def traverse(mid: str, depth: int):
|
def traverse(mid: str, depth: int):
|
||||||
if depth > max_depth or mid in visited:
|
if depth > max_depth or mid in visited:
|
||||||
return
|
return
|
||||||
visited.add(mid)
|
visited.add(mid)
|
||||||
|
|
||||||
entry = index.get("entries", {}).get(mid)
|
entry = entries.get(mid)
|
||||||
if not entry:
|
if not entry:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user