sys1bench 0.3.0__tar.gz → 0.3.1__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 (86) hide show
  1. {sys1bench-0.3.0 → sys1bench-0.3.1}/PKG-INFO +6 -6
  2. {sys1bench-0.3.0 → sys1bench-0.3.1}/README.md +5 -5
  3. {sys1bench-0.3.0 → sys1bench-0.3.1}/pyproject.toml +2 -2
  4. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/__init__.py +1 -1
  5. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/jev_typesafe.py +9 -2
  6. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/cli.py +50 -14
  7. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/data/__init__.py +21 -4
  8. sys1bench-0.3.1/src/sys1bench/data/configs/example_future_vendor.yaml +18 -0
  9. sys1bench-0.3.1/src/sys1bench/data/configs/hybrid_mock.yaml +4 -0
  10. sys1bench-0.3.1/src/sys1bench/data/configs/jev_1.13.yaml +4 -0
  11. sys1bench-0.3.1/src/sys1bench/data/configs/jev_1.13_openrouter.yaml +3 -0
  12. sys1bench-0.3.1/src/sys1bench/data/configs/laya_en.yaml +6 -0
  13. sys1bench-0.3.1/src/sys1bench/data/configs/laya_typed_decisions.yaml +6 -0
  14. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench.egg-info/PKG-INFO +6 -6
  15. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench.egg-info/SOURCES.txt +6 -0
  16. {sys1bench-0.3.0 → sys1bench-0.3.1}/LICENSE +0 -0
  17. {sys1bench-0.3.0 → sys1bench-0.3.1}/setup.cfg +0 -0
  18. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/__init__.py +0 -0
  19. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/base.py +0 -0
  20. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/embed_knn.py +0 -0
  21. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/encoder_finetuned.py +0 -0
  22. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/generic_http.py +0 -0
  23. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/hybrid_router.py +0 -0
  24. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/jev_openrouter.py +0 -0
  25. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/laya_local.py +0 -0
  26. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/llm_constrained.py +0 -0
  27. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/majority_prior.py +0 -0
  28. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/mock.py +0 -0
  29. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/nli_zeroshot.py +0 -0
  30. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/adapters/regex_keyword.py +0 -0
  31. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/analysis/__init__.py +0 -0
  32. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/analysis/arms.py +0 -0
  33. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/analysis/decision_value.py +0 -0
  34. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/analysis/decomposition.py +0 -0
  35. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/analysis/meta_eval.py +0 -0
  36. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/analysis/stats.py +0 -0
  37. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/data/canary/canary.jsonl +0 -0
  38. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/data/framings/guardrail_intent.yaml +0 -0
  39. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/data/framings/log_triage.yaml +0 -0
  40. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/data/framings/phishing_email.yaml +0 -0
  41. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/data/framings/policy_compliance.yaml +0 -0
  42. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/data/framings/support_tickets.yaml +0 -0
  43. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/framing/__init__.py +0 -0
  44. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/framing/expand.py +0 -0
  45. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/framing/perturb.py +0 -0
  46. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/__init__.py +0 -0
  47. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/base.py +0 -0
  48. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/guardrail_intent.py +0 -0
  49. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/log_triage.py +0 -0
  50. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/multilingual_tickets.py +0 -0
  51. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/phishing_email.py +0 -0
  52. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/policy_compliance.py +0 -0
  53. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/rag_relevance.py +0 -0
  54. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/generators/support_tickets.py +0 -0
  55. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/metrics/__init__.py +0 -0
  56. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/metrics/calibration.py +0 -0
  57. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/metrics/consistency.py +0 -0
  58. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/metrics/decision_value.py +0 -0
  59. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/metrics/efficiency.py +0 -0
  60. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/metrics/ordinal.py +0 -0
  61. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/metrics/robustness.py +0 -0
  62. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/metrics/selective.py +0 -0
  63. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/report/__init__.py +0 -0
  64. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/report/dashboard.py +0 -0
  65. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/report/latex.py +0 -0
  66. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/report/plots.py +0 -0
  67. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/report/results_doc.py +0 -0
  68. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/report/scorecard.py +0 -0
  69. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/__init__.py +0 -0
  70. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/benchmark_runner.py +0 -0
  71. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/cache.py +0 -0
  72. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/canary.py +0 -0
  73. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/hybrid_sweep.py +0 -0
  74. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/noul_consistency.py +0 -0
  75. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/ordinal_probes.py +0 -0
  76. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/robustness.py +0 -0
  77. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/suite.py +0 -0
  78. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/runners/sweeps.py +0 -0
  79. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench/schemas.py +0 -0
  80. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench.egg-info/dependency_links.txt +0 -0
  81. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench.egg-info/entry_points.txt +0 -0
  82. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench.egg-info/requires.txt +0 -0
  83. {sys1bench-0.3.0 → sys1bench-0.3.1}/src/sys1bench.egg-info/top_level.txt +0 -0
  84. {sys1bench-0.3.0 → sys1bench-0.3.1}/tests/test_generators_framing.py +0 -0
  85. {sys1bench-0.3.0 → sys1bench-0.3.1}/tests/test_metrics.py +0 -0
  86. {sys1bench-0.3.0 → sys1bench-0.3.1}/tests/test_runner_end_to_end.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sys1bench
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Benchmark harness for typed System One decision models (choice / score / noul): calibration vs noise floor, framing sensitivity, selective prediction, ordinal fidelity, interference, robustness.
5
5
  Author-email: Rahul Sharma <rsharma@rptu.de>
