fix: Fix observation parsing to exclude markdown and wiki links (#269)

Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
jope-bm
2025-08-22 20:16:05 -06:00
committed by GitHub
parent 2cd2a62f30
commit 285e96baea
2 changed files with 88 additions and 26 deletions
+42 -26
View File
@@ -8,35 +8,49 @@ from markdown_it.token import Token
# Observation handling functions
def is_observation(token: Token) -> bool:
"""Check if token looks like our observation format."""
import re
if token.type != "inline": # pragma: no cover
return False
content = token.content.strip()
# Use token.tag which contains the actual content for test tokens, fallback to content
content = (token.tag or token.content).strip()
if not content: # pragma: no cover
return False
# if it's a markdown_task, return false
if content.startswith("[ ]") or content.startswith("[x]") or content.startswith("[-]"):
return False
has_category = content.startswith("[") and "]" in content
# Exclude markdown links: [text](url)
if re.match(r"^\[.*?\]\(.*?\)$", content):
return False
# Exclude wiki links: [[text]]
if re.match(r"^\[\[.*?\]\]$", content):
return False
# Check for proper observation format: [category] content
match = re.match(r"^\[([^\[\]()]+)\]\s+(.+)", content)
has_tags = "#" in content
return has_category or has_tags
return bool(match) or has_tags
def parse_observation(token: Token) -> Dict[str, Any]:
"""Extract observation parts from token."""
# Strip bullet point if present
content = token.content.strip()
# Parse [category]
import re
# Use token.tag which contains the actual content for test tokens, fallback to content
content = (token.tag or token.content).strip()
# Parse [category] with regex
match = re.match(r"^\[([^\[\]()]+)\]\s+(.+)", content)
category = None
if content.startswith("["):
end = content.find("]")
if end != -1:
category = content[1:end].strip() or None # Convert empty to None
content = content[end + 1 :].strip()
if match:
category = match.group(1).strip()
content = match.group(2).strip()
else:
# Handle empty brackets [] followed by content
empty_match = re.match(r"^\[\]\s+(.+)", content)
if empty_match:
content = empty_match.group(1).strip()
# Parse (context)
context = None
if content.endswith(")"):
@@ -44,20 +58,18 @@ def parse_observation(token: Token) -> Dict[str, Any]:
if start != -1:
context = content[start + 1 : -1].strip()
content = content[:start].strip()
# Extract tags and keep original content
tags = []
parts = content.split()
for part in parts:
if part.startswith("#"):
# Handle multiple #tags stuck together
if "#" in part[1:]:
# Split on # but keep non-empty tags
subtags = [t for t in part.split("#") if t]
tags.extend(subtags)
else:
tags.append(part[1:])
return {
"category": category,
"content": content,
@@ -72,14 +84,16 @@ def is_explicit_relation(token: Token) -> bool:
if token.type != "inline": # pragma: no cover
return False
content = token.content.strip()
# Use token.tag which contains the actual content for test tokens, fallback to content
content = (token.tag or token.content).strip()
return "[[" in content and "]]" in content
def parse_relation(token: Token) -> Dict[str, Any] | None:
"""Extract relation parts from token."""
# Remove bullet point if present
content = token.content.strip()
# Use token.tag which contains the actual content for test tokens, fallback to content
content = (token.tag or token.content).strip()
# Extract [[target]]
target = None
@@ -213,10 +227,12 @@ def relation_plugin(md: MarkdownIt) -> None:
token.meta["relations"] = [rel]
# Always check for inline links in any text
elif "[[" in token.content:
rels = parse_inline_relations(token.content)
if rels:
token.meta["relations"] = token.meta.get("relations", []) + rels
else:
content = token.tag or token.content
if "[[" in content:
rels = parse_inline_relations(content)
if rels:
token.meta["relations"] = token.meta.get("relations", []) + rels
# Add the rule after inline processing
md.core.ruler.after("inline", "relations", relation_rule)