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.
- {haliosai_cli-2.0.8/haliosai_cli.egg-info → haliosai_cli-2.0.9}/PKG-INFO +3 -3
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/README.md +2 -2
- haliosai_cli-2.0.9/halios_cli/_version.py +1 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_eval.py +37 -3
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_support.py +27 -1
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9/haliosai_cli.egg-info}/PKG-INFO +3 -3
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/tests/test_cli_surface.py +56 -1
- haliosai_cli-2.0.8/halios_cli/_version.py +0 -1
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/LICENSE +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/MANIFEST.in +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/__init__.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_auth.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_optimize.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_project.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_scenario.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/cli_trace.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/discovery.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/py.typed +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/schemas/__init__.py +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/schemas/discovery.schema.json +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/schemas/eval.schema.json +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/halios_cli/schemas/scenarios.schema.json +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/SOURCES.txt +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/dependency_links.txt +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/entry_points.txt +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/requires.txt +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/haliosai_cli.egg-info/top_level.txt +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/pyproject.toml +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/setup.cfg +0 -0
- {haliosai_cli-2.0.8 → haliosai_cli-2.0.9}/tests/test_discovery.py +0 -0
- {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.
|
|
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.
|
|
101
|
+
uv tool install 'haliosai-cli>=2.0.9'
|
|
102
102
|
|
|
103
103
|
# Or install with pipx
|
|
104
|
-
pipx install 'haliosai-cli>=2.0.
|
|
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.
|
|
64
|
+
uv tool install 'haliosai-cli>=2.0.9'
|
|
65
65
|
|
|
66
66
|
# Or install with pipx
|
|
67
|
-
pipx install 'haliosai-cli>=2.0.
|
|
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
|
|
789
|
-
if
|
|
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
|
-
|
|
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.
|
|
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.
|
|
101
|
+
uv tool install 'haliosai-cli>=2.0.9'
|
|
102
102
|
|
|
103
103
|
# Or install with pipx
|
|
104
|
-
pipx install 'haliosai-cli>=2.0.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|