"""Tests for run_contextual_stream. These tests monkeypatch _run_single_agent_stream (the actual internal runner) rather than the plan's fictional _run_agent_loop, matching the real deep_agent.py architecture. """ import pytest from unittest.mock import AsyncMock, MagicMock, patch from app.schemas.contextual import ContextualScope @pytest.mark.asyncio async def test_run_contextual_stream_includes_scope_block(monkeypatch): """run_contextual_stream must inject the scope block into the system prompt and include get_page_details in the tool list while excluding note-edit tools.""" import app.core.deep_agent as deep_agent captured = {} async def fake_stream( *, user_id, system_prompt, message, context, agent_name="agent", tools=None, conversation_history=None, **kwargs, ): captured["sys"] = system_prompt captured["tool_names"] = [getattr(t, "name", str(t)) for t in (tools or [])] captured["agent_name"] = agent_name # Async generator that yields nothing — still satisfies the protocol. if False: yield # pragma: no cover monkeypatch.setattr(deep_agent, "_run_single_agent_stream", fake_stream) scope = ContextualScope( page="project", entity_type="project", entity_id="p1", entity_name="Acme", counts={"tasks": 1, "notes": 0, "milestones": 0}, ) context = { "conversation_history": [], "_debug": {"session_id": "s1"}, } results = [] async for item in deep_agent.run_contextual_stream( user_id="user1", message="hi", context=context, scope=scope, ): results.append(item) assert "Acme" in captured["sys"], "scope block must appear in system prompt" assert "Current view" in captured["sys"], "section header must be present" names = captured["tool_names"] assert "get_page_details" in names, "get_page_details tool must be included" # Entity-create tools: at least one of these must be present. assert any(n in names for n in ("create_task", "create_note", "update_task")), ( "at least one entity-create tool must be present" ) assert "create_timeline" in names, "create_timeline tool must be included" # Note edit tools must NOT be exposed. assert "propose_note_edit" not in names, "propose_note_edit must be excluded"