d959fe2163
Tracer:
- Collapse the ``live`` / ``completed`` LLM stat buckets into one
flat dict. The ``completed`` bucket was only ever written by tests
— production never moved stats across, and ``get_total_llm_stats``
always summed both for display.
- Drop ``record_llm_usage(agent_id=...)``: argument was unused, and
the per-call ``bucket=`` knob is gone with the buckets.
run_config_factory:
- Drop unused ``parallel_tool_calls``, ``tool_choice`` parameters
from ``make_run_config`` — no caller ever overrode them.
- Drop ``agent_name`` from ``make_agent_context`` — set into the
context dict but no consumer ever read it; the bus's ``names`` map
is the source of truth.
Wire reasoning_effort through:
- ``Config.get("strix_reasoning_effort")`` is now actually plumbed
to ``make_run_config`` from ``entry.py``. Previously the env var
was advertised but never consumed.
Multi-agent graph tools:
- Replace six copies of
``inner = ctx.context if isinstance(ctx.context, dict) else {}``
with a single ``_ctx(ctx)`` helper.
Todo tools:
- Lift the duplicated ``priority_order`` / ``status_order`` dicts
to module-level ``_PRIORITY_RANK`` / ``_STATUS_RANK`` and replace
both inline sort lambdas with ``_todo_sort_key``.
Notes tools:
- Delete ``append_note_content`` (and its test): docstring claimed
it was for an "agents-graph wiki-update hook on agent_finish" that
was never wired up. Pure dead public API.
Style:
- Drop the ``del ctx`` no-ops from notes / reporting / web_search
tools. ``ARG001`` is already silenced project-wide for tool
modules; the ``del`` was cargo-culted.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
188 lines
6.2 KiB
Python
188 lines
6.2 KiB
Python
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from strix.telemetry.tracer import Tracer, get_global_tracer, set_global_tracer
|
|
from strix.tools.notes import tools as notes_actions
|
|
|
|
|
|
def _reset_notes_state() -> None:
|
|
notes_actions._notes_storage.clear()
|
|
notes_actions._loaded_notes_run_dir = None
|
|
|
|
|
|
def test_wiki_notes_are_persisted_and_removed(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
_reset_notes_state()
|
|
|
|
previous_tracer = get_global_tracer()
|
|
tracer = Tracer("wiki-test-run")
|
|
set_global_tracer(tracer)
|
|
|
|
try:
|
|
created = notes_actions._create_note_impl(
|
|
title="Repo Map",
|
|
content="## Architecture\n- monolith",
|
|
category="wiki",
|
|
tags=["source-map"],
|
|
)
|
|
assert created["success"] is True
|
|
note_id = created["note_id"]
|
|
assert isinstance(note_id, str)
|
|
|
|
note = notes_actions._notes_storage[note_id]
|
|
wiki_filename = note.get("wiki_filename")
|
|
assert isinstance(wiki_filename, str)
|
|
|
|
wiki_path = tmp_path / "strix_runs" / "wiki-test-run" / "wiki" / wiki_filename
|
|
assert wiki_path.exists()
|
|
assert "## Architecture" in wiki_path.read_text(encoding="utf-8")
|
|
|
|
updated = notes_actions._update_note_impl(
|
|
note_id=note_id,
|
|
content="## Architecture\n- service-oriented",
|
|
)
|
|
assert updated["success"] is True
|
|
assert "service-oriented" in wiki_path.read_text(encoding="utf-8")
|
|
|
|
deleted = notes_actions._delete_note_impl(note_id=note_id)
|
|
assert deleted["success"] is True
|
|
assert wiki_path.exists() is False
|
|
finally:
|
|
_reset_notes_state()
|
|
set_global_tracer(previous_tracer)
|
|
|
|
|
|
def test_notes_jsonl_replay_survives_memory_reset(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
_reset_notes_state()
|
|
|
|
previous_tracer = get_global_tracer()
|
|
tracer = Tracer("notes-replay-run")
|
|
set_global_tracer(tracer)
|
|
|
|
try:
|
|
created = notes_actions._create_note_impl(
|
|
title="Auth findings",
|
|
content="initial finding",
|
|
category="findings",
|
|
tags=["auth"],
|
|
)
|
|
assert created["success"] is True
|
|
note_id = created["note_id"]
|
|
assert isinstance(note_id, str)
|
|
|
|
notes_path = tmp_path / "strix_runs" / "notes-replay-run" / "notes" / "notes.jsonl"
|
|
assert notes_path.exists() is True
|
|
|
|
_reset_notes_state()
|
|
listed = notes_actions._list_notes_impl(category="findings")
|
|
assert listed["success"] is True
|
|
assert listed["total_count"] == 1
|
|
assert listed["notes"][0]["note_id"] == note_id
|
|
assert "content" not in listed["notes"][0]
|
|
assert "content_preview" in listed["notes"][0]
|
|
|
|
updated = notes_actions._update_note_impl(note_id=note_id, content="updated finding")
|
|
assert updated["success"] is True
|
|
|
|
_reset_notes_state()
|
|
listed_after_update = notes_actions._list_notes_impl(search="updated finding")
|
|
assert listed_after_update["success"] is True
|
|
assert listed_after_update["total_count"] == 1
|
|
assert listed_after_update["notes"][0]["note_id"] == note_id
|
|
assert listed_after_update["notes"][0]["content_preview"] == "updated finding"
|
|
|
|
listed_with_content = notes_actions._list_notes_impl(
|
|
category="findings",
|
|
include_content=True,
|
|
)
|
|
assert listed_with_content["success"] is True
|
|
assert listed_with_content["total_count"] == 1
|
|
assert listed_with_content["notes"][0]["content"] == "updated finding"
|
|
|
|
deleted = notes_actions._delete_note_impl(note_id=note_id)
|
|
assert deleted["success"] is True
|
|
|
|
_reset_notes_state()
|
|
listed_after_delete = notes_actions._list_notes_impl(category="findings")
|
|
assert listed_after_delete["success"] is True
|
|
assert listed_after_delete["total_count"] == 0
|
|
finally:
|
|
_reset_notes_state()
|
|
set_global_tracer(previous_tracer)
|
|
|
|
|
|
def test_get_note_returns_full_note(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
_reset_notes_state()
|
|
|
|
previous_tracer = get_global_tracer()
|
|
tracer = Tracer("get-note-run")
|
|
set_global_tracer(tracer)
|
|
|
|
try:
|
|
created = notes_actions._create_note_impl(
|
|
title="Repo wiki",
|
|
content="entrypoints and sinks",
|
|
category="wiki",
|
|
tags=["repo:appsmith"],
|
|
)
|
|
assert created["success"] is True
|
|
note_id = created["note_id"]
|
|
assert isinstance(note_id, str)
|
|
|
|
result = notes_actions._get_note_impl(note_id=note_id)
|
|
assert result["success"] is True
|
|
assert result["note"]["note_id"] == note_id
|
|
assert result["note"]["content"] == "entrypoints and sinks"
|
|
finally:
|
|
_reset_notes_state()
|
|
set_global_tracer(previous_tracer)
|
|
|
|
|
|
def test_list_and_get_note_handle_wiki_repersist_oserror_gracefully(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
_reset_notes_state()
|
|
|
|
previous_tracer = get_global_tracer()
|
|
tracer = Tracer("wiki-repersist-oserror-run")
|
|
set_global_tracer(tracer)
|
|
|
|
try:
|
|
created = notes_actions._create_note_impl(
|
|
title="Repo wiki",
|
|
content="initial wiki content",
|
|
category="wiki",
|
|
tags=["repo:demo"],
|
|
)
|
|
assert created["success"] is True
|
|
note_id = created["note_id"]
|
|
assert isinstance(note_id, str)
|
|
|
|
_reset_notes_state()
|
|
|
|
def _raise_oserror(*_args: object, **_kwargs: object) -> None:
|
|
raise OSError("disk full")
|
|
|
|
monkeypatch.setattr(notes_actions, "_persist_wiki_note", _raise_oserror)
|
|
|
|
listed = notes_actions._list_notes_impl(category="wiki")
|
|
assert listed["success"] is True
|
|
assert listed["total_count"] == 1
|
|
assert listed["notes"][0]["note_id"] == note_id
|
|
|
|
fetched = notes_actions._get_note_impl(note_id=note_id)
|
|
assert fetched["success"] is True
|
|
assert fetched["note"]["note_id"] == note_id
|
|
assert fetched["note"]["content"] == "initial wiki content"
|
|
finally:
|
|
_reset_notes_state()
|
|
set_global_tracer(previous_tracer)
|