Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions agent/agent_runtime_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2932,6 +2932,7 @@ def _execute(next_args: dict) -> Any:
around_message_id=next_args.get("around_message_id"),
window=next_args.get("window", 5),
sort=next_args.get("sort"),
detail=next_args.get("detail", "adaptive"),
db=session_db,
current_session_id=agent.session_id,
),
Expand Down
1 change: 1 addition & 0 deletions agent/tool_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1761,6 +1761,7 @@ def _execute(next_args: dict) -> Any:
around_message_id=next_args.get("around_message_id"),
window=next_args.get("window", 5),
sort=next_args.get("sort"),
detail=next_args.get("detail", "adaptive"),
db=session_db,
current_session_id=agent.session_id,
)
Expand Down
42 changes: 41 additions & 1 deletion tests/run_agent/test_token_persistence_non_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,49 @@ def fake_session_search(**kwargs):
monkeypatch.setitem(sys.modules, "tools.session_search_tool", session_search_mod)

agent = _make_agent(None, platform="acp")
result = json.loads(agent._invoke_tool("session_search", {"query": "Hermes"}, "task-id"))
result = json.loads(agent._invoke_tool(
"session_search",
{"query": "Hermes", "detail": "full"},
"task-id",
))

assert result["success"] is True
assert captured["db"] is sentinel_db
assert captured["query"] == "Hermes"
assert captured["detail"] == "full"
assert agent._session_db is sentinel_db


def test_sequential_session_search_forwards_detail(monkeypatch):
session_db = MagicMock()
captured = {}

session_search_mod = ModuleType("tools.session_search_tool")

def fake_session_search(**kwargs):
captured.update(kwargs)
return json.dumps({"success": True, "results": []})

session_search_mod.session_search = fake_session_search
monkeypatch.setitem(sys.modules, "tools.session_search_tool", session_search_mod)

agent = _make_agent(session_db, platform="acp")
tool_call = SimpleNamespace(
id="search-1",
function=SimpleNamespace(
name="session_search",
arguments=json.dumps({"query": "Hermes", "detail": "full"}),
),
)
assistant_message = SimpleNamespace(tool_calls=[tool_call])
messages = []

agent._execute_tool_calls_sequential(
assistant_message,
messages,
"task-id",
)

assert captured["db"] is session_db
assert captured["query"] == "Hermes"
assert captured["detail"] == "full"
101 changes: 96 additions & 5 deletions tests/tools/test_session_search.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
"""Tests for the single-shape session_search tool.

Three calling shapes:
1. DISCOVERY — pass query → FTS5 + anchored window + bookends per hit
Four calling shapes:
1. DISCOVERY — pass query → FTS5 + adaptive/full hydration
2. SCROLL — pass session_id + around_message_id → just the window
3. BROWSE — no args → recent sessions chronologically
3. READ — pass session_id → whole or head/tail-truncated session
4. BROWSE — no args → recent sessions chronologically

All run zero LLM calls.
"""
import inspect
import json
import time

Expand Down Expand Up @@ -72,6 +74,8 @@ def test_schema_params_cover_every_shape(self):
assert "query" in params
assert "limit" in params
assert params["sort"]["enum"] == ["newest", "oldest"]
assert params["detail"]["enum"] == ["adaptive", "full"]
assert params["detail"]["default"] == "adaptive"
# Scroll shape
assert "session_id" in params
assert "around_message_id" in params
Expand All @@ -81,6 +85,22 @@ def test_schema_params_cover_every_shape(self):
# Mode is inferred from which args are set — no explicit mode param
assert "mode" not in params

def test_detail_parameter_is_appended_for_positional_compatibility(self):
parameters = list(inspect.signature(session_search).parameters)
historical_prefix = [
"query",
"role_filter",
"limit",
"db",
"current_session_id",
"session_id",
"around_message_id",
"window",
"sort",
"profile",
]
assert parameters == [*historical_prefix, "detail"]


class TestFormatTimestamp:
def test_formats_unix_and_passes_through_the_rest(self):
Expand Down Expand Up @@ -132,17 +152,22 @@ def search_spy(*args, **kwargs):
assert "context" not in requested_fields
assert len(result["results"]) == 1
hit = result["results"][0]
assert hit["detail"] == "full"
assert "bookend_start" in hit
assert hit["messages"]
assert "bookend_end" in hit

def test_discovery_result_has_bookends_and_window(self, db):
def test_full_detail_returns_bookends_and_window_for_every_hit(self, db):
_seed_modpack_sessions(db)
result = json.loads(session_search(query="modpack", limit=3, db=db))
result = json.loads(session_search(
query="modpack", limit=3, detail="full", db=db
))
assert result["success"] is True
assert result["mode"] == "discover"
assert result["detail"] == "full"
assert result["count"] >= 1
for hit in result["results"]:
assert hit["detail"] == "full"
assert "bookend_start" in hit
assert "messages" in hit
assert "bookend_end" in hit
Expand All @@ -151,6 +176,72 @@ def test_discovery_result_has_bookends_and_window(self, db):
assert "messages_before" in hit
assert "messages_after" in hit

def test_default_discovery_keeps_top_full_and_compacts_lower_hits(self, db):
_seed_modpack_sessions(db)

result = json.loads(session_search(query="modpack", limit=3, db=db))

assert result["success"] is True
assert result["detail"] == "adaptive"
assert len(result["results"]) == 3

top, *lower = result["results"]
assert top["detail"] == "full"
assert "bookend_start" in top
assert len(top["messages"]) > 1
assert "bookend_end" in top

for hit in lower:
assert hit["detail"] == "compact"
assert hit["bookend_start"] == []
assert len(hit["messages"]) == 1
assert hit["messages"][0]["id"] == hit["match_message_id"]
assert hit["messages"][0]["anchor"] is True
assert hit["bookend_end"] == []

def test_adaptive_detail_preserves_ranking_and_reduces_payload(self, db):
now = int(time.time())
for session_index in range(3):
session_id = f"payload_{session_index}"
db.create_session(session_id, source="cli")
db._conn.execute(
"UPDATE sessions SET started_at = ? WHERE id = ?",
(now - session_index, session_id),
)
for message_index in range(8):
db.append_message(
session_id,
role="user" if message_index % 2 == 0 else "assistant",
content=f"opening {session_index}-{message_index} " + "o" * 2500,
)
db.append_message(
session_id,
role="user",
content=f"payloadneedle anchor {session_index} " + "a" * 3500,
)
for message_index in range(8):
db.append_message(
session_id,
role="assistant" if message_index % 2 == 0 else "user",
content=f"closing {session_index}-{message_index} " + "c" * 2500,
)
db._conn.commit()

adaptive_json = session_search(query="payloadneedle", limit=3, db=db)
full_json = session_search(
query="payloadneedle", limit=3, detail="full", db=db
)
adaptive = json.loads(adaptive_json)
full = json.loads(full_json)

assert [r["session_id"] for r in adaptive["results"]] == [
r["session_id"] for r in full["results"]
]
assert [r["match_message_id"] for r in adaptive["results"]] == [
r["match_message_id"] for r in full["results"]
]
assert len(adaptive_json.encode("utf-8")) < len(full_json.encode("utf-8")) * 0.6


def test_current_session_filtered_out(self, db):
_seed_modpack_sessions(db)
Expand Down
Loading