6
6
  License-Expression: Apache-2.0
@@ -55,8 +55,8 @@ Dynamic: license-file
55
55
  </p>
56
56
 
57
57
  <p align="center">
58
- <a href="https://pypi.org/project/sys1bench/"><img alt="PyPI" src="https://img.shields.io/pypi/v/sys1bench?color=4F46E5&label=PyPI"></a>
59
- <a href="https://pypi.org/project/sys1bench/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/sys1bench?color=06B6D4"></a>
58
+ <a href="https://pypi.org/project/sys1bench/"><img alt="PyPI" src="https://img.shields.io/pypi/v/sys1bench?color=4F46E5&label=PyPI&logo=pypi&logoColor=white&cacheSeconds=3600"></a>
59
+ <a href="https://pypi.org/project/sys1bench/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/sys1bench?color=06B6D4&logo=python&logoColor=white&cacheSeconds=3600"></a>
60
60
  <a href="https://github.com/rssr25/system-one-bench/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/rssr25/system-one-bench/actions/workflows/ci.yml/badge.svg"></a>
61
61
  <a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue.svg"></a>
62
62
  <img alt="Tests" src="https://img.shields.io/badge/tests-31%20passing-brightgreen">
@@ -114,10 +114,10 @@ sys1bench score preds.jsonl prior.jsonl --out summary.json
114
114
  # Jev (hosted, first-party API)
115
115
  echo 'TypeSafe_API_KEY=...' > .env
116
116
  sys1bench canary jev_typesafe --model jev-1.13.0 # 200 fixed items; drift baseline
117
- sys1bench suite all results/jev --config configs/models/jev_1.13.yaml --n 500 --concurrency 4
117
+ sys1bench suite all results/jev --config jev_1.13 --n 500 --concurrency 4 # packaged config; `sys1bench configs` lists them
118
118
 
119
119
  # Laya (local; same manifests as Jev so the comparison is item-for-item)
120
- sys1bench suite all results/laya --config configs/models/laya_en.yaml --manifests-from results/jev --budget
120
+ sys1bench suite all results/laya --config laya_en --manifests-from results/jev --budget
121
121
 
122
122
  # Report, LaTeX tables, HTML dashboard and plots for everything under results/
123
123
  sys1bench report results --latex results/tables.tex --html results/dashboard.html
@@ -132,7 +132,7 @@ sys1bench plots results
132
132
 
133
133
  | Your model | What to do |
134
134
  |---|---|
135
- | Hosted, conventional JSON decisions API | Copy [`configs/models/example_future_vendor.yaml`](configs/models/example_future_vendor.yaml), fill in URL, auth env var and field names. No code. |
135
+ | Hosted, conventional JSON decisions API | `sys1bench configs example_future_vendor > my_model.yaml`, fill in URL, auth env var and field names, run with `--config my_model.yaml`. No code. |
136
136
  | Anything else | Subclass `BaseAdapter`: declare `capabilities` (primitives, max options, state tokens, native abstain, batching) and implement `decide` (state + typed questions in, one probability vector per question out). Register with `@register("my_model")` or the `sys1bench.adapters` entry-point group from your own package. |
137
137
 
138
138
  Capability limits are declared, then measured: a request outside them is recorded as a `capability_issue` or `rejected_by_vendor` row, never a crash.
