haliosai-cli 2.0.8__tar.gz → 2.0.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {haliosai_cli-2.0.8/haliosai_cli.egg-info → haliosai_cli-2.0.9}/PKG-INFO +3 -3
  2. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/README.md +2 -2
  3. haliosai_cli-2.0.9/halios_cli/_version.py +1 -0
  4. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_eval.py +37 -3
  5. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_support.py +27 -1
  6. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9/haliosai_cli.egg-info}/PKG-INFO +3 -3
  7. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/tests/test_cli_surface.py +56 -1
  8. haliosai_cli-2.0.8/halios_cli/_version.py +0 -1
  9. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/LICENSE +0 -0
  10. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/MANIFEST.in +0 -0
  11. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/__init__.py +0 -0
  12. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli.py +0 -0
  13. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_auth.py +0 -0
  14. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_optimize.py +0 -0
  15. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_project.py +0 -0
  16. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_scenario.py +0 -0
  17. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_trace.py +0 -0
  18. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/discovery.py +0 -0
  19. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/py.typed +0 -0
  20. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/schemas/__init__.py +0 -0
  21. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/schemas/discovery.schema.json +0 -0
  22. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/schemas/eval.schema.json +0 -0
  23. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/schemas/scenarios.schema.json +0 -0
  24. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/SOURCES.txt +0 -0
  25. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/dependency_links.txt +0 -0
  26. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/entry_points.txt +0 -0
  27. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/requires.txt +0 -0
  28. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/top_level.txt +0 -0
  29. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/pyproject.toml +0 -0
  30. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/setup.cfg +0 -0
  31. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/tests/test_discovery.py +0 -0
  32. {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/tests/test_skill_examples.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haliosai-cli
3
- Version: 2.0.8
3
+ Version: 2.0.9
4
4
  Summary: Halios CLI for coding-agent evaluations, guardrails, and OpenTelemetry evidence
5
5
  Author-email: HaliosLabs <support@halios.ai>
6
6
  License-Expression: Apache-2.0
@@ -98,10 +98,10 @@ If you prefer to drive evaluations directly from the command line or CI:
98
98
 
99
99
  ```bash
100
100
  # Recommended: Install with uv tool
101
- uv tool install 'haliosai-cli>=2.0.7'
101
+ uv tool install 'haliosai-cli>=2.0.9'
102
102
 
103
103
  # Or install with pipx
104
- pipx install 'haliosai-cli>=2.0.7'
104
+ pipx install 'haliosai-cli>=2.0.9'
105
105
 
106
106
  # See available commands and usage
107
107
  halios --help
@@ -61,10 +61,10 @@ If you prefer to drive evaluations directly from the command line or CI:
61
61
 
62
62
  ```bash
63
63
  # Recommended: Install with uv tool
64
- uv tool install 'haliosai-cli>=2.0.7'
64
+ uv tool install 'haliosai-cli>=2.0.9'
65
65
 
66
66
  # Or install with pipx
67
- pipx install 'haliosai-cli>=2.0.7'
67
+ pipx install 'haliosai-cli>=2.0.9'
68
68
 
69
69
  # See available commands and usage
70
70
  halios --help
@@ -0,0 +1 @@
1
+ __version__ = "2.0.9"
@@ -782,12 +782,38 @@ def _verify_simulation_telemetry(
782
782
 
783
783
 
784
784
  def _raise_for_failed_run(report: dict[str, Any], run_id: str) -> None:
785
+ trials = [trial for trial in (report.get("trials") or []) if isinstance(trial, dict)]
786
+ quota_trials = [
787
+ trial
788
+ for trial in trials
789
+ if trial.get("completeness_status") == "incomplete_quota"
790
+ or trial.get("outcome") == "ineligible"
791
+ or "managed ai allowance" in str(trial.get("error") or "").lower()
792
+ or "monthly allowance" in str(trial.get("error") or "").lower()
793
+ or "quota" in str(trial.get("error") or "").lower()
794
+ ]
795
+ if quota_trials or report.get("completeness_status") == "incomplete_quota":
796
+ run_url = str((report.get("links") or {}).get("evaluation_run") or "")
797
+ parsed_run_url = urllib.parse.urlsplit(run_url)
798
+ if parsed_run_url.scheme in {"http", "https"} and parsed_run_url.hostname:
799
+ billing_origin = urllib.parse.urlunsplit(
800
+ (parsed_run_url.scheme, parsed_run_url.netloc, "", "", "")
801
+ )
802
+ billing_url = f"{billing_origin}/settings/billing"
803
+ else:
804
+ billing_url = "https://app.halios.ai/settings/billing"
805
+ raise typer.BadParameter(
806
+ f"Evaluation run {run_id} marked incomplete_quota: monthly usage allowance reached.\n"
807
+ "Stop automated retries. Enable pay-as-you-go or wait for the monthly reset.\n"
808
+ f"Billing: {billing_url}\n"
809
+ "BYOK is an alternative only when the managed AI token allowance is exhausted."
810
+ )
811
+
785
812
  check_execution_error_count = int(report.get("check_execution_error_count") or 0)
786
813
  failed_trials = [
787
814
  trial
788
- for trial in (report.get("trials") or [])
789
- if isinstance(trial, dict)
790
- and (
815
+ for trial in trials
816
+ if (
791
817
  trial.get("error")
792
818
  or trial.get("state") == "evaluation_failed"
793
819
  or trial.get("outcome") in {"error", "errored", "timed_out", "blocked"}
@@ -1042,6 +1068,14 @@ def run(
1042
1068
  timeout=30,
1043
1069
  )
1044
1070
  if otlp_response.is_error:
1071
+ if otlp_response.status_code == 402:
1072
+ try:
1073
+ detail = otlp_response.json().get("detail", otlp_response.text)
1074
+ except Exception:
1075
+ detail = otlp_response.text
1076
+ from .cli_support import ApiError
1077
+
1078
+ raise ApiError(402, detail)
1045
1079
  raise typer.BadParameter(
1046
1080
  f"OTLP root export failed: {otlp_response.status_code}"
1047
1081
  )
@@ -25,7 +25,33 @@ class ApiError(typer.BadParameter):
25
25
  def __init__(self, status_code: int, detail: Any):
26
26
  self.status_code = status_code
27
27
  self.detail = detail
28
- super().__init__(f"Halios API {status_code}: {detail}")
28
+ if (
29
+ status_code == 402
30
+ and isinstance(detail, dict)
31
+ and detail.get("code") == "usage_limit_exceeded"
32
+ ):
33
+ meter = str(detail.get("meter") or "usage").replace("_", " ")
34
+ remediation = str(
35
+ detail.get("remediation")
36
+ or "Enable pay-as-you-go or wait for the next monthly reset."
37
+ )
38
+ billing_url = str(detail.get("billing_url") or "https://app.halios.ai/settings/billing")
39
+ used = detail.get("used")
40
+ included = detail.get("included")
41
+ usage_str = (
42
+ f" ({used:,} / {included:,} used)"
43
+ if used is not None and included is not None
44
+ else ""
45
+ )
46
+ msg = (
47
+ "Halios usage allowance exhausted: "
48
+ f"Monthly {meter} allowance is exhausted{usage_str}.\n"
49
+ f"{remediation}\n"
50
+ f"Billing: {billing_url}"
51
+ )
52
+ super().__init__(msg)
53
+ else:
54
+ super().__init__(f"Halios API {status_code}: {detail}")
29
55
 
30
56
 
31
57
  def normalize_url(value: str) -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haliosai-cli
3
- Version: 2.0.8
3
+ Version: 2.0.9
4
4
  Summary: Halios CLI for coding-agent evaluations, guardrails, and OpenTelemetry evidence
5
5
  Author-email: HaliosLabs <support@halios.ai>
6
6
  License-Expression: Apache-2.0
@@ -98,10 +98,10 @@ If you prefer to drive evaluations directly from the command line or CI:
98
98
 
99
99
  ```bash
100
100
  # Recommended: Install with uv tool
101
- uv tool install 'haliosai-cli>=2.0.7'
101
+ uv tool install 'haliosai-cli>=2.0.9'
102
102
 
103
103
  # Or install with pipx
104
- pipx install 'haliosai-cli>=2.0.7'
104
+ pipx install 'haliosai-cli>=2.0.9'
105
105
 
106
106
  # See available commands and usage
107
107
  halios --help
@@ -11,11 +11,13 @@ import typer
11
11
  from typer.testing import CliRunner
12
12
 
13
13
  from halios_cli import cli_project, cli_support, cli_trace
14
+ from halios_cli._version import __version__
14
15
  from halios_cli.cli import app
15
16
  from halios_cli.cli_eval import (
16
17
  _eval_schema_errors,
17
18
  _invoke_adapter,
18
19
  _otlp_root_payload,
20
+ _raise_for_failed_run,
19
21
  _scenario_schema_errors,
20
22
  )
21
23
 
@@ -40,7 +42,7 @@ class FakeApiClient:
40
42
 
41
43
  def _patch_trace_context(monkeypatch) -> None:
42
44
  FakeApiClient.calls = []
43
- credentials = SimpleNamespace(ui_base_url="https://app.halios.ai")
45
+ credentials = SimpleNamespace(ui_base_url="https://app.halios.ai", api_key="test")
44
46
  monkeypatch.setattr(cli_trace, "_context", lambda: ("agent-id", credentials))
45
47
  monkeypatch.setattr(cli_trace, "ApiClient", FakeApiClient)
46
48
 
@@ -52,6 +54,20 @@ def test_top_level_exposes_agent_workflows() -> None:
52
54
  assert "trace" in result.output
53
55
 
54
56
 
57
+ def test_skill_install_guidance_requires_current_cli_version() -> None:
58
+ root = pathlib.Path(__file__).resolve().parents[1]
59
+ expected_requirement = f"haliosai-cli>={__version__}"
60
+ expected_compatibility = f"haliosai-cli {__version__} or newer"
61
+
62
+ assert expected_compatibility in (root / "skills/halios/SKILL.md").read_text()
63
+ for relative_path in (
64
+ "README.md",
65
+ "skills/halios/workflows/connect.md",
66
+ "skills/halios/assets/github-actions-eval-gate.yml",
67
+ ):
68
+ assert expected_requirement in (root / relative_path).read_text()
69
+
70
+
55
71
  def test_bundled_eval_example_is_valid_and_balanced() -> None:
56
72
  root = pathlib.Path(__file__).resolve().parents[1]
57
73
  example = cli_support.load_yaml(root / "skills/halios/assets/eval.example.yml")
@@ -321,3 +337,42 @@ def test_eval_quality_gaps_flags_empty_simulator_context() -> None:
321
337
  ]
322
338
  gaps = _eval_quality_gaps(eval_plan={}, scenarios=scenarios)
323
339
  assert any("simulator_context is empty for a multi-turn scenario" in gap for gap in gaps)
340
+
341
+
342
+ def test_api_error_formats_402_usage_limit_exceeded() -> None:
343
+ error = cli_support.ApiError(
344
+ 402,
345
+ {
346
+ "code": "usage_limit_exceeded",
347
+ "meter": "managed_ai_tokens",
348
+ "used": 1031875,
349
+ "included": 1000000,
350
+ "remediation": "Enable overages, use BYOK, or wait for the next monthly reset.",
351
+ "billing_url": "https://app.halios.ai/settings/billing",
352
+ },
353
+ )
354
+ message = str(error)
355
+ assert (
356
+ "Halios usage allowance exhausted: Monthly managed ai tokens allowance is exhausted"
357
+ in message
358
+ )
359
+ assert "1,031,875 / 1,000,000 used" in message
360
+ assert "Enable overages, use BYOK, or wait for the next monthly reset." in message
361
+ assert "https://app.halios.ai/settings/billing" in message
362
+
363
+
364
+ def test_failed_quota_run_uses_report_ui_origin_and_bounds_byok_guidance() -> None:
365
+ report = {
366
+ "trials": [{"completeness_status": "incomplete_quota"}],
367
+ "links": {
368
+ "evaluation_run": "http://localhost:3000/agents/agent-id/evaluations/run-id"
369
+ },
370
+ }
371
+
372
+ with pytest.raises(typer.BadParameter) as exc_info:
373
+ _raise_for_failed_run(report, "run-id")
374
+
375
+ message = str(exc_info.value)
376
+ assert "Stop automated retries" in message
377
+ assert "Billing: http://localhost:3000/settings/billing" in message
378
+ assert "BYOK is an alternative only when the managed AI token allowance" in message
@@ -1 +0,0 @@
1
- __version__ = "2.0.8"
File without changes
File without changes
File without changes