"""Breadcrumb keys — the index a later search asks by."""
from navi.memory.breadcrumbs import (
MAX_BREADCRUMBS,
extract_breadcrumbs,
split_keys_line,
)
class TestSplitKeysLine:
def test_the_trailing_keys_line_is_parsed_and_removed(self):
text = "## Goal\nDo the thing.\n\nKEYS: navi/server.py, pytest, port 8099"
clean, keys = split_keys_line(text)
assert clean == "## Goal\nDo the thing."
assert keys == ["navi/server.py", "pytest", "port 8099"]
def test_bold_and_lowercase_spellings_are_recognised(self):
for line in ("**KEYS**: a, b", "keys: a, b", "KEYS: a; b"):
_, keys = split_keys_line(f"summary\n{line}")
assert keys == ["a", "b"], line
def test_none_yields_no_keys(self):
clean, keys = split_keys_line("summary\nKEYS: NONE")
assert keys == []
assert clean == "summary"
def test_backticks_and_bullets_are_stripped(self):
_, keys = split_keys_line("s\nKEYS: `memory_search`, - `navi/memory/_chunks.py`, " + "x" * 200)
assert keys == ["memory_search", "navi/memory/_chunks.py"]
def test_a_summary_without_the_line_is_untouched(self):
text = "## Goal\nNothing to index here."
assert split_keys_line(text) == (text, [])
def test_only_the_last_line_counts(self):
# The model may mention KEYS in prose; the index is the line at the end.
text = "KEYS: not-this-one\n## Goal\nbody\nKEYS: real_key"
clean, keys = split_keys_line(text)
assert keys == ["real_key"]
assert "not-this-one" in clean
class TestExtractBreadcrumbs:
def test_names_commands_paths_and_amounts_are_found(self):
text = (
"We ran `uv run pytest -q` in navi/core/compressor.py and it failed:\n"
"AssertionError: memory_search returned 0 hits\n"
"The budget is 4,5 GB and ticket #522 is closed."
)
found = extract_breadcrumbs([text])
joined = " | ".join(found)
assert "uv run pytest -q" in joined
assert "navi/core/compressor.py" in joined
assert "memory_search" in joined
assert "#522" in joined
assert any("4,5 GB" in item for item in found)
def test_identifiers_and_urls(self):
found = extract_breadcrumbs(
["See https://tasks.gnexus.space/tasks/522 and call MemorySearchTool.execute."]
)
assert "https://tasks.gnexus.space/tasks/522" in found
assert "MemorySearchTool" in found
def test_duplicates_collapse_case_insensitively(self):
found = extract_breadcrumbs(["`navi/config.py` and NAVI/CONFIG.PY"])
assert len([f for f in found if f.lower() == "navi/config.py"]) == 1
def test_the_limit_is_respected(self):
text = " ".join(f"`thing_{index}`" for index in range(60))
assert len(extract_breadcrumbs([text], limit=5)) == 5
assert extract_breadcrumbs([text], limit=0) == []
def test_the_cap_is_not_exceeded_by_default(self):
text = " ".join(f"`name_{index}`" for index in range(MAX_BREADCRUMBS + 20))
assert len(extract_breadcrumbs([text])) == MAX_BREADCRUMBS
def test_empty_text_produces_nothing(self):
assert extract_breadcrumbs([]) == []
assert extract_breadcrumbs(["", None]) == [] # type: ignore[list-item]
def test_extraction_is_deterministic(self):
text = "`alpha`, `/tmp/x.py`, snake_case_name, 12 ms"
assert extract_breadcrumbs([text]) == extract_breadcrumbs([text])