Skip to content

Commit 2a6e7a2

Browse files
committed
Fix exact concept index row matching
1 parent 65e1493 commit 2a6e7a2

2 files changed

Lines changed: 61 additions & 14 deletions

File tree

openkb/agent/compiler.py

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,35 @@ def _backlink_concepts(wiki_dir: Path, doc_name: str, concept_slugs: list[str])
461461
path.write_text(text, encoding="utf-8")
462462

463463

464+
def _find_section_bounds(lines: list[str], heading: str) -> tuple[int, int] | None:
465+
"""Return [start, end) line indexes for a section headed by ``heading``."""
466+
for i, line in enumerate(lines):
467+
if line != heading:
468+
continue
469+
start = i + 1
470+
end = len(lines)
471+
for j in range(start, len(lines)):
472+
if lines[j].startswith("## "):
473+
end = j
474+
break
475+
return start, end
476+
return None
477+
478+
479+
def _find_index_entry_line(lines: list[str], heading: str, link: str) -> int | None:
480+
"""Find an index entry that starts with ``- {link}`` inside one section only."""
481+
bounds = _find_section_bounds(lines, heading)
482+
if bounds is None:
483+
return None
484+
485+
start, end = bounds
486+
entry_prefix = f"- {link}"
487+
for i in range(start, end):
488+
if lines[i].startswith(entry_prefix):
489+
return i
490+
return None
491+
492+
464493
def _update_index(
465494
wiki_dir: Path, doc_name: str, concept_names: list[str],
466495
doc_brief: str = "", concept_briefs: dict[str, str] | None = None,
@@ -484,34 +513,32 @@ def _update_index(
484513
encoding="utf-8",
485514
)
486515

487-
text = index_path.read_text(encoding="utf-8")
516+
lines = index_path.read_text(encoding="utf-8").split("\n")
488517

489518
doc_link = f"[[summaries/{doc_name}]]"
490-
if doc_link not in text:
519+
if _find_index_entry_line(lines, "## Documents", doc_link) is None:
491520
doc_entry = f"- {doc_link} ({doc_type})"
492521
if doc_brief:
493522
doc_entry += f" — {doc_brief}"
494-
if "## Documents" in text:
495-
text = text.replace("## Documents\n", f"## Documents\n{doc_entry}\n", 1)
523+
doc_bounds = _find_section_bounds(lines, "## Documents")
524+
if doc_bounds is not None:
525+
lines.insert(doc_bounds[0], doc_entry)
496526

497527
for name in concept_names:
498528
concept_link = f"[[concepts/{name}]]"
499529
concept_entry = f"- {concept_link}"
500530
if name in concept_briefs:
501531
concept_entry += f" — {concept_briefs[name]}"
502-
if concept_link in text:
532+
concept_line = _find_index_entry_line(lines, "## Concepts", concept_link)
533+
if concept_line is not None:
503534
if name in concept_briefs:
504-
lines = text.split("\n")
505-
for i, line in enumerate(lines):
506-
if concept_link in line:
507-
lines[i] = concept_entry
508-
break
509-
text = "\n".join(lines)
535+
lines[concept_line] = concept_entry
510536
else:
511-
if "## Concepts" in text:
512-
text = text.replace("## Concepts\n", f"## Concepts\n{concept_entry}\n", 1)
537+
concept_bounds = _find_section_bounds(lines, "## Concepts")
538+
if concept_bounds is not None:
539+
lines.insert(concept_bounds[0], concept_entry)
513540

514-
index_path.write_text(text, encoding="utf-8")
541+
index_path.write_text("\n".join(lines), encoding="utf-8")
515542

516543

517544
# ---------------------------------------------------------------------------

tests/test_compiler.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,26 @@ def test_appends_entries_with_briefs(self, tmp_path):
198198
assert "[[concepts/attention]] — Focus mechanism" in text
199199
assert "[[concepts/transformer]] — NN architecture" in text
200200

201+
def test_updates_only_exact_concept_row(self, tmp_path):
202+
wiki = tmp_path / "wiki"
203+
wiki.mkdir()
204+
(wiki / "index.md").write_text(
205+
"# Index\n\n## Documents\n\n## Concepts\n"
206+
"- [[concepts/transformer]] — Uses [[concepts/attention]] internally\n"
207+
"- [[concepts/attention]] — Old brief\n\n## Explorations\n",
208+
encoding="utf-8",
209+
)
210+
_update_index(
211+
wiki,
212+
"my-doc",
213+
["attention"],
214+
concept_briefs={"attention": "New brief"},
215+
)
216+
text = (wiki / "index.md").read_text()
217+
assert "- [[concepts/transformer]] — Uses [[concepts/attention]] internally" in text
218+
assert "- [[concepts/attention]] — New brief" in text
219+
assert text.count("[[concepts/attention]] — New brief") == 1
220+
201221
def test_no_duplicates(self, tmp_path):
202222
wiki = tmp_path / "wiki"
203223
wiki.mkdir()

0 commit comments

Comments
 (0)