Files
cleveragents-core/robot/helper_skeleton_compressor.py
T
freemo fae438a7a7
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 15s
CI / build (pull_request) Successful in 15s
CI / quality (pull_request) Successful in 17s
CI / security (pull_request) Successful in 33s
CI / typecheck (pull_request) Successful in 35s
CI / unit_tests (pull_request) Successful in 2m22s
CI / integration_tests (pull_request) Successful in 3m0s
CI / docker (pull_request) Successful in 39s
CI / coverage (pull_request) Successful in 4m21s
CI / lint (push) Successful in 14s
CI / quality (push) Successful in 16s
CI / build (push) Successful in 16s
CI / security (push) Successful in 30s
CI / typecheck (push) Successful in 36s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 3m38s
CI / docker (push) Successful in 39s
CI / integration_tests (push) Successful in 4m25s
CI / coverage (push) Successful in 4m19s
CI / benchmark-publish (push) Successful in 15m57s
CI / benchmark-regression (pull_request) Successful in 28m50s
refactor(acms): unify ContextFragment model hierarchies by extending CRP base types
Core domain types (FragmentProvenance, ContextFragment, ContextBudget,
ContextPayload) now extend their CRP counterparts via Pydantic v2
inheritance, ensuring isinstance compatibility across the model
hierarchy.

Key changes:
- CRP base types made frozen=True (no consumer mutates them)
- CRP AssembledContext fields changed from list to tuple (frozen consistency)
- Core types extend CRP bases: FragmentProvenance(CRPFragmentProvenance),
  ContextFragment(CRPContextFragment), ContextBudget(CRPContextBudget),
  ContextPayload(CRPAssembledContext)
- Removed duplicate ContextFragment dataclass from skeleton_compressor
- Updated project_context.py to pass tuples to frozen AssembledContext
- Added Behave tests (10 scenarios), Robot integration tests (3 cases),
  and ASV benchmarks for the unified hierarchy
- Updated Known Limitations table in docs/reference/acms.md

ISSUES CLOSED: #569
2026-03-05 21:38:55 +00:00

192 lines
5.6 KiB
Python

"""Helper script for skeleton compressor Robot Framework tests.
Usage:
python helper_skeleton_compressor.py compress <ratio>
python helper_skeleton_compressor.py validate-ratio-bounds
python helper_skeleton_compressor.py metadata-fields
python helper_skeleton_compressor.py stable-ordering
"""
from __future__ import annotations
import sys
from pathlib import Path
# Ensure source tree is importable
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
from cleveragents.application.services.skeleton_compressor import ( # noqa: E402
SkeletonCompressorService,
)
from cleveragents.domain.models.core.context_fragment import ( # noqa: E402
ContextFragment,
FragmentProvenance,
)
# Default provenance for skeleton test fragments.
_SKEL_PROV = FragmentProvenance(resource_uri="skeleton://robot-test")
def _make_skel_fragment(
fragment_id: str,
content: str,
token_count: int,
relevance_score: float,
source_decision_id: str | None = None,
) -> ContextFragment:
"""Create a ContextFragment suitable for skeleton compression tests."""
metadata: dict[str, str] = {}
if source_decision_id is not None:
metadata["source_decision_id"] = source_decision_id
return ContextFragment(
fragment_id=fragment_id,
uko_node=f"skeleton://{fragment_id}",
content=content,
token_count=token_count,
relevance_score=relevance_score,
provenance=_SKEL_PROV,
metadata=metadata,
)
def _sample_fragments() -> list[ContextFragment]:
"""Build a repeatable set of sample fragments."""
return [
_make_skel_fragment(
fragment_id="frag-001",
content="High relevance content " * 20,
token_count=400,
relevance_score=0.9,
source_decision_id="01HXDECISION00000000000001",
),
_make_skel_fragment(
fragment_id="frag-002",
content="Medium relevance content " * 15,
token_count=300,
relevance_score=0.6,
source_decision_id="01HXDECISION00000000000002",
),
_make_skel_fragment(
fragment_id="frag-003",
content="Low relevance content " * 15,
token_count=300,
relevance_score=0.3,
source_decision_id="01HXDECISION00000000000003",
),
]
def cmd_compress(ratio_str: str) -> None:
"""Compress sample fragments and print summary."""
ratio = float(ratio_str)
svc = SkeletonCompressorService()
result = svc.compress(_sample_fragments(), skeleton_ratio=ratio)
meta = result.metadata
print(f"skeleton-compress-ok ratio={meta.ratio}")
print(f"original_tokens={meta.original_tokens}")
print(f"compressed_tokens={meta.compressed_tokens}")
print(f"fragment_count={len(result.fragments)}")
print(f"decision_ids={len(meta.source_decision_ids)}")
def cmd_validate_ratio_bounds() -> None:
"""Verify that out-of-range ratios raise ValueError."""
svc = SkeletonCompressorService()
frags = _sample_fragments()
for bad in (-0.1, 1.5, 2.0):
try:
svc.compress(frags, skeleton_ratio=bad)
print(f"FAIL: ratio {bad} did not raise")
sys.exit(1)
except ValueError:
pass
# Valid bounds
for good in (0.0, 0.5, 1.0):
svc.compress(frags, skeleton_ratio=good)
print("skeleton-ratio-bounds-ok")
def cmd_metadata_fields() -> None:
"""Verify metadata fields are populated correctly."""
svc = SkeletonCompressorService()
result = svc.compress(_sample_fragments(), skeleton_ratio=0.5)
meta = result.metadata
checks_passed = True
if meta.ratio != 0.5:
print(f"FAIL: ratio={meta.ratio}")
checks_passed = False
if meta.original_tokens != 1000:
print(f"FAIL: original_tokens={meta.original_tokens}")
checks_passed = False
if meta.compressed_tokens > 500:
print(f"FAIL: compressed_tokens={meta.compressed_tokens} > 500")
checks_passed = False
if not meta.source_decision_ids:
print("FAIL: no decision IDs")
checks_passed = False
if checks_passed:
print("skeleton-metadata-ok")
else:
sys.exit(1)
def cmd_stable_ordering() -> None:
"""Verify fragments come out in deterministic order."""
svc = SkeletonCompressorService()
frags = [
_make_skel_fragment(
fragment_id=f"frag-{chr(ord('c') - i)}",
content="x",
token_count=10,
relevance_score=0.5,
)
for i in range(3)
]
r1 = svc.compress(frags, skeleton_ratio=0.0)
r2 = svc.compress(list(reversed(frags)), skeleton_ratio=0.0)
ids1 = [f.fragment_id for f in r1.fragments]
ids2 = [f.fragment_id for f in r2.fragments]
if ids1 == ids2:
print("skeleton-stable-ordering-ok")
else:
print(f"FAIL: {ids1} != {ids2}")
sys.exit(1)
def main() -> None:
"""Dispatch subcommand."""
if len(sys.argv) < 2:
print("Usage: helper_skeleton_compressor.py <command> [args]")
sys.exit(1)
cmd = sys.argv[1]
if cmd == "compress":
if len(sys.argv) < 3:
print("Usage: compress <ratio>")
sys.exit(1)
cmd_compress(sys.argv[2])
elif cmd == "validate-ratio-bounds":
cmd_validate_ratio_bounds()
elif cmd == "metadata-fields":
cmd_metadata_fields()
elif cmd == "stable-ordering":
cmd_stable_ordering()
else:
print(f"Unknown command: {cmd}")
sys.exit(1)
if __name__ == "__main__":
main()