@@ -3,8 +3,8 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <a href="https://pypi.org/project/sys1bench/"><img alt="PyPI" src="https://img.shields.io/pypi/v/sys1bench?color=4F46E5&label=PyPI"></a>
7
- <a href="https://pypi.org/project/sys1bench/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/sys1bench?color=06B6D4"></a>
6
+ <a href="https://pypi.org/project/sys1bench/"><img alt="PyPI" src="https://img.shields.io/pypi/v/sys1bench?color=4F46E5&label=PyPI&logo=pypi&logoColor=white&cacheSeconds=3600"></a>
7
+ <a href="https://pypi.org/project/sys1bench/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/sys1bench?color=06B6D4&logo=python&logoColor=white&cacheSeconds=3600"></a>
8
8
  <a href="https://github.com/rssr25/system-one-bench/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/rssr25/system-one-bench/actions/workflows/ci.yml/badge.svg"></a>
9
9
  <a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue.svg"></a>
10
10
  <img alt="Tests" src="https://img.shields.io/badge/tests-31%20passing-brightgreen">
@@ -62,10 +62,10 @@ sys1bench score preds.jsonl prior.jsonl --out summary.json
62
62
  # Jev (hosted, first-party API)
63
63
  echo 'TypeSafe_API_KEY=...' > .env
64
64
  sys1bench canary jev_typesafe --model jev-1.13.0 # 200 fixed items; drift baseline
65
- sys1bench suite all results/jev --config configs/models/jev_1.13.yaml --n 500 --concurrency 4
65
+ sys1bench suite all results/jev --config jev_1.13 --n 500 --concurrency 4 # packaged config; `sys1bench configs` lists them
66
66
 
67
67
  # Laya (local; same manifests as Jev so the comparison is item-for-item)
68
- sys1bench suite all results/laya --config configs/models/laya_en.yaml --manifests-from results/jev --budget
68
+ sys1bench suite all results/laya --config laya_en --manifests-from results/jev --budget
69
69
 
70
70
  # Report, LaTeX tables, HTML dashboard and plots for everything under results/
71
71
  sys1bench report results --latex results/tables.tex --html results/dashboard.html
@@ -80,7 +80,7 @@ sys1bench plots results
80
80
 
81
81
  | Your model | What to do |
82
82
  |---|---|
83
- | Hosted, conventional JSON decisions API | Copy [`configs/models/example_future_vendor.yaml`](configs/models/example_future_vendor.yaml), fill in URL, auth env var and field names. No code. |
83
+ | Hosted, conventional JSON decisions API | `sys1bench configs example_future_vendor > my_model.yaml`, fill in URL, auth env var and field names, run with `--config my_model.yaml`. No code. |
84
84
  | Anything else | Subclass `BaseAdapter`: declare `capabilities` (primitives, max options, state tokens, native abstain, batching) and implement `decide` (state + typed questions in, one probability vector per question out). Register with `@register("my_model")` or the `sys1bench.adapters` entry-point group from your own package. |
85
85
 
86
86
  Capability limits are declared, then measured: a request outside them is recorded as a `capability_issue` or `rejected_by_vendor` row, never a crash.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sys1bench"
3
- version = "0.3.0"
3
+ version = "0.3.1"
4
4
  description = "Benchmark harness for typed System One decision models (choice / score / noul): calibration vs noise floor, framing sensitivity, selective prediction, ordinal fidelity, interference, robustness."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -59,7 +59,7 @@ build-backend = "setuptools.build_meta"
59
59
  where = ["src"]
60
60
 
61
61
  [tool.setuptools.package-data]
62
- "sys1bench.data" = ["framings/*.yaml", "canary/*.jsonl"]
62
+ "sys1bench.data" = ["framings/*.yaml", "canary/*.jsonl", "configs/*.yaml"]
63
63
 
64
64
  [tool.pytest.ini_options]
65
65
  testpaths = ["tests"]
@@ -1,3 +1,3 @@
1
1
  """sys1bench: benchmark harness for typed System One decision models."""
2
2
 
3
- __version__ = "0.3.0"
3
+ __version__ = "0.3.1"
@@ -27,7 +27,7 @@ from typing import Any
27
27
  import httpx
28
28
 
29
29
  from ..schemas import Answer, DecisionRequest, DecisionResponse, LatencyRecord, ModelCapabilities, ProviderRecord, Question
