"""Helper script for project context CLI Robot Framework tests. Usage: python robot/helper_project_context_cli.py """ from __future__ import annotations import json import sys from io import StringIO from typing import Any from unittest.mock import MagicMock, patch from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from cleveragents.application.services.context_tiers import ContextTierService from cleveragents.domain.models.acms.tiers import ( ContextTier, TieredFragment, ) from cleveragents.domain.models.core.context_policy import ( ContextView, ProjectContextPolicy, ) from cleveragents.domain.models.core.project import ( NamespacedProject, parse_namespaced_name, ) from cleveragents.infrastructure.database.models import Base from cleveragents.infrastructure.database.repositories import ( NamespacedProjectRepository, ) class _NoClose: """Session wrapper that no-ops close().""" def __init__(self, s: object) -> None: object.__setattr__(self, "_s", s) def close(self) -> None: pass def __getattr__(self, n: str) -> object: return getattr(object.__getattribute__(self, "_s"), n) def _setup_db() -> tuple[NamespacedProjectRepository, Any]: """Create in-memory SQLite DB, return (repo, session_factory).""" engine = create_engine("sqlite:///:memory:", echo=False) Base.metadata.create_all(engine) session = sessionmaker(bind=engine, expire_on_commit=False)() wrapper = _NoClose(session) def factory() -> object: return wrapper repo = NamespacedProjectRepository(session_factory=factory) return repo, factory def _create_project( repo: NamespacedProjectRepository, name: str, ) -> None: parsed = parse_namespaced_name(name) proj = NamespacedProject( name=parsed.name, namespace=parsed.namespace, ) repo.create(proj) def _make_mock_container( repo: NamespacedProjectRepository, session_factory: Any, tier_service: ContextTierService | None = None, ) -> MagicMock: """Build a mock DI container wired to the test fixtures.""" mock_container = MagicMock() mock_container.namespaced_project_repo.return_value = repo mock_container.session_factory.return_value = session_factory if tier_service is None: tier_service = ContextTierService() mock_container.context_tier_service.return_value = tier_service return mock_container def _capturing_format_output(data: Any, format_type: str) -> str: """Wrapper around ``format_output`` that captures stdout writes. ``format_output`` for machine-readable formats (json, yaml, plain) writes directly to ``sys.stdout`` and returns ``""``. This wrapper redirects ``sys.stdout`` only during the ``format_output`` call so that the rendered content is returned as a string, allowing the caller's ``console.print(result)`` to write it to the test's Rich console buffer. Structlog noise that would otherwise pollute the captured stdout is excluded because the redirect is scoped tightly. """ import sys as _sys from cleveragents.cli.formatting import format_output as _real_format_output buf = StringIO() old = _sys.stdout _sys.stdout = buf try: ret = _real_format_output(data, format_type) finally: _sys.stdout = old return ret or buf.getvalue().rstrip("\n") def _run_cli_func( func: Any, repo: NamespacedProjectRepository, session_factory: Any, tier_service: ContextTierService | None = None, **kwargs: Any, ) -> tuple[int, str]: """Execute a CLI function with mocked DI and capture output.""" import typer from rich.console import Console as RichConsole mock_cont = _make_mock_container(repo, session_factory, tier_service) buf = StringIO() test_console = RichConsole( file=buf, no_color=True, highlight=False, force_terminal=False, width=500, soft_wrap=True, ) exit_code = 0 with ( patch( "cleveragents.application.container.get_container", return_value=mock_cont, ), patch( "cleveragents.cli.commands.project_context.console", test_console, ), patch( "cleveragents.cli.commands.project_context.err_console", test_console, ), patch( "cleveragents.cli.commands.project_context.format_output", _capturing_format_output, ), ): try: func(**kwargs) except typer.Exit as exc: exit_code = exc.exit_code except typer.Abort: exit_code = 1 return exit_code, buf.getvalue() def test_context_set_show() -> None: """Set a context policy and then read it back.""" from cleveragents.cli.commands.project_context import ( _read_policy, _write_policy, ) repo, sf = _setup_db() _create_project(repo, "ctx-robot") # Write a policy policy = ProjectContextPolicy( default_view=ContextView( include_resources=["db-*"], exclude_paths=["*.pyc"], max_file_size=1048576, ), strategize_view=ContextView( include_resources=["cache-*"], ), ) _write_policy(sf, "local/ctx-robot", policy) # Read it back loaded = _read_policy(sf, "local/ctx-robot") if loaded.default_view.include_resources != ["db-*"]: raise AssertionError( f"include_resources mismatch: {loaded.default_view.include_resources}" ) if loaded.strategize_view is None: raise AssertionError("strategize_view is None") if loaded.strategize_view.include_resources != ["cache-*"]: raise AssertionError("strategize include_resources mismatch") # Test inheritance resolved = loaded.resolve_view("execute") if resolved.include_resources != ["cache-*"]: raise AssertionError( f"execute should inherit from strategize, got {resolved.include_resources}" ) print("context-set-show-ok") def test_context_inspect_wired() -> None: """Verify inspect is wired to ACMS and succeeds.""" from cleveragents.cli.commands.project_context import context_inspect repo, sf = _setup_db() _create_project(repo, "ctx-robot") tier_svc = ContextTierService() # Pre-populate a fragment tier_svc.store( TieredFragment( fragment_id="robot-f1", content="test fragment", tier=ContextTier.HOT, project_name="local/ctx-robot", token_count=50, ) ) exit_code, output = _run_cli_func( context_inspect, repo, sf, tier_service=tier_svc, project="local/ctx-robot", output_format="json", ) if exit_code != 0: raise AssertionError(f"inspect failed with exit {exit_code}: {output}") data = json.loads(output.strip()) if "tier_metrics" not in data: raise AssertionError(f"Missing tier_metrics in output: {data.keys()}") if "project_fragments" not in data: raise AssertionError(f"Missing project_fragments in output: {data.keys()}") if data["project_fragments"]["total"] != 1: raise AssertionError( f"Expected 1 fragment, got {data['project_fragments']['total']}" ) print("context-inspect-wired-ok") def test_context_simulate_wired() -> None: """Verify simulate is wired to ACMS and succeeds.""" from cleveragents.cli.commands.project_context import context_simulate repo, sf = _setup_db() _create_project(repo, "ctx-robot") tier_svc = ContextTierService() # Pre-populate a fragment for simulation tier_svc.store( TieredFragment( fragment_id="robot-sim1", content="simulation test fragment", tier=ContextTier.HOT, project_name="local/ctx-robot", token_count=100, ) ) exit_code, output = _run_cli_func( context_simulate, repo, sf, tier_service=tier_svc, project="local/ctx-robot", output_format="json", ) if exit_code != 0: raise AssertionError(f"simulate failed with exit {exit_code}: {output}") data = json.loads(output.strip()) if "total_tokens" not in data: raise AssertionError(f"Missing total_tokens in output: {data.keys()}") if data["total_tokens"] <= 0: raise AssertionError( f"Expected positive total_tokens, got {data['total_tokens']}" ) if "strategies_used" not in data: raise AssertionError(f"Missing strategies_used in output: {data.keys()}") print("context-simulate-wired-ok") def test_context_set_acms_options() -> None: """Verify context set persists ACMS pipeline config.""" from cleveragents.cli.commands.project_context import ( _read_acms_config, context_set, ) repo, sf = _setup_db() _create_project(repo, "ctx-robot") exit_code, output = _run_cli_func( context_set, repo, sf, project="local/ctx-robot", hot_max_tokens=4000, warm_max_decisions=200, temporal_scope="recent", auto_refresh=False, ) if exit_code != 0: raise AssertionError(f"set failed with exit {exit_code}: {output}") acms = _read_acms_config(sf, "local/ctx-robot") if acms["hot_max_tokens"] != 4000: raise AssertionError(f"hot_max_tokens mismatch: {acms['hot_max_tokens']}") if acms["warm_max_decisions"] != 200: raise AssertionError( f"warm_max_decisions mismatch: {acms['warm_max_decisions']}" ) if acms["temporal_scope"] != "recent": raise AssertionError(f"temporal_scope mismatch: {acms['temporal_scope']}") if acms["auto_refresh"] is not False: raise AssertionError(f"auto_refresh mismatch: {acms['auto_refresh']}") print("context-set-acms-ok") def test_context_show_acms_config() -> None: """Verify context show includes ACMS config in JSON output.""" from cleveragents.cli.commands.project_context import context_set, context_show repo, sf = _setup_db() _create_project(repo, "ctx-robot") # First set some ACMS config _run_cli_func( context_set, repo, sf, project="local/ctx-robot", hot_max_tokens=5000, ) exit_code, output = _run_cli_func( context_show, repo, sf, project="local/ctx-robot", output_format="json", ) if exit_code != 0: raise AssertionError(f"show failed with exit {exit_code}: {output}") envelope = json.loads(output.strip()) if envelope.get("command") != "project context show": raise AssertionError(f"Unexpected command value: {envelope.get('command')}") payload = envelope.get("data") if not isinstance(payload, dict): raise AssertionError(f"Expected data payload dict, got: {type(payload)!r}") context_policy = payload.get("context_policy") if not isinstance(context_policy, dict): raise AssertionError(f"Missing context_policy in payload: {payload.keys()}") if context_policy.get("project") != "local/ctx-robot": raise AssertionError( f"context_policy project mismatch: {context_policy.get('project')}" ) limits = payload.get("limits") if not isinstance(limits, dict): raise AssertionError(f"Missing limits in payload: {payload.keys()}") if limits.get("hot_max_tokens") != 5000: raise AssertionError(f"hot_max_tokens mismatch: {limits.get('hot_max_tokens')}") if "summarization" not in payload: raise AssertionError( f"Missing summarization section in payload: {payload.keys()}" ) if "current_usage" not in payload: raise AssertionError( f"Missing current_usage section in payload: {payload.keys()}" ) messages = envelope.get("messages") if messages != ["Context policy loaded"]: raise AssertionError(f"Unexpected messages payload: {messages}") print("context-show-acms-ok") TESTS: dict[str, Any] = { "set-show": test_context_set_show, "inspect-wired": test_context_inspect_wired, "simulate-wired": test_context_simulate_wired, "set-acms": test_context_set_acms_options, "show-acms": test_context_show_acms_config, } if __name__ == "__main__": if len(sys.argv) < 2 or sys.argv[1] not in TESTS: print( f"Usage: {sys.argv[0]} <{'|'.join(TESTS)}>", file=sys.stderr, ) sys.exit(2) try: TESTS[sys.argv[1]]() except Exception as exc: print(f"FAIL: {exc}", file=sys.stderr) sys.exit(1)