"""End-to-end verification tests for recent fixes.
Verifies:
1. Directory events are written to mount_prefix path
2. IndexService with fs/llm processes directory events
3. Agent skill queries recall from agent space
"""
import pytest
import sys
from pathlib import Path
from unittest.mock import Mock, MagicMock
sys.path.insert(0, str(Path(__file__).parent.parent))
from core.models import RequestContext, TypedQuery
from commit import OutboxStore
from fs.agfs_adapter import AGFSContextFS
from index import OutboxWorker, WorkerConfig
from retrieval.query_planner import QueryPlanner
from providers.llm import MockLLM
from providers.embedder import MockEmbedder
from providers.vector_index import InMemoryVectorIndex
from core.enums import ContextType
@pytest.mark.integration
class TestFixesVerification:
"""Verification tests for recent bug fixes."""
def test_directory_event_uses_mount_prefix(self):
"""Verify directory events are written to correct mount_prefix path."""
mock_client = Mock()
mock_client.mkdir.return_value = None
mock_client.write.return_value = None
mock_fs = Mock()
mock_fs.list_children.return_value = []
store = OutboxStore(client=mock_client, fs=mock_fs, mount_prefix="/custom")
ctx = RequestContext(
account_id="test-acct",
user_id="user-1",
agent_id="agent-1",
session_id="sess-1",
trace_id="trace-1",
)
from core.models import ContextNode
node = ContextNode(
uri="ctx://test-acct/users/user-1/memories/preferences/coffee",
context_type="MEMORY",
category="preference",
level=3,
owner_space="user:user-1",
abstract="Likes coffee",
overview="## Coffee Preference\n\nDark roast",
content="Full content here",
metadata={"status": "ACTIVE"},
)
event = store.register_directory(node, ctx)
assert event.event_type == "UPSERT_DIRECTORY"
assert event.uri == "ctx://test-acct/users/user-1/memories/preferences/"
write_calls = [call[0][0] for call in mock_client.write.call_args_list]
outbox_writes = [p for p in write_calls if ".outbox" in p]
assert len(outbox_writes) > 0
assert any("/custom/accounts/" in p for p in outbox_writes), \
f"Expected /custom/accounts/ in paths: {outbox_writes}"
def test_index_service_with_fs_llm_processes_directory(self):
"""Verify IndexService with fs/llm can process UPSERT_DIRECTORY events."""
mock_client = Mock()
mock_fs = Mock()
mock_fs.list_children.return_value = []
mock_llm = MockLLM()
embedder = MockEmbedder()
vector_index = InMemoryVectorIndex()
from service.index_service import IndexService
service = IndexService(
outbox_store=OutboxStore(client=mock_client, fs=mock_fs),
embedder=embedder,
vector_index=vector_index,
get_account_ids=lambda: ["test-acct"],
fs=mock_fs,
llm=mock_llm,
)
service.start(worker_count=1)
assert service._worker is not None
assert service._worker._fs is mock_fs
assert service._worker._llm is mock_llm
service.stop(wait=True)
def test_agent_skill_query_uses_agent_space(self):
"""Verify SKILL queries use agent_space_name()."""
planner = QueryPlanner()
ctx = RequestContext(
account_id="test-acct",
user_id="user-1",
agent_id="agent-1",
session_id="sess-1",
trace_id="trace-1",
)
queries = planner.plan("how to deploy a service", ctx)
assert len(queries) == 1
assert queries[0].context_type == ContextType.SKILL.value
assert queries[0].owner_space == ctx.agent_space_name(), \
f"Expected {ctx.agent_space_name()}, got {queries[0].owner_space}"
queries = planner.plan("用户偏好是什么", ctx)
assert len(queries) == 1
assert queries[0].context_type == ContextType.MEMORY.value
assert queries[0].owner_space is None, \
f"Expected None for MEMORY, got {queries[0].owner_space}"
def test_overview_append_preserves_existing_content(self):
"""Verify overview_append merges instead of overwriting."""
from commit import ArchiveBuilder
from core.models import WritePlan, CandidateMemory
builder = ArchiveBuilder(llm=MockLLM())
ctx = RequestContext(
account_id="test-acct",
user_id="user-1",
agent_id="agent-1",
session_id="sess-1",
trace_id="trace-1",
)
candidate = CandidateMemory(
category="preference",
owner_scope="user",
routing_key="coffee",
abstract="Likes dark roast",
overview="Prefers dark roast coffee",
content="Full content",
confidence=0.9,
)
existing_overview = "Alice's coffee preference"
new_overview = "She likes dark roast"
plan = WritePlan(
action="merge",
target_uri="ctx://test-acct/users/user-1/memories/preferences/coffee",
merged_fields={
"existing_overview": existing_overview,
"overview_append": new_overview,
},
relation_edges=[],
)
node = builder.build(candidate, plan, ctx)
assert existing_overview in node.overview, \
f"Existing overview '{existing_overview}' not in '{node.overview}'"
assert new_overview in node.overview, \
f"New overview '{new_overview}' not in '{node.overview}'"
def test_content_append_preserves_existing_content(self):
"""Verify content_append merges instead of overwriting."""
from commit import ArchiveBuilder
from core.models import WritePlan, CandidateMemory
builder = ArchiveBuilder(llm=MockLLM())
ctx = RequestContext(
account_id="test-acct",
user_id="user-1",
agent_id="agent-1",
session_id="sess-1",
trace_id="trace-1",
)
candidate = CandidateMemory(
category="preference",
owner_scope="user",
routing_key="coding",
abstract="Coding style",
overview="## Coding Style",
content="New info",
confidence=0.9,
)
existing_content = "## Coding Style\n\n- Uses 4 spaces"
new_content = "- Prefers snake_case"
plan = WritePlan(
action="merge",
target_uri="ctx://test-acct/users/user-1/memories/preferences/coding",
merged_fields={
"existing_content": existing_content,
"content_append": new_content,
},
relation_edges=[],
)
node = builder.build(candidate, plan, ctx)
assert "Uses 4 spaces" in node.content
assert "Prefers snake_case" in node.content