diff --git a/features/steps/project_context_cli_steps.py b/features/steps/project_context_cli_steps.py index 6b80c51d8..80a32acb2 100644 --- a/features/steps/project_context_cli_steps.py +++ b/features/steps/project_context_cli_steps.py @@ -701,7 +701,7 @@ def step_issue6323_seed_usage(context: Any, project: str) -> None: content="hot context fragment", tier=ContextTier.HOT, project_name=project, - resource_id="res:hot", + resource_id="res:repo", token_count=8_420, ) ) @@ -713,7 +713,7 @@ def step_issue6323_seed_usage(context: Any, project: str) -> None: content="warm fragment", tier=ContextTier.WARM, project_name=project, - resource_id=f"res:warm-{idx}", + resource_id="res:repo", token_count=10, ) ) @@ -725,7 +725,7 @@ def step_issue6323_seed_usage(context: Any, project: str) -> None: content="cold fragment", tier=ContextTier.COLD, project_name=project, - resource_id=f"res:cold-{idx}", + resource_id="res:repo", token_count=5, ) ) @@ -735,7 +735,7 @@ def step_issue6323_seed_usage(context: Any, project: str) -> None: "hot_context_tokens": "***REDACTED***", "warm_entries": 12, "cold_entries": 47, - "indexed_resources": 1 + 12 + 47, + "indexed_resources": 1, } ) @@ -757,7 +757,7 @@ def _issue6323_assert_payload( assert parsed["status"] == "ok" assert parsed["exit_code"] == 0 assert "timing" in parsed and "duration_ms" in parsed["timing"] - assert parsed["messages"] == [{"level": "ok", "text": "Context policy loaded"}] + assert parsed["messages"] == ["Context policy loaded"] payload = parsed.get("data") assert payload is not None, "Expected 'data' field in output payload" diff --git a/robot/helper_project_context_cli.py b/robot/helper_project_context_cli.py index 9d29bcecd..4b27e58d8 100644 --- a/robot/helper_project_context_cli.py +++ b/robot/helper_project_context_cli.py @@ -357,14 +357,47 @@ def test_context_show_acms_config() -> None: if exit_code != 0: raise AssertionError(f"show failed with exit {exit_code}: {output}") - data = json.loads(output.strip()) - if "acms_config" not in data: - raise AssertionError(f"Missing acms_config in output: {data.keys()}") - if data["acms_config"]["hot_max_tokens"] != 5000: + envelope = json.loads(output.strip()) + if envelope.get("command") != "project context show": raise AssertionError( - f"hot_max_tokens mismatch: {data['acms_config']['hot_max_tokens']}" + 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") diff --git a/src/cleveragents/cli/commands/project_context.py b/src/cleveragents/cli/commands/project_context.py index 5ffb58855..73f580783 100644 --- a/src/cleveragents/cli/commands/project_context.py +++ b/src/cleveragents/cli/commands/project_context.py @@ -23,7 +23,7 @@ from __future__ import annotations import contextlib import hashlib import json as _json -from typing import Annotated, Any +from typing import Annotated, Any, cast import typer from rich.console import Console @@ -108,7 +108,18 @@ def _load_policy_json( ).fetchone() if row is None or row[0] is None: return None - return _json.loads(row[0]) # type: ignore[no-any-return] + blob = row[0] + if isinstance(blob, (bytes, bytearray)): + raw = blob.decode("utf-8") + else: + raw = str(blob) + loaded = _json.loads(raw) + if not isinstance(loaded, dict): + raise TypeError( + "Stored context_policy_json must be a JSON object, " + f"got {type(loaded).__name__}" + ) + return cast(dict[str, Any], loaded) finally: session.close() @@ -885,7 +896,7 @@ def context_show( fmt = output_format.lower() command_name = "project context show" - success_message = {"level": "ok", "text": "Context policy loaded"} + success_message = "Context policy loaded" if fmt == OutputFormat.RICH: policy_lines = [ @@ -952,9 +963,6 @@ def context_show( if rendered: console.print(rendered) - if fmt == OutputFormat.PLAIN.value: - console.print("[OK] Context policy loaded") - @app.command(name="inspect") def context_inspect(