4221582368
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 15s
CI / quality (pull_request) Successful in 19s
CI / security (pull_request) Successful in 34s
CI / typecheck (pull_request) Successful in 36s
CI / unit_tests (pull_request) Successful in 2m28s
CI / docker (pull_request) Successful in 38s
CI / integration_tests (pull_request) Successful in 3m11s
CI / coverage (pull_request) Successful in 4m27s
CI / lint (push) Successful in 13s
CI / build (push) Successful in 15s
CI / quality (push) Successful in 16s
CI / security (push) Successful in 33s
CI / typecheck (push) Successful in 34s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m21s
CI / docker (push) Successful in 42s
CI / integration_tests (push) Successful in 3m12s
CI / coverage (push) Successful in 5m6s
CI / benchmark-publish (push) Successful in 17m3s
CI / benchmark-regression (pull_request) Successful in 31m31s
Implemented the remaining ACMS pipeline components and advanced context strategies: Pipeline Phase 3: - FragmentOrdererProtocol + RelevanceCoherenceOrderer: orders fragments by relevance while maintaining narrative coherence via UKO node prefix grouping. Groups related fragments together, sorts groups by max relevance, and within groups orders by relevance desc / depth asc. - PreambleGeneratorProtocol + ProvenancePreambleGenerator: generates provenance preamble with strategy contributions (fragment counts and token percentages), confidence indicators (avg/min/max), tier and depth distribution, UKO node coverage, and coverage gap detection. Advanced Strategies: - ArceStrategy (quality 0.95): adaptive recursive context expansion with iterative multi-backend refinement and configurable iteration limit (default 5) to prevent unbounded refinement. Uses composite scoring (relevance + depth + diversity) with contextual boosting for fragments related to the current top-ranked anchor set. - TemporalArchaeologyStrategy (quality 0.5): historical context retrieval from graph+cold backends. Prioritises cold-tier fragments using a temporal scoring model (tier bonus + relevance + depth). - PlanDecisionContextStrategy (quality 0.7): decision history retrieval from warm/cold backends. Prioritises warm then cold tier fragments for correction and retry scenarios. All strategies registered in strategy registry with correct quality scores and backend requirements. All components implement their respective Protocol interfaces and can be injected into the ContextAssemblyPipeline via constructor dependency injection. Tests: - 33 BDD scenarios in features/acms_pipeline_phase3.feature - Robot Framework integration tests in robot/acms_pipeline_phase3.robot - ASV performance benchmarks in benchmarks/acms_pipeline_phase3_bench.py ISSUES CLOSED: #545
229 lines
7.3 KiB
Python
229 lines
7.3 KiB
Python
"""Robot Framework helper for ACMS pipeline Phase 3 integration tests.
|
|
|
|
Provides a CLI-style interface for Robot to invoke Phase 3 pipeline
|
|
components and verify the results. Exit code 0 = success, 1 = failure.
|
|
|
|
Usage:
|
|
python robot/helper_acms_pipeline_phase3.py orderer-basic
|
|
python robot/helper_acms_pipeline_phase3.py preamble-generate
|
|
python robot/helper_acms_pipeline_phase3.py arce-strategy
|
|
python robot/helper_acms_pipeline_phase3.py temporal-strategy
|
|
python robot/helper_acms_pipeline_phase3.py plan-decision-strategy
|
|
python robot/helper_acms_pipeline_phase3.py pipeline-integration
|
|
"""
|
|
|
|
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.application.services.acms_advanced_strategies import ( # noqa: E402
|
|
ArceStrategy,
|
|
PlanDecisionContextStrategy,
|
|
TemporalArchaeologyStrategy,
|
|
)
|
|
from cleveragents.application.services.acms_phase3 import ( # noqa: E402
|
|
ProvenancePreambleGenerator,
|
|
RelevanceCoherenceOrderer,
|
|
)
|
|
from cleveragents.application.services.acms_service import ACMSPipeline # noqa: E402
|
|
from cleveragents.domain.models.core.context_fragment import ( # noqa: E402
|
|
ContextBudget,
|
|
ContextFragment,
|
|
FragmentProvenance,
|
|
)
|
|
|
|
_DEFAULT_PROV = FragmentProvenance(resource_uri="test://robot-phase3")
|
|
_PLAN_ID = "01JQTESTPN00000000000000DD"
|
|
|
|
|
|
def _frag(
|
|
uko_node: str = "test://default",
|
|
content: str = "test content",
|
|
score: float = 0.5,
|
|
tokens: int = 10,
|
|
depth: int = 0,
|
|
tier: str = "warm",
|
|
strategy_source: str = "",
|
|
) -> ContextFragment:
|
|
return ContextFragment(
|
|
uko_node=uko_node,
|
|
content=content,
|
|
relevance_score=score,
|
|
token_count=tokens,
|
|
detail_depth=depth,
|
|
tier=tier,
|
|
strategy_source=strategy_source,
|
|
provenance=_DEFAULT_PROV,
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Test commands
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def _test_orderer_basic() -> None:
|
|
"""Test RelevanceCoherenceOrderer groups and orders fragments."""
|
|
orderer = RelevanceCoherenceOrderer()
|
|
frags = [
|
|
_frag("project://app/io.py", "io module", 0.9, 20, 3),
|
|
_frag("project://app/main.py", "main entry", 0.5, 15, 3),
|
|
_frag("project://lib/util.py", "utility", 0.7, 25, 3),
|
|
_frag("project://app/net.py", "network", 0.8, 10, 3),
|
|
]
|
|
result = list(orderer.order(frags))
|
|
assert len(result) == 4, f"Expected 4, got {len(result)}"
|
|
# First fragment should be from the highest-relevance group
|
|
assert result[0].relevance_score == 0.9
|
|
print("phase3-orderer-ok")
|
|
|
|
|
|
def _test_preamble_generate() -> None:
|
|
"""Test ProvenancePreambleGenerator produces structured preamble."""
|
|
gen = ProvenancePreambleGenerator()
|
|
frags = [
|
|
_frag(
|
|
"project://app/main.py",
|
|
"hello",
|
|
0.8,
|
|
100,
|
|
3,
|
|
strategy_source="relevance",
|
|
),
|
|
_frag(
|
|
"project://app/io.py",
|
|
"world",
|
|
0.6,
|
|
50,
|
|
5,
|
|
strategy_source="arce",
|
|
),
|
|
]
|
|
preamble = gen.generate(frags)
|
|
assert preamble is not None
|
|
assert "Strategy Contributions" in preamble
|
|
assert "relevance" in preamble
|
|
assert "arce" in preamble
|
|
assert "Confidence" in preamble
|
|
|
|
# Empty list returns None
|
|
assert gen.generate([]) is None
|
|
print("phase3-preamble-ok")
|
|
|
|
|
|
def _test_arce_strategy() -> None:
|
|
"""Test ArceStrategy iterative refinement."""
|
|
strategy = ArceStrategy(max_iterations=3)
|
|
assert strategy.name == "arce"
|
|
assert strategy.can_handle({}) == 0.95
|
|
assert strategy.capabilities.supports_semantic_search
|
|
|
|
frags = [
|
|
_frag("project://app/io.py", "async IO handler", 0.7, 20, 5),
|
|
_frag("project://app/main.py", "main application", 0.5, 15, 3),
|
|
]
|
|
budget = ContextBudget(max_tokens=1000, reserved_tokens=0)
|
|
result = list(strategy.assemble(frags, budget))
|
|
assert len(result) > 0
|
|
total = sum(f.token_count for f in result)
|
|
assert total <= 1000
|
|
|
|
# Empty input
|
|
assert list(strategy.assemble([], budget)) == []
|
|
print("phase3-arce-ok")
|
|
|
|
|
|
def _test_temporal_strategy() -> None:
|
|
"""Test TemporalArchaeologyStrategy cold-tier preference."""
|
|
strategy = TemporalArchaeologyStrategy()
|
|
assert strategy.name == "temporal-archaeology"
|
|
assert strategy.can_handle({}) == 0.5
|
|
|
|
frags = [
|
|
_frag("project://app/old.py", "archived", 0.5, 20, 3, tier="cold"),
|
|
_frag("project://app/new.py", "recent", 0.9, 15, 3, tier="hot"),
|
|
]
|
|
budget = ContextBudget(max_tokens=1000, reserved_tokens=0)
|
|
result = list(strategy.assemble(frags, budget))
|
|
assert len(result) > 0
|
|
# Cold-tier should be first
|
|
assert result[0].tier == "cold"
|
|
|
|
assert list(strategy.assemble([], budget)) == []
|
|
print("phase3-temporal-ok")
|
|
|
|
|
|
def _test_plan_decision_strategy() -> None:
|
|
"""Test PlanDecisionContextStrategy warm/cold preference."""
|
|
strategy = PlanDecisionContextStrategy()
|
|
assert strategy.name == "plan-decision-context"
|
|
assert strategy.can_handle({}) == 0.7
|
|
|
|
frags = [
|
|
_frag("project://app/plan.py", "decision", 0.7, 20, 3, tier="warm"),
|
|
_frag("project://app/new.py", "new code", 0.9, 15, 3, tier="hot"),
|
|
]
|
|
budget = ContextBudget(max_tokens=1000, reserved_tokens=0)
|
|
result = list(strategy.assemble(frags, budget))
|
|
assert len(result) > 0
|
|
# Warm-tier should be first
|
|
assert result[0].tier == "warm"
|
|
|
|
assert list(strategy.assemble([], budget)) == []
|
|
print("phase3-plan-decision-ok")
|
|
|
|
|
|
def _test_pipeline_integration() -> None:
|
|
"""Test Phase 3 components injected into ACMSPipeline."""
|
|
pipeline = ACMSPipeline(
|
|
orderer=RelevanceCoherenceOrderer(),
|
|
preamble_generator=ProvenancePreambleGenerator(),
|
|
)
|
|
frags = [
|
|
_frag("project://app/main.py", "hello", 0.8, 10, 3),
|
|
_frag("project://lib/util.py", "world", 0.6, 15, 5),
|
|
]
|
|
budget = ContextBudget(max_tokens=100000, reserved_tokens=0)
|
|
payload = pipeline.assemble(
|
|
plan_id=_PLAN_ID,
|
|
fragments=frags,
|
|
budget=budget,
|
|
)
|
|
assert len(payload.fragments) == 2
|
|
assert payload.preamble is not None
|
|
assert "Context Assembly Provenance" in payload.preamble
|
|
print("phase3-pipeline-ok")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Dispatcher
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_TESTS: dict[str, Callable[[], None]] = {
|
|
"orderer-basic": _test_orderer_basic,
|
|
"preamble-generate": _test_preamble_generate,
|
|
"arce-strategy": _test_arce_strategy,
|
|
"temporal-strategy": _test_temporal_strategy,
|
|
"plan-decision-strategy": _test_plan_decision_strategy,
|
|
"pipeline-integration": _test_pipeline_integration,
|
|
}
|
|
|
|
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)
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
sys.exit(1)
|