mirror of
https://github.com/Egonex-AI/Understand-Anything.git
synced 2026-06-22 10:58:03 +08:00
fix(understand-knowledge): Windows path + zod schema null compatibility
Four single-line fixes that make `/understand-knowledge` work end-to-end on Windows.
## Root causes
1. Path separator mismatch (3 occurrences in parse-knowledge-base.py)
- `str(rel.with_suffix(""))` returns backslash-separated stems on Windows
(e.g. `entities\foo`), while wikilinks always use forward slashes
(`[[entities/foo]]`).
- Result: name_map keys and article_ids hold `entities\foo`, while
`resolve_wikilink()` looks up `entities/foo` -> 100% miss.
- Tested on Windows 11 + Python 3.14: 151/151 wikilinks unresolved,
0 edges built from wikilinks.
Fix: use `rel.with_suffix("").as_posix()` in all three places
(lines 235, 316, 330 on main).
2. Null vs missing field (1 occurrence)
- `"category": category or None` writes `null` when category is empty.
- `KnowledgeMetaSchema.category` in packages/core/src/schema.ts is
`z.string().optional()`, which accepts `undefined`/missing but
rejects `null`.
- Result: every article node fails GraphNodeSchema validation in the
dashboard (`Invalid input: expected string, received null`),
all nodes get dropped, dashboard renders empty.
Fix: omit the field when empty using dict spread.
## After
Tested with a 27-article Karpathy wiki on Windows:
- before: 151 unresolved wikilinks, 0 edges, 0 nodes rendered in dashboard
- after: 0 unresolved, 110 wikilink edges + 23 LLM-implicit edges,
all 53 nodes (article/topic/entity/claim) render correctly
No behavior change on macOS/Linux: `as_posix()` is a no-op when the OS
already uses `/`, and dict spread produces the same key as the previous
truthy branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -232,7 +232,7 @@ def build_name_to_stem_map(wiki_root: Path) -> dict[str, str]:
|
||||
basename_counts: dict[str, int] = {}
|
||||
for md_file in wiki_root.rglob("*.md"):
|
||||
rel = md_file.relative_to(wiki_root)
|
||||
stem = str(rel.with_suffix("")) # e.g., "decisions/decision-foo"
|
||||
stem = rel.with_suffix("").as_posix() # e.g., "decisions/decision-foo"
|
||||
basename = md_file.stem # e.g., "decision-foo"
|
||||
# Full relative path always maps uniquely
|
||||
name_map[stem.lower()] = stem
|
||||
@@ -313,7 +313,7 @@ def parse_wiki(root: Path) -> dict:
|
||||
article_ids: set[str] = set()
|
||||
for md_file in sorted(wiki_root.rglob("*.md")):
|
||||
rel = md_file.relative_to(wiki_root)
|
||||
stem = str(rel.with_suffix(""))
|
||||
stem = rel.with_suffix("").as_posix()
|
||||
# Only filter infra files at root level (no parent directory)
|
||||
if rel.parent == Path(".") and rel.name.lower() in INFRA_FILES:
|
||||
continue
|
||||
@@ -327,7 +327,7 @@ def parse_wiki(root: Path) -> dict:
|
||||
|
||||
for md_file in sorted(wiki_root.rglob("*.md")):
|
||||
rel = md_file.relative_to(wiki_root)
|
||||
stem = str(rel.with_suffix(""))
|
||||
stem = rel.with_suffix("").as_posix()
|
||||
basename = md_file.stem
|
||||
|
||||
# Skip infrastructure files only at wiki root level
|
||||
@@ -381,7 +381,7 @@ def parse_wiki(root: Path) -> dict:
|
||||
"complexity": complexity,
|
||||
"knowledgeMeta": {
|
||||
"wikilinks": [wl["target"] for wl in wikilinks],
|
||||
"category": category or None,
|
||||
**({"category": category} if category else {}),
|
||||
"content": text[:3000], # First 3000 chars for LLM analysis
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user