Files
cleveragents-core/robot/helper_unified_context_models.py
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

179 lines
5.3 KiB
Python

"""Robot Framework helper for unified context model integration tests.
Verifies isinstance compatibility across the CRP/core model hierarchy
and basic construction/immutability contracts.
Usage:
python robot/helper_unified_context_models.py isinstance-check
python robot/helper_unified_context_models.py construction-check
python robot/helper_unified_context_models.py immutability-check
"""
from __future__ import annotations
import sys
from collections.abc import Callable
from pathlib import Path
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
from cleveragents.domain.models.acms.crp import ( # noqa: E402
AssembledContext as CRPAssembledContext,
)
from cleveragents.domain.models.acms.crp import ( # noqa: E402
ContextBudget as CRPContextBudget,
)
from cleveragents.domain.models.acms.crp import ( # noqa: E402
ContextFragment as CRPContextFragment,
)
from cleveragents.domain.models.acms.crp import ( # noqa: E402
FragmentProvenance as CRPFragmentProvenance,
)
from cleveragents.domain.models.core.context_fragment import ( # noqa: E402
ContextBudget,
ContextFragment,
ContextPayload,
FragmentProvenance,
)
_DEFAULT_PROV = FragmentProvenance(resource_uri="test://robot-unified")
def _cmd_isinstance_check() -> int:
"""Verify isinstance compatibility for all four model types."""
prov = FragmentProvenance(resource_uri="test://robot")
if not isinstance(prov, CRPFragmentProvenance):
print("FAIL: FragmentProvenance is not instance of CRP type")
return 1
frag = ContextFragment(
uko_node="test://robot",
content="hello",
token_count=5,
provenance=prov,
)
if not isinstance(frag, CRPContextFragment):
print("FAIL: ContextFragment is not instance of CRP type")
return 1
budget = ContextBudget(max_tokens=4096, reserved_tokens=512)
if not isinstance(budget, CRPContextBudget):
print("FAIL: ContextBudget is not instance of CRP type")
return 1
payload = ContextPayload(plan_id="01JQTESTPN00000000000000AA")
if not isinstance(payload, CRPAssembledContext):
print("FAIL: ContextPayload is not instance of CRP AssembledContext")
return 1
print("unified-isinstance-ok")
return 0
def _cmd_construction_check() -> int:
"""Verify construction with inherited and extended fields."""
prov = FragmentProvenance(
resource_uri="test://construct",
strategy="test_strategy",
resource_type="git-checkout",
)
if prov.strategy != "test_strategy":
print(f"FAIL: expected strategy='test_strategy', got {prov.strategy!r}")
return 1
if prov.resource_type != "git-checkout":
print(
f"FAIL: expected resource_type='git-checkout', got {prov.resource_type!r}"
)
return 1
frag = ContextFragment(
uko_node="project://test",
content="constructed fragment",
token_count=20,
tier="hot",
provenance=prov,
)
if frag.tier != "hot":
print(f"FAIL: expected tier='hot', got {frag.tier!r}")
return 1
if not frag.fragment_id:
print("FAIL: fragment_id is empty")
return 1
if len(frag.fragment_id) != 26:
print(f"FAIL: expected ULID (26 chars), got {len(frag.fragment_id)}")
return 1
budget = ContextBudget(max_tokens=8192, reserved_tokens=1024)
if budget.available_tokens != 7168:
print(f"FAIL: expected available=7168, got {budget.available_tokens}")
return 1
print("unified-construction-ok")
return 0
def _cmd_immutability_check() -> int:
"""Verify that frozen models reject mutation."""
frag = ContextFragment(
uko_node="project://immut",
content="test",
token_count=4,
provenance=_DEFAULT_PROV,
)
try:
frag.uko_node = "project://mutated" # type: ignore[misc]
print("FAIL: expected frozen error for ContextFragment mutation")
return 1
except Exception:
pass
budget = ContextBudget(max_tokens=4096, reserved_tokens=512)
try:
budget.max_tokens = 9999 # type: ignore[misc]
print("FAIL: expected frozen error for ContextBudget mutation")
return 1
except Exception:
pass
prov = CRPFragmentProvenance(resource_uri="test://crp")
try:
prov.resource_uri = "test://mutated" # type: ignore[misc]
print("FAIL: expected frozen error for CRP FragmentProvenance mutation")
return 1
except Exception:
pass
print("unified-immutability-ok")
return 0
_COMMANDS: dict[str, Callable[[], int]] = {
"isinstance-check": _cmd_isinstance_check,
"construction-check": _cmd_construction_check,
"immutability-check": _cmd_immutability_check,
}
def main() -> int:
"""Entry point called by Robot Framework ``Run Process``."""
if len(sys.argv) < 2:
print(
"Usage: helper_unified_context_models.py "
"<isinstance-check|construction-check|immutability-check>"
)
return 1
command = sys.argv[1]
handler = _COMMANDS.get(command)
if handler is None:
print(f"Unknown command: {command}")
return 1
return handler()
if __name__ == "__main__":
sys.exit(main())