fix(cli): align project context show structured output
ISSUES CLOSED: #6323
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user