from __future__ import annotations import io import sys from pathlib import Path import pytest from rich.console import Console sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) from cc_slim.commands import handle_command from cc_slim.engine import Agent, Config from cc_slim.memory import MemoryStore from cc_slim.mode import ModeState from cc_slim.permissions import PermissionChecker from cc_slim.session import SessionStore from cc_slim.tools import build_default_tools def make_workspace(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> tuple[Path, MemoryStore]: home = tmp_path / "home" home.mkdir() monkeypatch.setattr("cc_slim.memory.Path.home", lambda: home) monkeypatch.setattr("cc_slim.session.Path.home", lambda: home) workspace = tmp_path / "workspace" workspace.mkdir() (workspace / "AGENTS.md").write_text("# Workspace Rules\nworkspace-agents\n", encoding="utf-8") skills = workspace / "SKILLS" skills.mkdir() (skills / "a.md").write_text("skill-a\n", encoding="utf-8") memory = MemoryStore(workspace) return workspace, memory def make_agent(monkeypatch: pytest.MonkeyPatch, workspace: Path) -> Agent: monkeypatch.setattr(Agent, "_build_client", lambda self: object()) config = Config(provider="openai", model="test-model", api_key="key", base_url=None) permissions = PermissionChecker(workspace) return Agent(config=config, tools=build_default_tools(workspace), workspace=workspace, permission_checker=permissions) def test_dream_command_is_routed(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: workspace, memory = make_workspace(monkeypatch, tmp_path) output = io.StringIO() console = Console(file=output, force_terminal=False, color_system=None) class DummyAgent: def __init__(self) -> None: self.called = False def dream(self, store: MemoryStore) -> str: self.called = True assert store is memory return "已完成 dream,memory 已更新" agent = DummyAgent() result = handle_command( "/dream", console=console, root=workspace, config=type("ConfigObj", (), {"model": "test-model"})(), store=SessionStore(workspace), memory=memory, mode=ModeState(), permissions=PermissionChecker(workspace), agent=agent, # type: ignore[arg-type] build_agent=lambda *args, **kwargs: agent, render_history=lambda store: None, ) assert agent.called is True assert result is agent assert "已完成 dream,memory 已更新" in output.getvalue() def test_agent_dream_updates_memory_and_refreshes_prompt(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: workspace, memory = make_workspace(monkeypatch, tmp_path) agent = make_agent(monkeypatch, workspace) agent.history = [{"role": "user", "content": "请记住这个项目运行在 Windows 上"}] original_prompt = agent.system_prompt monkeypatch.setattr( agent, "_run_dream_model", lambda current_memory, session_text: """## Constraints - 项目默认运行在 Windows 上 ## Consolidated Facts - 需要优先考虑 PowerShell 兼容性 """, ) result = agent.dream(memory) sections = memory.read_sections() assert result == "已完成 dream,memory 已更新" assert sections["Constraints"] == "- 项目默认运行在 Windows 上" assert sections["Consolidated Facts"] == "- 需要优先考虑 PowerShell 兼容性" assert agent.system_prompt != original_prompt assert "项目默认运行在 Windows 上" in agent.system_prompt def test_dream_does_not_modify_workspace_agents(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: workspace, memory = make_workspace(monkeypatch, tmp_path) agent = make_agent(monkeypatch, workspace) agent.history = [{"role": "user", "content": "记住这个项目使用 uv run"}] agents_before = (workspace / "AGENTS.md").read_text(encoding="utf-8") monkeypatch.setattr( agent, "_run_dream_model", lambda current_memory, session_text: """## Project Memory - 使用 uv run 执行命令 """, ) agent.dream(memory) assert (workspace / "AGENTS.md").read_text(encoding="utf-8") == agents_before def test_system_prompt_layers_remain_in_order(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: workspace, memory = make_workspace(monkeypatch, tmp_path) memory.apply_dream( """## Project Memory - project-memory-marker """ ) agent = make_agent(monkeypatch, workspace) prompt = agent.system_prompt system_index = prompt.index("# cc-slim System") runtime_index = prompt.index("## 运行环境") agents_index = prompt.index("workspace-agents") skills_index = prompt.index("skill-a") memory_index = prompt.index("# Memory") assert system_index < runtime_index < agents_index < skills_index < memory_index