Files
mem0/integrations/agent-plugin-core/tests/test_sidekick.py
T

84 lines
3.3 KiB
Python

"""Exercise bundled subagent hooks as separate host processes, without Mem0 calls."""
import json
import os
import subprocess
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "python"))
from memory_core import EvidenceStore # noqa: E402
@pytest.mark.parametrize("host", ["claude-code", "codex", "kimi", "cursor"])
def test_sidekick_hooks_preserve_parent_scope_and_correlate_completion(tmp_path, host):
parent = tmp_path / "parent"
child = tmp_path / "child-worktree"
parent.mkdir()
child.mkdir()
database = tmp_path / "data" / "evidence.sqlite3"
store = EvidenceStore(database)
repo = store.repo_for_session("parent-session", str(parent))
store.mark_injected("parent-session", repo.identity, [{"id": "one", "memory": "Parent memory marker."}])
store.mark_injected("other-session", repo.identity, [{"id": "two", "memory": "Foreign memory marker."}])
store.close()
plugin = ROOT.parent / f"{host}-plugin"
adapter = plugin / ("adapters/claude/hook.py" if host == "claude-code" else "hooks/adapter.py")
start, stop = "sidekick-start", "sidekick-stop"
payload = {"session_id": "parent-session", "cwd": str(child), "agent_id": "worker", "agent_type": "sidekick"}
response_key = "last_assistant_message"
if host == "kimi":
start, stop = "SubagentStart", "SubagentStop"
payload["agent_name"] = payload.pop("agent_type")
response_key = "response"
elif host == "cursor":
start, stop = "subagentStart", "subagentStop"
payload = {
"conversation_id": "parent-session",
"workspace_roots": [str(child)],
"subagent_id": "worker",
"subagent_type": "sidekick",
}
response_key = "summary"
env = {key: value for key, value in os.environ.items() if not key.startswith(("MEM0_", "CLAUDE_PLUGIN_"))}
env.update(MEM0_CODE_DATA_DIR=str(database.parent), MEM0_TELEMETRY="false", MEM0_API_URL="http://127.0.0.1:1")
def invoke(event, body):
result = subprocess.run(
[sys.executable, str(adapter), event],
input=json.dumps({**body, "hook_event_name": event}),
text=True,
capture_output=True,
env=env,
timeout=15,
check=True,
)
return result.stdout
output = invoke(start, payload)
if host == "cursor":
assert json.loads(output) == {"permission": "allow"}
else:
context = output if host == "kimi" else json.loads(output)["hookSpecificOutput"]["additionalContext"]
assert "Parent memory marker." in context
assert "Foreign memory marker." not in output
assert "Parent memory marker." not in invoke(start, payload)
invoke(stop, {**payload, response_key: "Finished the delegated task."})
store = EvidenceStore(database)
runs = store.conn.execute("SELECT * FROM sidekick_runs").fetchall()
store.close()
assert len(runs) == 1
assert (runs[0]["repo_id"], runs[0]["session_id"], runs[0]["agent_id"]) == (
repo.identity, "parent-session", "worker"
)
assert runs[0]["stopped_at"]
assert runs[0]["final_message"] == "Finished the delegated task."
assert (runs[0]["context_chars"] > 0) == (host != "cursor")