whitebox follow up: better wiki

This commit is contained in:
bearsyankees
2026-03-31 16:44:48 -04:00
parent c0243367a8
commit 4f10ae40d7
11 changed files with 352 additions and 51 deletions

View File

@@ -296,3 +296,120 @@ def test_load_primary_wiki_note_prefers_repo_tag_match(monkeypatch) -> None:
assert note is not None
assert note["note_id"] == "wiki-target"
assert selected_note_ids == ["wiki-target"]
def test_load_primary_wiki_note_prefers_requested_wiki_kind(monkeypatch) -> None:
selected_note_ids: list[str] = []
def fake_list_notes(category=None):
assert category == "wiki"
return {
"success": True,
"notes": [
{"note_id": "wiki-security", "tags": ["repo:appsmith", "wiki:security"]},
{"note_id": "wiki-overview", "tags": ["repo:appsmith", "wiki:overview"]},
],
"total_count": 2,
}
def fake_get_note(note_id: str):
selected_note_ids.append(note_id)
return {
"success": True,
"note": {
"note_id": note_id,
"title": "Repo Wiki",
"content": "content",
},
}
monkeypatch.setattr("strix.tools.notes.notes_actions.list_notes", fake_list_notes)
monkeypatch.setattr("strix.tools.notes.notes_actions.get_note", fake_get_note)
agent_state = SimpleNamespace(task="analyze /workspace/appsmith")
overview_note = agents_graph_actions._load_primary_wiki_note(
agent_state,
preferred_kind="overview",
allow_kind_fallback=False,
)
security_note = agents_graph_actions._load_primary_wiki_note(
agent_state,
preferred_kind="security",
allow_kind_fallback=True,
)
assert overview_note is not None
assert security_note is not None
assert overview_note["note_id"] == "wiki-overview"
assert security_note["note_id"] == "wiki-security"
assert selected_note_ids == ["wiki-overview", "wiki-security"]
def test_agent_finish_prefers_security_wiki_for_append(monkeypatch) -> None:
monkeypatch.setenv("STRIX_LLM", "openai/gpt-5")
agents_graph_actions._agent_graph["nodes"].clear()
agents_graph_actions._agent_graph["edges"].clear()
agents_graph_actions._agent_messages.clear()
agents_graph_actions._running_agents.clear()
agents_graph_actions._agent_instances.clear()
agents_graph_actions._agent_states.clear()
parent_id = "parent-sec"
child_id = "child-sec"
agents_graph_actions._agent_graph["nodes"][parent_id] = {
"name": "Parent",
"task": "parent task",
"status": "running",
"parent_id": None,
}
agents_graph_actions._agent_graph["nodes"][child_id] = {
"name": "Child",
"task": "child task",
"status": "running",
"parent_id": parent_id,
}
agents_graph_actions._agent_instances[child_id] = SimpleNamespace(
llm_config=LLMConfig(is_whitebox=True)
)
captured: dict[str, str] = {}
def fake_list_notes(category=None):
assert category == "wiki"
return {
"success": True,
"notes": [
{"note_id": "wiki-overview", "tags": ["repo:appsmith", "wiki:overview"]},
{"note_id": "wiki-security", "tags": ["repo:appsmith", "wiki:security"]},
],
"total_count": 2,
}
def fake_get_note(note_id: str):
return {
"success": True,
"note": {"note_id": note_id, "title": "Repo Wiki", "content": "Existing wiki content"},
}
def fake_append_note_content(note_id: str, delta: str):
captured["note_id"] = note_id
captured["delta"] = delta
return {"success": True, "note_id": note_id}
monkeypatch.setattr("strix.tools.notes.notes_actions.list_notes", fake_list_notes)
monkeypatch.setattr("strix.tools.notes.notes_actions.get_note", fake_get_note)
monkeypatch.setattr("strix.tools.notes.notes_actions.append_note_content", fake_append_note_content)
state = SimpleNamespace(agent_id=child_id, parent_id=parent_id, task="analyze /workspace/appsmith")
result = agents_graph_actions.agent_finish(
agent_state=state,
result_summary="Static triage completed",
findings=["Found candidate sink"],
success=True,
final_recommendations=["Validate with dynamic PoC"],
)
assert result["agent_completed"] is True
assert captured["note_id"] == "wiki-security"
assert "Static triage completed" in captured["delta"]

View File

@@ -124,7 +124,7 @@ def test_get_note_returns_full_note(tmp_path: Path, monkeypatch) -> None:
title="Repo wiki",
content="entrypoints and sinks",
category="wiki",
tags=["repo:appsmith"],
tags=["repo:appsmith", "wiki:security"],
)
assert created["success"] is True
note_id = created["note_id"]
@@ -134,6 +134,7 @@ def test_get_note_returns_full_note(tmp_path: Path, monkeypatch) -> None:
assert result["success"] is True
assert result["note"]["note_id"] == note_id
assert result["note"]["content"] == "entrypoints and sinks"
assert result["note"]["wiki_kind"] == "security"
finally:
_reset_notes_state()
set_global_tracer(previous_tracer) # type: ignore[arg-type]
@@ -212,3 +213,55 @@ def test_list_and_get_note_handle_wiki_repersist_oserror_gracefully(
finally:
_reset_notes_state()
set_global_tracer(previous_tracer) # type: ignore[arg-type]
def test_wiki_index_tracks_overview_and_security_notes(tmp_path: Path, monkeypatch) -> None:
monkeypatch.chdir(tmp_path)
_reset_notes_state()
previous_tracer = get_global_tracer()
tracer = Tracer("wiki-index-run")
set_global_tracer(tracer)
try:
overview = notes_actions.create_note(
title="Repo overview wiki",
content="architecture and entrypoints",
category="wiki",
tags=["repo:demo", "wiki:overview"],
)
assert overview["success"] is True
overview_id = overview["note_id"]
assert isinstance(overview_id, str)
security = notes_actions.create_note(
title="Repo security wiki",
content="scanner summary and follow-ups",
category="wiki",
tags=["repo:demo", "wiki:security"],
)
assert security["success"] is True
security_id = security["note_id"]
assert isinstance(security_id, str)
wiki_index = tmp_path / "strix_runs" / "wiki-index-run" / "wiki" / "index.json"
assert wiki_index.exists() is True
index_data = wiki_index.read_text(encoding="utf-8")
assert '"wiki_kind": "overview"' in index_data
assert '"wiki_kind": "security"' in index_data
listed = notes_actions.list_notes(category="wiki")
assert listed["success"] is True
note_kinds = {note["note_id"]: note.get("wiki_kind") for note in listed["notes"]}
assert note_kinds[overview_id] == "overview"
assert note_kinds[security_id] == "security"
deleted = notes_actions.delete_note(note_id=overview_id)
assert deleted["success"] is True
index_after_delete = wiki_index.read_text(encoding="utf-8")
assert overview_id not in index_after_delete
assert security_id in index_after_delete
finally:
_reset_notes_state()
set_global_tracer(previous_tracer) # type: ignore[arg-type]