30
- from .base import BaseAdapter, finalize_answer, register
30
+ from .base import BaseAdapter, FatalAdapterError, finalize_answer, register
31
31
 
32
32
  DEFAULT_URL = "https://api.typesafe.ai/v1/systemone"
33
33
  PRICE_PER_M_INPUT = 0.042
@@ -38,7 +38,7 @@ def _load_dotenv_key() -> str | None:
38
38
  for k in ENV_KEYS:
39
39
  if os.environ.get(k):
40
40
  return os.environ[k]
41
- for candidate in (Path.cwd() / ".env", Path(__file__).resolve().parents[3] / ".env"):
41
+ for candidate in (Path.cwd() / ".env",):
42
42
  if candidate.exists():
43
43
  for line in candidate.read_text().splitlines():
44
44
  line = line.strip()
@@ -95,6 +95,9 @@ class JevTypeSafeAdapter(BaseAdapter):
95
95
  raise ValueError("pin a versioned Jev id (e.g. jev-1.13.0); aliases move silently. Pass allow_alias=True to override.")
96
96
  self.url, self.timeout_s, self.max_retries = url, timeout_s, max_retries
97
97
  self.api_key = api_key or _load_dotenv_key()
98
+ if not self.api_key:
99
+ raise FatalAdapterError("No TypeSafe API key found. Set TypeSafe_API_KEY (or TYPESAFE_API_KEY) in the environment or in a .env file "
100
+ "in the working directory. Keys: https://typesafe.ai")
98
101
  self._client = httpx.Client(timeout=timeout_s, http2=False)
99
102
 
100
103
  @property
@@ -121,6 +124,8 @@ class JevTypeSafeAdapter(BaseAdapter):
121
124
  except ValueError:
122
125
  pass
123
126
  raise httpx.HTTPStatusError(f"{r.status_code}: {r.text[:200]}", request=r.request, response=r)
127
+ if r.status_code in (401, 403):
128
+ raise FatalAdapterError(f"TypeSafe API rejected the key (HTTP {r.status_code}). Check TypeSafe_API_KEY.")
124
129
  if 400 <= r.status_code < 500 and r.status_code != 429:
125
130
  # request rejected (400 over the 32k state limit, 413, 422 malformed): never retry, classify as vendor rejection
126
131
  raise ValueError(f"{r.status_code} rejected: {r.text[:300]}")
@@ -140,6 +145,8 @@ class JevTypeSafeAdapter(BaseAdapter):
140
145
  "questions": {k: to_vendor_question(q) for k, q in request.questions.items()}}
141
146
  try:
142
147
  data, ms, headers = self._post(body)
148
+ except FatalAdapterError:
149
+ raise
143
150
  except Exception as e:
144
151
  kind = "rejected_by_vendor" if isinstance(e, ValueError) else "transport"
