whileai 0.60__tar.gz → 0.62__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 (93) hide show
  1. {whileai-0.60/whileai.egg-info → whileai-0.62}/PKG-INFO +7 -3
  2. {whileai-0.60 → whileai-0.62}/README.md +6 -2
  3. {whileai-0.60 → whileai-0.62}/pyproject.toml +5 -1
  4. {whileai-0.60 → whileai-0.62}/whileai/auth.py +61 -0
  5. {whileai-0.60 → whileai-0.62}/whileai/cli.py +19 -1
  6. whileai-0.62/whileai/init_evals.py +553 -0
  7. {whileai-0.60 → whileai-0.62}/whileai/simulations/data.py +10 -1
  8. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/actionspace.py +14 -5
  9. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/adapters.py +25 -1
  10. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/generator.py +6 -3
  11. {whileai-0.60 → whileai-0.62}/whileai/simulations/run/config.py +5 -0
  12. {whileai-0.60 → whileai-0.62}/whileai/simulations/run/engine.py +209 -13
  13. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/hygiene.py +18 -1
  14. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/judging.py +10 -1
  15. {whileai-0.60 → whileai-0.62}/whileai/simulations/simulation.py +13 -1
  16. whileai-0.62/whileai/templates/__init__.py +1 -0
  17. whileai-0.62/whileai/templates/evals.py +455 -0
  18. {whileai-0.60 → whileai-0.62/whileai.egg-info}/PKG-INFO +7 -3
  19. {whileai-0.60 → whileai-0.62}/whileai.egg-info/SOURCES.txt +4 -1
  20. {whileai-0.60 → whileai-0.62}/whileai.egg-info/entry_points.txt +2 -0
  21. {whileai-0.60 → whileai-0.62}/LICENSE +0 -0
  22. {whileai-0.60 → whileai-0.62}/MANIFEST.in +0 -0
  23. {whileai-0.60 → whileai-0.62}/setup.cfg +0 -0
  24. {whileai-0.60 → whileai-0.62}/whileai/__init__.py +0 -0
  25. {whileai-0.60 → whileai-0.62}/whileai/_env.py +0 -0
  26. {whileai-0.60 → whileai-0.62}/whileai/ingest.py +0 -0
  27. {whileai-0.60 → whileai-0.62}/whileai/py.typed +0 -0
  28. {whileai-0.60 → whileai-0.62}/whileai/simulations/__init__.py +0 -0
  29. {whileai-0.60 → whileai-0.62}/whileai/simulations/__main__.py +0 -0
  30. {whileai-0.60 → whileai-0.62}/whileai/simulations/environment.py +0 -0
  31. {whileai-0.60 → whileai-0.62}/whileai/simulations/export.py +0 -0
  32. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/__init__.py +0 -0
  33. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/agents.py +0 -0
  34. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/anthropic_backend.py +0 -0
  35. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/coverage.py +0 -0
  36. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/diversity.py +0 -0
  37. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/embeddings.py +0 -0
  38. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/explore.py +0 -0
  39. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/offline_agent.py +0 -0
  40. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/scenarios.py +0 -0
  41. {whileai-0.60 → whileai-0.62}/whileai/simulations/generate/usage_meter.py +0 -0
  42. {whileai-0.60 → whileai-0.62}/whileai/simulations/ingest/__init__.py +0 -0
  43. {whileai-0.60 → whileai-0.62}/whileai/simulations/ingest/otel.py +0 -0
  44. {whileai-0.60 → whileai-0.62}/whileai/simulations/ingest/platform.py +0 -0
  45. {whileai-0.60 → whileai-0.62}/whileai/simulations/ingest/traces.py +0 -0
  46. {whileai-0.60 → whileai-0.62}/whileai/simulations/monitor.py +0 -0
  47. {whileai-0.60 → whileai-0.62}/whileai/simulations/py.typed +0 -0
  48. {whileai-0.60 → whileai-0.62}/whileai/simulations/run/__init__.py +0 -0
  49. {whileai-0.60 → whileai-0.62}/whileai/simulations/run/rows.py +0 -0
  50. {whileai-0.60 → whileai-0.62}/whileai/simulations/run/spec.py +0 -0
  51. {whileai-0.60 → whileai-0.62}/whileai/simulations/schema.py +0 -0
  52. {whileai-0.60 → whileai-0.62}/whileai/simulations/schemas/row-v1.json +0 -0
  53. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/__init__.py +0 -0
  54. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/agreement.py +0 -0
  55. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/audit.py +0 -0
  56. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/checklist.py +0 -0
  57. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/curriculum.py +0 -0
  58. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/delta.py +0 -0
  59. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/grade_llm.py +0 -0
  60. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/grading.py +0 -0
  61. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/grounding.py +0 -0
  62. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/hack_scan.py +0 -0
  63. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/judge_trust.py +0 -0
  64. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/labels.py +0 -0
  65. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/llm_judge.py +0 -0
  66. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/logprobs.py +0 -0
  67. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/markers.py +0 -0
  68. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/optimize.py +0 -0
  69. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/pairwise.py +0 -0
  70. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/passat.py +0 -0
  71. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/preflight.py +0 -0
  72. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/privileged.py +0 -0
  73. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/publish_gate.py +0 -0
  74. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/quality.py +0 -0
  75. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/reference.py +0 -0
  76. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/rubric.py +0 -0
  77. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/spec.py +0 -0
  78. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/stage.py +0 -0
  79. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/stats.py +0 -0
  80. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/style.py +0 -0
  81. {whileai-0.60 → whileai-0.62}/whileai/simulations/score/trace.py +0 -0
  82. {whileai-0.60 → whileai-0.62}/whileai/simulations/training.py +0 -0
  83. {whileai-0.60 → whileai-0.62}/whileai/simulations/verify/__init__.py +0 -0
  84. {whileai-0.60 → whileai-0.62}/whileai/simulations/verify/base.py +0 -0
  85. {whileai-0.60 → whileai-0.62}/whileai/simulations/verify/code.py +0 -0
  86. {whileai-0.60 → whileai-0.62}/whileai/simulations/verify/math.py +0 -0
  87. {whileai-0.60 → whileai-0.62}/whileai/simulations/verify/structured.py +0 -0
  88. {whileai-0.60 → whileai-0.62}/whileai/simulations/verify/text.py +0 -0
  89. {whileai-0.60 → whileai-0.62}/whileai/simulations/world/__init__.py +0 -0
  90. {whileai-0.60 → whileai-0.62}/whileai/simulations/world/sandbox.py +0 -0
  91. {whileai-0.60 → whileai-0.62}/whileai.egg-info/dependency_links.txt +0 -0
  92. {whileai-0.60 → whileai-0.62}/whileai.egg-info/requires.txt +0 -0
  93. {whileai-0.60 → whileai-0.62}/whileai.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: whileai
