"""Helper script for Robot Framework cost budget tests.""" from __future__ import annotations import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) from cleveragents.application.services.autonomy_guardrail_service import ( AutonomyGuardrailService, ) from cleveragents.application.services.cost_budget_service import CostBudgetService from cleveragents.config.settings import Settings from cleveragents.domain.models.core.cost_budget import ( BudgetLevel, OrgCostAccumulator, SessionCostBudget, ThreadSafeOrgCostAccumulator, ) from cleveragents.domain.models.core.session import Session def _test_session_record() -> None: """Session budget tracks cumulative cost.""" b = SessionCostBudget(max_cost_usd=100.0) b.record_cost(25.0) assert b.total_cost == 25.0 assert abs((b.utilization() or 0) - 0.25) < 0.001 assert abs((b.remaining() or 0) - 75.0) < 0.001 print("session-record-ok") def _test_session_exceeded() -> None: """Session budget detects exceeded.""" b = SessionCostBudget(max_cost_usd=10.0) b.record_cost(15.0) assert b.is_exceeded() print("session-exceeded-ok") def _test_org_record() -> None: """Org accumulator tracks cost.""" acc = OrgCostAccumulator(org_id="org-1", max_cost_usd=500.0) acc.record_cost(100.0) assert abs(acc.total_cost - 100.0) < 0.001 assert abs((acc.utilization() or 0) - 0.2) < 0.001 assert abs((acc.remaining() or 0) - 400.0) < 0.001 print("org-record-ok") def _test_org_exceeded() -> None: """Org accumulator detects exceeded.""" acc = OrgCostAccumulator(org_id="org-1", max_cost_usd=50.0) acc.record_cost(60.0) assert acc.is_exceeded() print("org-exceeded-ok") def _test_thread_safe() -> None: """Thread-safe wrapper delegates correctly.""" inner = OrgCostAccumulator(org_id="safe-org", max_cost_usd=200.0) ts = ThreadSafeOrgCostAccumulator(inner) ts.record_cost(50.0) assert abs(ts.total_cost - 50.0) < 0.001 assert abs((ts.utilization() or 0) - 0.25) < 0.001 snap = ts.snapshot() assert snap.org_id == "safe-org" assert abs(snap.total_cost - 50.0) < 0.001 print("thread-safe-ok") def _test_hierarchy_allow() -> None: """Budget hierarchy allows under all caps.""" svc = CostBudgetService() svc.configure_session_budget("s1", max_cost_usd=100.0) svc.configure_org_budget("o1", max_cost_usd=500.0) svc.configure_session_budget("s1", max_cost_usd=100.0, org_id="o1") result = svc.check_budget_hierarchy("s1", plan_cost=10.0) assert result.allowed is True print("hierarchy-allow-ok") def _test_hierarchy_session_block() -> None: """Budget hierarchy blocks at session level.""" svc = CostBudgetService() svc.configure_session_budget("s2", max_cost_usd=10.0) svc.record_plan_cost("s2", 8.0) result = svc.check_budget_hierarchy("s2", plan_cost=5.0) assert result.allowed is False assert result.exceeded_level == BudgetLevel.SESSION print("hierarchy-session-block-ok") def _test_hierarchy_org_block() -> None: """Budget hierarchy blocks at org level.""" svc = CostBudgetService() svc.configure_session_budget("s3", max_cost_usd=100.0) svc.configure_org_budget("o2", max_cost_usd=10.0) svc.configure_session_budget("s3", max_cost_usd=100.0, org_id="o2") svc.record_plan_cost("s3", 8.0) result = svc.check_budget_hierarchy("s3", plan_cost=5.0) assert result.allowed is False assert result.exceeded_level == BudgetLevel.ORG print("hierarchy-org-block-ok") def _test_hierarchy_plan_block() -> None: """Budget hierarchy blocks at plan level.""" svc = CostBudgetService() svc.configure_session_budget("s4", max_cost_usd=100.0) result = svc.check_budget_hierarchy( "s4", plan_cost=5.0, plan_budget=3.0, plan_spent=0.0 ) assert result.allowed is False assert result.exceeded_level == BudgetLevel.PLAN print("hierarchy-plan-block-ok") def _test_guardrail_hierarchy() -> None: """Guardrail service integrates budget hierarchy.""" cbs = CostBudgetService() cbs.configure_session_budget("gs1", max_cost_usd=10.0) gs = AutonomyGuardrailService(cost_budget_service=cbs) gs.associate_plan_with_session("gp1", "gs1") gs.record_plan_cost_to_session("gp1", 8.0) result = gs.check_budget_hierarchy("gp1", 5.0) assert result.allowed is False assert result.exceeded_level == BudgetLevel.SESSION print("guardrail-hierarchy-ok") def _test_settings_defaults() -> None: """Settings have correct budget defaults.""" s = Settings(_env_file=None) # type: ignore[call-arg] assert s.session_max_cost_usd is None assert s.org_max_cost_usd is None assert abs(s.budget_warning_threshold - 0.8) < 0.001 print("settings-defaults-ok") def _test_session_model() -> None: """Session model includes cost_budget field.""" from ulid import ULID sess = Session( session_id=str(ULID()), cost_budget=SessionCostBudget(max_cost_usd=50.0), ) assert sess.cost_budget.max_cost_usd == 50.0 sess.cost_budget.record_cost(10.0) cli = sess.as_cli_dict() assert "cost_budget" in cli assert cli["cost_budget"]["total_cost"] == 10.0 print("session-model-ok") _TESTS = { "session-record": _test_session_record, "session-exceeded": _test_session_exceeded, "org-record": _test_org_record, "org-exceeded": _test_org_exceeded, "thread-safe": _test_thread_safe, "hierarchy-allow": _test_hierarchy_allow, "hierarchy-session-block": _test_hierarchy_session_block, "hierarchy-org-block": _test_hierarchy_org_block, "hierarchy-plan-block": _test_hierarchy_plan_block, "guardrail-hierarchy": _test_guardrail_hierarchy, "settings-defaults": _test_settings_defaults, "session-model": _test_session_model, } if __name__ == "__main__": if len(sys.argv) < 2 or sys.argv[1] not in _TESTS: print(f"Usage: {sys.argv[0]} <{'|'.join(sorted(_TESTS))}>", file=sys.stderr) sys.exit(1) _TESTS[sys.argv[1]]()