feat: implement append_note_content function and update related tests

This commit is contained in:
bearsyankees
2026-03-23 20:36:45 -04:00
parent 7a06df8e05
commit 21f89dd6bd
7 changed files with 71 additions and 15 deletions

View File

@@ -738,7 +738,7 @@ def _parse_name_status_z(raw_output: bytes) -> list[DiffEntry]:
# Backward-compat fallback if output is tab-delimited unexpectedly.
status_fallback, has_tab, first_path = token.partition("\t")
if not has_tab:
break
break
fallback_code = status_fallback[:1]
fallback_similarity: int | None = None
if len(status_fallback) > 1 and status_fallback[1:].isdigit():

View File

@@ -113,7 +113,7 @@ class LLM:
ordered_skills.append(f"scan_modes/{self.config.scan_mode}")
if self.config.is_whitebox:
ordered_skills.append("coordination/source_aware_whitebox")
ordered_skills.append("source_aware_sast")
ordered_skills.append("custom/source_aware_sast")
deduped: list[str] = []
seen: set[str] = set()

View File

@@ -36,10 +36,13 @@ mkdir -p "$ART"
semgrep scan --config p/default --config p/golang --config p/secrets \
--metrics=off --json --output "$ART/semgrep.json" .
sg scan --json . > "$ART/ast-grep.json"
# Ruleless AST pass (works without sgconfig.yml/rules project setup)
sg run --pattern '$F($$$ARGS)' --json=stream . > "$ART/ast-grep.json" 2> "$ART/ast-grep.log" || true
gitleaks detect --source . --report-format json --report-path "$ART/gitleaks.json" || true
trufflehog filesystem --no-update --json --no-verification . > "$ART/trufflehog.json" || true
trivy fs --format json --output "$ART/trivy-fs.json" .
# Keep trivy focused on vuln/misconfig (secrets already covered above) and increase timeout for large repos
trivy fs --scanners vuln,misconfig --timeout 30m --offline-scan \
--format json --output "$ART/trivy-fs.json" . || true
```
If one tool is skipped or fails, record that in the shared wiki note along with the reason.
@@ -64,7 +67,8 @@ If diff scope is active, restrict to changed files first, then expand only when
Use `sg` for structure-aware code hunting:
```bash
sg scan --json . > /workspace/.strix-source-aware/ast-grep.json
# Ruleless one-off structural pass (no sgconfig.yml required)
sg run --pattern '$F($$$ARGS)' --json=stream . > /workspace/.strix-source-aware/ast-grep.json 2> /workspace/.strix-source-aware/ast-grep.log || true
```
Target high-value patterns such as:
@@ -95,7 +99,8 @@ trufflehog filesystem --json . > /workspace/.strix-source-aware/trufflehog.json
Run repository-wide dependency and config checks:
```bash
trivy fs --format json --output /workspace/.strix-source-aware/trivy-fs.json .
trivy fs --scanners vuln,misconfig --timeout 30m --offline-scan \
--format json --output /workspace/.strix-source-aware/trivy-fs.json . || true
```
## Converting Static Signals Into Exploits

View File

@@ -123,7 +123,7 @@ def _append_wiki_update_on_finish(
return
try:
from strix.tools.notes.notes_actions import update_note
from strix.tools.notes.notes_actions import append_note_content
note = _load_primary_wiki_note(agent_state)
if not note:
@@ -133,7 +133,6 @@ def _append_wiki_update_on_finish(
if not isinstance(note_id, str) or not note_id:
return
existing_content = str(note.get("content") or "")
timestamp = datetime.now(UTC).isoformat()
summary = " ".join(str(result_summary).split())
if len(summary) > 1200:
@@ -151,8 +150,7 @@ def _append_wiki_update_on_finish(
"Recommendations:\n"
f"{recommendation_lines}\n"
)
updated_content = f"{existing_content.rstrip()}{delta}"
update_note(note_id=note_id, content=updated_content)
append_note_content(note_id=note_id, delta=delta)
except Exception:
# Best-effort update; never block agent completion on note persistence.
return

View File

@@ -364,6 +364,26 @@ def get_note(note_id: str) -> dict[str, Any]:
return {"success": True, "note": note_with_id}
def append_note_content(note_id: str, delta: str) -> dict[str, Any]:
with _notes_lock:
try:
_ensure_notes_loaded()
if note_id not in _notes_storage:
return {"success": False, "error": f"Note with ID '{note_id}' not found"}
if not isinstance(delta, str):
return {"success": False, "error": "Delta must be a string"}
note = _notes_storage[note_id]
existing_content = str(note.get("content") or "")
updated_content = f"{existing_content.rstrip()}{delta}"
return update_note(note_id=note_id, content=updated_content)
except (ValueError, TypeError) as e:
return {"success": False, "error": f"Failed to append note content: {e}"}
@register_tool(sandbox_execution=False)
def update_note(
note_id: str,

View File

@@ -164,14 +164,14 @@ def test_agent_finish_appends_wiki_update_for_whitebox(monkeypatch) -> None:
},
}
def fake_update_note(note_id: str, content: str):
def fake_append_note_content(note_id: str, delta: str):
captured["note_id"] = note_id
captured["content"] = content
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.update_note", fake_update_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)
result = agents_graph_actions.agent_finish(
@@ -185,8 +185,8 @@ def test_agent_finish_appends_wiki_update_for_whitebox(monkeypatch) -> None:
assert result["agent_completed"] is True
assert captured_get["note_id"] == "wiki-note-1"
assert captured["note_id"] == "wiki-note-1"
assert "Agent Update: Child" in captured["content"]
assert "AST pass completed" in captured["content"]
assert "Agent Update: Child" in captured["delta"]
assert "AST pass completed" in captured["delta"]
def test_run_agent_in_thread_injects_shared_wiki_context_in_whitebox(monkeypatch) -> None:

View File

@@ -137,3 +137,36 @@ def test_get_note_returns_full_note(tmp_path: Path, monkeypatch) -> None:
finally:
_reset_notes_state()
set_global_tracer(previous_tracer) # type: ignore[arg-type]
def test_append_note_content_appends_delta(tmp_path: Path, monkeypatch) -> None:
monkeypatch.chdir(tmp_path)
_reset_notes_state()
previous_tracer = get_global_tracer()
tracer = Tracer("append-note-run")
set_global_tracer(tracer)
try:
created = notes_actions.create_note(
title="Repo wiki",
content="base",
category="wiki",
tags=["repo:demo"],
)
assert created["success"] is True
note_id = created["note_id"]
assert isinstance(note_id, str)
appended = notes_actions.append_note_content(
note_id=note_id,
delta="\n\n## Agent Update: worker\nSummary: done",
)
assert appended["success"] is True
loaded = notes_actions.get_note(note_id=note_id)
assert loaded["success"] is True
assert loaded["note"]["content"] == "base\n\n## Agent Update: worker\nSummary: done"
finally:
_reset_notes_state()
set_global_tracer(previous_tracer) # type: ignore[arg-type]