3
- Version: 0.60
3
+ Version: 0.62
4
4
  Summary: While Python SDK: trace ingestion and verification client, plus agent simulations grounded in your tools and system prompt.
5
5
  Author: While
6
6
  License: Apache-2.0
@@ -41,7 +41,9 @@ The While Python SDK. One package, two importable modules:
41
41
  - `whileai`: the platform client. OTLP trace ingest and trace-dataset listing against the token gate.
42
42
  - `whileai.simulations`: post-training data for an agent. Give it the agent's traces, or its tools and system prompt; it simulates the situations, the people, and the world, plays the agent through multi-turn tool-calling conversations, and returns rows for your grader.
43
43
 
44
- **Renamed.** This SDK was `zeroproof` (ZeroProof is now While). `pip install zeroproof` still works: it installs `whileai`, and `import zeroproof` (or the older `zeroproof_simulations`) resolves to the same modules with a deprecation warning. `ZEROPROOF_*` environment variables and a saved `~/.zeroproof/credentials.json` are still read. Change the import when you can; new releases land under `whileai`. zp, ZeroProof and While all name this one product: the package is `whileai`, the import is `whileai.simulations`, keys start with `zp_`. A machine with the old package still picks up `~/.zeroproof/credentials.json`; set `WHILEAI_HOME` to a fresh directory to isolate a new account from it.
44
+ Have an agent and want a pass rate with an interval? Start at [docs/evals.md](docs/evals.md) (offline, seconds, `coverage_gap` names what your tests miss).
45
+
46
+ **Renamed.** This SDK was `zeroproof` (ZeroProof is now While). `pip install zeroproof` still works: it installs `whileai`, and `import zeroproof` (or the older `zeroproof_simulations`) resolves to the same modules with a deprecation warning. `ZEROPROOF_*` environment variables and a saved `~/.zeroproof/credentials.json` are still read. Change the import when you can; new releases land under `whileai`. zp, ZeroProof and While all name this one product: the package is `whileai`, the import is `whileai.simulations`, keys start with `zp_`. `zp`, `wai` and `whileai` run the same CLI, so `zp login` and `whileai login` do the same thing (the help text says `whileai`). A machine with the old package still picks up `~/.zeroproof/credentials.json`; set `WHILEAI_HOME` to a fresh directory to isolate a new account from it.
45
47
 