145
152
  return DecisionResponse(
@@ -17,7 +17,7 @@ import yaml
17
17
 
18
18
  from . import __version__
19
19
  from .adapters import get_adapter, list_adapters
20
- from .data import framings_path
20
+ from .data import canary_path, config_path, framings_path, list_configs
21
21
  from .framing import apply_corruption, expand_framings, permute_options, strip_options, strip_state
22
22
  from .framing.expand import load_framings
23
23
  from .generators import GENERATORS, get_generator
@@ -38,14 +38,31 @@ def _main(ctx: typer.Context, version: bool = typer.Option(False, "--version", "
38
38
  typer.echo(ctx.get_help())
39
39
 
40
40
 
41
+ def _fail(msg: str, code: int = 2) -> None:
42
+ typer.secho(f"error: {msg}", fg=typer.colors.RED, err=True)
43
+ raise typer.Exit(code)
44
+
45
+
41
46
  def _adapter_from(adapter: str | None, model: str | None, config: str | None):
47
+ from .adapters.base import FatalAdapterError
48
+
42
49
  cfg = {}
43
50
  if config:
44
- cfg = yaml.safe_load(Path(config).read_text()) or {}
45
- adapter = adapter or cfg.pop("adapter")
51
+ try:
52
+ cfg = yaml.safe_load(config_path(config).read_text()) or {}
53
+ except FileNotFoundError as e:
54
+ _fail(str(e))
55
+ adapter = adapter or cfg.pop("adapter", None)
56
+ if not adapter:
57
+ _fail("no adapter given: pass --adapter <id> or --config <yaml with an `adapter:` key>. Known: " + ", ".join(list_adapters()))
46
58
  if model:
47
59
  cfg["model_id"] = model
48
- return get_adapter(adapter, **cfg)
60
+ try:
61
+ return get_adapter(adapter, **cfg)
62
+ except KeyError as e:
63
+ _fail(str(e).strip('"'))
64
+ except (ValueError, FatalAdapterError) as e:
65
+ _fail(str(e))
49
66
 
50
67
 
51
68
  @app.command()
@@ -55,8 +72,19 @@ def adapters():
55
72
  typer.echo(a)
56
73
 
57
74
 
75
+ @app.command()
76
+ def configs(show: Optional[str] = typer.Argument(None, help="print a packaged config by name")):
77
+ """List packaged example model configs (use with --config <name>), or print one to copy and edit."""
78
+ if show:
79
+ typer.echo(config_path(show).read_text())
80
+ return
81
+ for c in sorted(list_configs()):
82
+ typer.echo(c)
83
+
84
+
58
85
  @app.command()
59
86
  def generators():
87
+ """List Tier G generators and their versions."""
60
88
  for g in sorted(GENERATORS):
61
89
  typer.echo(f"{g}@{GENERATORS[g].version}")
62
90
 
@@ -93,14 +121,22 @@ def run(manifest: Path, out: Path, adapter: str | None = None, model: str | None
93
121
  if permutations:
94
122
  items = permute_options(items, permutations)
95
123
  c = ResponseCache(cache)
96
- rows_all += run_items(items, ad, c, suite=suite, arm="main", concurrency=concurrency, progress=True)
97
- base = [i for i in items if i.permutation_id == "p0" and all(q.framing_id == "f0" for q in i.questions.values())]
98
- if corruption:
99
- rows_all += run_items(apply_corruption(base), ad, c, suite=suite, arm="corruption", concurrency=concurrency)
100
- if short_circuit:
101
- rows_all += run_items(strip_state(base), ad, c, suite=suite, arm="state_only", concurrency=concurrency)
102
- rows_all += run_items(strip_options(base), ad, c, suite=suite, arm="options_only", concurrency=concurrency)
124
+ from .adapters.base import FatalAdapterError
125
+
126
+ try:
127
+ rows_all += run_items(items, ad, c, suite=suite, arm="main", concurrency=concurrency, progress=True)
128
+ base = [i for i in items if i.permutation_id == "p0" and all(q.framing_id == "f0" for q in i.questions.values())]
129
+ if corruption:
130
+ rows_all += run_items(apply_corruption(base), ad, c, suite=suite, arm="corruption", concurrency=concurrency)
131
+ if short_circuit:
132
+ rows_all += run_items(strip_state(base), ad, c, suite=suite, arm="state_only", concurrency=concurrency)
133
+ rows_all += run_items(strip_options(base), ad, c, suite=suite, arm="options_only", concurrency=concurrency)
134
+ except FatalAdapterError as e:
135
+ _fail(str(e), code=3)
103
136
  write_predictions(rows_all, out)
137
+ n_err = sum(1 for r in rows_all if r.error)
138
+ if n_err:
139
+ typer.secho(f"warning: {n_err}/{len(rows_all)} rows have errors (see the `error` field); first: {next(r.error for r in rows_all if r.error)}", fg=typer.colors.YELLOW, err=True)
104
140
  typer.echo(f"wrote {len(rows_all)} prediction rows to {out}; cache size {len(c)}")
105
141
 
106
142
 
@@ -124,11 +160,11 @@ def score(predictions: list[Path], out: Path = Path("results/summary.json"), tab
124
160
 
125
161
 
126
162
  @app.command()
127
- def canary(adapter: str, model: str | None = None, manifest: Path = Path("data/canary/canary.jsonl"),
163
+ def canary(adapter: str, model: str | None = None, manifest: Path | None = None,
128
164
  store: Path = Path("results/canary"), config: Path | None = None):
129
- """Run the drift canary for a hosted model."""
165
+ """Run the drift canary for a hosted model (default: the packaged 200-item set)."""
130
166
  ad = _adapter_from(adapter, model, str(config) if config else None)
131
- res = run_canary(load_manifest(manifest), ad, store)
167
+ res = run_canary(load_manifest(manifest or canary_path()), ad, store)
132
168
  typer.echo(json.dumps(res, indent=1))
133
169
  if res["drift_suspected"]:
134
170
  raise typer.Exit(code=2)
@@ -22,10 +22,10 @@ def framings_path(name_or_path: str | Path) -> Path:
22
22
  p = Path(name_or_path)
23
23
  if p.exists():
24
24
  return p
25
- stem = p.stem if p.suffix else str(name_or_path)
26
- cand = _pkg_file("framings", f"{stem}.yaml")
27
- if cand.exists():
28
- return cand
25
+ for stem in (str(name_or_path), p.stem): # names may contain dots (jev_1.13), so try the full name first
26
+ cand = _pkg_file("framings", f"{stem}.yaml")
27
+ if cand.exists():
28
+ return cand
29
29
  raise FileNotFoundError(f"no framing set {name_or_path!r}; packaged: {sorted(list_framings())}")
30
30
 
31
31
 
@@ -35,3 +35,20 @@ def list_framings() -> list[str]:
35
35
 
36
36
  def canary_path() -> Path:
37
37
  return _pkg_file("canary", "canary.jsonl")
38
+
39
+
40
+ def config_path(name_or_path: str | Path) -> Path:
41
+ """Resolve a model config: an existing path, or a packaged example in `configs/<name>.yaml`
42
+ (jev_1.13, jev_1.13_openrouter, laya_en, laya_typed_decisions, example_future_vendor, hybrid_mock)."""
43
+ p = Path(name_or_path)
44
+ if p.exists():
45
+ return p
46
+ for stem in (str(name_or_path), p.stem):
47
+ cand = _pkg_file("configs", f"{stem}.yaml")
48
+ if cand.exists():
49
+ return cand
50
+ raise FileNotFoundError(f"no config {name_or_path!r}; packaged: {sorted(list_configs())}")
51
+
52
+
53
+ def list_configs() -> list[str]:
54
+ return [p.stem for p in Path(str(resources.files(_PKG).joinpath("configs"))).glob("*.yaml")]
@@ -0,0 +1,18 @@
1
+ # Template for a new hosted System One model: no code needed if its JSON shape is conventional.
2
+ adapter: generic_http
3
+ model_id: vendor/decider-1.0
4
+ url: https://api.vendor.example/v1/decisions
5
+ auth_env: VENDOR_API_KEY
6
+ type_map: {choice: choice, score: score, noul: boolean}
7
+ body_template: {"model": "{model_id}", "state": "{state}", "questions": "{questions}"}
8
+ answers_path: [answers]
9
+ fields:
10
+ probs: [[probabilities], [distribution]]
11
+ p_true: [[probability]]
12
+ confidence: [[confidence]]
13
+ model_returned: [[model]]
14
+ generation_id: [[id]]
15
+ input_tokens: [[usage, input_tokens]]
16
+ price_per_m_input: 0.05
17
+ max_options: 255
18
+ max_state_tokens: 32000
@@ -0,0 +1,4 @@
1
+ adapter: hybrid_router
2
+ threshold: 0.7
3
+ primary: {adapter: mock, skill: 0.8, temperature: 0.8, latency_ms: 40}
4
+ fallback: {adapter: mock, skill: 0.95, latency_ms: 1500}
@@ -0,0 +1,4 @@
1
+ adapter: jev_typesafe
2
+ model_id: jev-1.13.0 # versioned id; never jev-latest / jev-preview
3
+ timeout_s: 30
4
+ max_retries: 6
@@ -0,0 +1,3 @@
1
+ adapter: jev_openrouter
2
+ model_id: typesafe/jev-1.13 # OpenRouter alpha Decisions API route (needs OPENROUTER_API_KEY)
3
+ route: openrouter
@@ -0,0 +1,6 @@
1
+ adapter: laya_local
2
+ model_id: convaiinnovations/laya
3
+ checkpoint: english # english | multilingual | typed-decisions | router
4
+ device: cuda # falls back to CPU if CUDA is unavailable; the device used is recorded per row
5
+ head_max_len: 192 # Suite C sweeps [64,128,192,256,384,512]
6
+ max_len: 512
@@ -0,0 +1,6 @@
1
+ adapter: laya_local
2
+ model_id: convaiinnovations/laya
3
+ checkpoint: typed-decisions
4
+ device: cuda
5
+ head_max_len: 256
6
+ max_len: 1024
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sys1bench
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Benchmark harness for typed System One decision models (choice / score / noul): calibration vs noise floor, framing sensitivity, selective prediction, ordinal fidelity, interference, robustness.
5
5
  Author-email: Rahul Sharma <rsharma@rptu.de>
6
6
  License-Expression: Apache-2.0
@@ -55,8 +55,8 @@ Dynamic: license-file
55
55
  </p>
56
56
 
57
57
  <p align="center">
58
- <a href="https://pypi.org/project/sys1bench/"><img alt="PyPI" src="https://img.shields.io/pypi/v/sys1bench?color=4F46E5&label=PyPI"></a>
59
- <a href="https://pypi.org/project/sys1bench/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/sys1bench?color=06B6D4"></a>
58
+ <a href="https://pypi.org/project/sys1bench/"><img alt="PyPI" src="https://img.shields.io/pypi/v/sys1bench?color=4F46E5&label=PyPI&logo=pypi&logoColor=white&cacheSeconds=3600"></a>
59
+ <a href="https://pypi.org/project/sys1bench/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/sys1bench?color=06B6D4&logo=python&logoColor=white&cacheSeconds=3600"></a>
60
60
  <a href="https://github.com/rssr25/system-one-bench/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/rssr25/system-one-bench/actions/workflows/ci.yml/badge.svg"></a>
61
61
  <a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue.svg"></a>
62
62
  <img alt="Tests" src="https://img.shields.io/badge/tests-31%20passing-brightgreen">
@@ -114,10 +114,10 @@ sys1bench score preds.jsonl prior.jsonl --out summary.json
114
114
  # Jev (hosted, first-party API)
115
115
  echo 'TypeSafe_API_KEY=...' > .env
116
116
  sys1bench canary jev_typesafe --model jev-1.13.0 # 200 fixed items; drift baseline
117
- sys1bench suite all results/jev --config configs/models/jev_1.13.yaml --n 500 --concurrency 4
117
+ sys1bench suite all results/jev --config jev_1.13 --n 500 --concurrency 4 # packaged config; `sys1bench configs` lists them
118
118
 
119
119
  # Laya (local; same manifests as Jev so the comparison is item-for-item)
120
- sys1bench suite all results/laya --config configs/models/laya_en.yaml --manifests-from results/jev --budget
120
+ sys1bench suite all results/laya --config laya_en --manifests-from results/jev --budget
121
121
 
122
122
  # Report, LaTeX tables, HTML dashboard and plots for everything under results/
123
123
  sys1bench report results --latex results/tables.tex --html results/dashboard.html
@@ -132,7 +132,7 @@ sys1bench plots results
132
132
 
133
133
  | Your model | What to do |
134
134
  |---|---|
135
- | Hosted, conventional JSON decisions API | Copy [`configs/models/example_future_vendor.yaml`](configs/models/example_future_vendor.yaml), fill in URL, auth env var and field names. No code. |
135
+ | Hosted, conventional JSON decisions API | `sys1bench configs example_future_vendor > my_model.yaml`, fill in URL, auth env var and field names, run with `--config my_model.yaml`. No code. |
136
136
  | Anything else | Subclass `BaseAdapter`: declare `capabilities` (primitives, max options, state tokens, native abstain, batching) and implement `decide` (state + typed questions in, one probability vector per question out). Register with `@register("my_model")` or the `sys1bench.adapters` entry-point group from your own package. |
137
137
 
138
138
  Capability limits are declared, then measured: a request outside them is recorded as a `capability_issue` or `rejected_by_vendor` row, never a crash.
@@ -32,6 +32,12 @@ src/sys1bench/analysis/meta_eval.py
32
32
  src/sys1bench/analysis/stats.py
33
33
  src/sys1bench/data/__init__.py
34
34
  src/sys1bench/data/canary/canary.jsonl
35
+ src/sys1bench/data/configs/example_future_vendor.yaml
36
+ src/sys1bench/data/configs/hybrid_mock.yaml
37
+ src/sys1bench/data/configs/jev_1.13.yaml
38
+ src/sys1bench/data/configs/jev_1.13_openrouter.yaml
39
+ src/sys1bench/data/configs/laya_en.yaml
40
+ src/sys1bench/data/configs/laya_typed_decisions.yaml
35
41
  src/sys1bench/data/framings/guardrail_intent.yaml
36
42
  src/sys1bench/data/framings/log_triage.yaml
37
43
  src/sys1bench/data/framings/phishing_email.yaml
File without changes
File without changes