46
48
  Releases of `whileai` before 0.3 were an unrelated encrypted agent-to-agent messaging client. That code was removed in 0.04; pin `whileai<0.3` if you still depend on it.
47
49
 
@@ -195,7 +197,9 @@ that reads the trajectory, run the asks `k` times each, and read pass@1
195
197
  with its interval. Offline first, then the hosted writer. The how-to is
196
198
  [docs/evals.md](docs/evals.md); the runnable version is
197
199
  [`recipes/02-measure/eval-your-agent`](recipes/02-measure/eval-your-agent),
198
- which ends at a CI gate, not a push.
200
+ which ends at a CI gate, not a push. `whileai init-evals` writes those
201
+ four files for you, wired to the tools, system prompt and callable it
202
+ finds in the project, and prints what it picked.
199
203
 
200
204
  ```python
201
205
  data = wai.simulate(
@@ -5,7 +5,9 @@ The While Python SDK. One package, two importable modules:
5
5
  - `whileai`: the platform client. OTLP trace ingest and trace-dataset listing against the token gate.
6
6
  - `whileai.simulations`: post-training data for an agent. Give it the agent's traces, or its tools and system prompt; it simulates the situations, the people, and the world, plays the agent through multi-turn tool-calling conversations, and returns rows for your grader.
7
7
 
8
- **Renamed.** This SDK was `zeroproof` (ZeroProof is now While). `pip install zeroproof` still works: it installs `whileai`, and `import zeroproof` (or the older `zeroproof_simulations`) resolves to the same modules with a deprecation warning. `ZEROPROOF_*` environment variables and a saved `~/.zeroproof/credentials.json` are still read. Change the import when you can; new releases land under `whileai`. zp, ZeroProof and While all name this one product: the package is `whileai`, the import is `whileai.simulations`, keys start with `zp_`. A machine with the old package still picks up `~/.zeroproof/credentials.json`; set `WHILEAI_HOME` to a fresh directory to isolate a new account from it.
8
+ Have an agent and want a pass rate with an interval? Start at [docs/evals.md](docs/evals.md) (offline, seconds, `coverage_gap` names what your tests miss).
9
+
10
+ **Renamed.** This SDK was `zeroproof` (ZeroProof is now While). `pip install zeroproof` still works: it installs `whileai`, and `import zeroproof` (or the older `zeroproof_simulations`) resolves to the same modules with a deprecation warning. `ZEROPROOF_*` environment variables and a saved `~/.zeroproof/credentials.json` are still read. Change the import when you can; new releases land under `whileai`. zp, ZeroProof and While all name this one product: the package is `whileai`, the import is `whileai.simulations`, keys start with `zp_`. `zp`, `wai` and `whileai` run the same CLI, so `zp login` and `whileai login` do the same thing (the help text says `whileai`). A machine with the old package still picks up `~/.zeroproof/credentials.json`; set `WHILEAI_HOME` to a fresh directory to isolate a new account from it.
9
11
 
10
12
  Releases of `whileai` before 0.3 were an unrelated encrypted agent-to-agent messaging client. That code was removed in 0.04; pin `whileai<0.3` if you still depend on it.
11
13
 
@@ -159,7 +161,9 @@ that reads the trajectory, run the asks `k` times each, and read pass@1
159
161
  with its interval. Offline first, then the hosted writer. The how-to is
160
162
  [docs/evals.md](docs/evals.md); the runnable version is
161
163
  [`recipes/02-measure/eval-your-agent`](recipes/02-measure/eval-your-agent),
162
- which ends at a CI gate, not a push.
164
+ which ends at a CI gate, not a push. `whileai init-evals` writes those
165
+ four files for you, wired to the tools, system prompt and callable it
166
+ finds in the project, and prints what it picked.
163
167
 
164
168
  ```python
165
169
  data = wai.simulate(
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "whileai"
7
- version = "0.60"
7
+ version = "0.62"
8
8
  description = "While Python SDK: trace ingestion and verification client, plus agent simulations grounded in your tools and system prompt."
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
@@ -38,6 +38,10 @@ Datasets = "https://huggingface.co/datasets/zero-proof-ai/agent-simulations"
38
38
 
39
39
  [project.scripts]
40
40
  whileai = "whileai.cli:main"
41
+ # same CLI under the two names people type: the product is "zp"
42
+ # (keys start with zp_) and "wai" is the short import alias.
43
+ zp = "whileai.cli:main"
44
+ wai = "whileai.cli:main"
41
45
  whileai-simulations = "whileai.simulations.score.quality:main"
42
46
 
43
47
  [project.optional-dependencies]
@@ -66,6 +66,27 @@ def trial_note(daily_input_tokens: float | None = None) -> str:
66
66
  )
67
67
 
68
68
 
69
+ def trial_prerun_note() -> str | None:
70
+ """The one line a trial key needs before a hosted run spends it, or ``None``.
71
+
72
+ Read from the tier the credentials file recorded at sign-up or at the
73
+ last ``whileai status`` / ``whileai login``, so a run can say this
74
+ without a network call. A key from the environment has no recorded
75
+ tier, so this says nothing rather than guess at one.
76
+ """
77
+ if getenv("API_KEY"):
78
+ return None
79
+ saved = _read(credentials_path()) or {}
80
+ if not saved.get("api_key") or str(saved.get("tier") or "") != "trial":
81
+ return None
82
+ tokens = int(float(saved.get("daily_input_tokens") or DEFAULT_TRIAL_INPUT_TOKENS))
83
+ return (
84
+ f"trial key: the hosted writer covers about {trial_situations(tokens)} situations a day "
85
+ f"({tokens // 1000}k input tokens); simulator=False writes them offline with no quota; "
86
+ f"sign in once at {SIGN_IN_URL} to lift it"
87
+ )
88
+
89
+
69
90
  def _api_url() -> str:
70
91
  return getenv("API_URL", DEFAULT_API_URL).rstrip("/")
71
92
 
@@ -112,6 +133,37 @@ def _read(path: Path) -> dict | None:
112
133
  return data if isinstance(data, dict) else None
113
134
 
114
135
 
136
+ def _tier_fields(payload: dict) -> dict:
137
+ """The tier facts worth keeping next to the key, from ``/signup`` or ``/me``."""
138
+ tier = str((payload or {}).get("tier") or "").strip()
139
+ if not tier:
140
+ return {}
141
+ fields: dict = {"tier": tier}
142
+ trial = (payload or {}).get("trial") or {}
143
+ if isinstance(trial, dict):
144
+ if trial.get("daily_input_tokens") is not None:
145
+ fields["daily_input_tokens"] = trial["daily_input_tokens"]
146
+ if trial.get("expires_at"):
147
+ fields["expires_at"] = str(trial["expires_at"])
148
+ return fields
149
+
150
+
151
+ def remember_account(payload: dict) -> None:
152
+ """Record a ``/signup`` or ``/me`` reply's tier in the credentials file.
153
+
154
+ Only for the key that file holds: a key from the environment may belong
155
+ to another account, and writing its tier here would mislabel this one.
156
+ """
157
+ fields = _tier_fields(payload)
158
+ saved = _read(credentials_path())
159
+ if not fields or not saved or not saved.get("api_key"):
160
+ return
161
+ if all(saved.get(key) == value for key, value in fields.items()):
162
+ return
163
+ saved.update(fields)
164
+ _write_private(credentials_path(), saved)
165
+
166
+
115
167
  def stored_api_key() -> str | None:
116
168
  """The key saved by ``whileai login``, or ``None``."""
117
169
  data = _read(credentials_path())
@@ -264,6 +316,10 @@ def login(
264
316
  )
265
317
  with contextlib.suppress(OSError):
266
318
  _pending_path().unlink()
319
+ # the tier the key carries, saved next to it, so a run can
320
+ # name a trial limit before it spends one
321
+ with contextlib.suppress(LoginError, OSError, ValueError):
322
+ remember_account(account(data["api_key"]))
267
323
  say(f"Logged in. Key saved to {credentials_path()}")
268
324
  return data["api_key"]
269
325
  error = data.get("error", "")
@@ -306,6 +362,9 @@ def signup(email: str, *, name: str | None = None, out: Callable[[str], None] |
306
362
  "user_id": data.get("user_id"),
307
363
  "email": data.get("email", email),
308
364
  "created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
365
+ # so simulate() can warn about the trial before a hosted
366
+ # run spends it, without a call to /me
367
+ **_tier_fields(data),
309
368
  },
310
369
  )
311
370
  say(f"Account created for {data.get('email', email)}. Key saved to {credentials_path()}")
@@ -382,6 +441,8 @@ def status() -> dict:
382
441
  out["tier"] = f"unknown ({err})"
383
442
  else:
384
443
  out["tier"] = me.get("tier")
444
+ if not env:
445
+ remember_account(me)
385
446
  if me.get("tier") == "trial":
386
447
  trial = me.get("trial") or {}
387
448
  out["trial_expires_at"] = trial.get("expires_at")
@@ -1,4 +1,4 @@
1
- """``whileai`` command line: login, signup, logout, status."""
1
+ """``whileai`` command line: login, signup, logout, status, init-evals."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -7,6 +7,7 @@ import json
7
7
  import sys
8
8
 
9
9
  from . import auth
10
+ from .init_evals import add_arguments as init_evals_args
10
11
 
11
12
 
12
13
  def main(argv: list[str] | None = None) -> int:
@@ -33,6 +34,12 @@ def main(argv: list[str] | None = None) -> int:
33
34
  sub.add_parser("logout", help="delete the saved key")
34
35
  sub.add_parser("status", help="show which key the SDK will use")
35
36
 
37
+ p_init = sub.add_parser(
38
+ "init-evals",
39
+ help="write an eval harness (agent, judge, run, test) wired to this project",
40
+ )
41
+ init_evals_args(p_init)
42
+
36
43
  p_purge = sub.add_parser(
37
44
  "purge", help="delete an agent's traces, datasets and record, or empty datasets"
38
45
  )
@@ -72,6 +79,17 @@ def main(argv: list[str] | None = None) -> int:
72
79
  return 1
73
80
  return 0
74
81
 
82
+ if args.command == "init-evals":
83
+ from .init_evals import init_evals
84
+
85
+ return init_evals(
86
+ agent=args.agent,
87
+ tools=args.tools,
88
+ system_prompt=args.system_prompt,
89
+ out=args.dir,
90
+ force=args.force,
91
+ )
92
+
75
93
  if args.command == "logout":
76
94
  print("Logged out." if auth.logout() else "No saved key.")
77
95
  return 0