@openpond/evals 0.5.0 → 0.7.0
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.
- package/CONTRACT.md +13 -1
- package/LEARNING.md +106 -0
- package/README.md +28 -2
- package/conformance/telemetry/v1/invalid-batch.json +17 -0
- package/conformance/telemetry/v1/valid-batch.json +58 -0
- package/dist/graders.js +26 -5
- package/dist/index.js +8 -0
- package/dist/javascript-verifier-contract.js +7 -0
- package/dist/javascript-verifier-node.js +56 -0
- package/dist/javascript-verifier-worker-source.js +1 -0
- package/dist/javascript-verifier-worker.js +6 -0
- package/dist/javascript-verifier.js +64 -0
- package/dist/learned-preference.js +334 -0
- package/dist/learning/admission.js +209 -0
- package/dist/learning/assets.js +37 -0
- package/dist/learning/contracts.js +267 -0
- package/dist/learning/errors.js +12 -0
- package/dist/learning/grade-worker.js +99 -0
- package/dist/learning/index.js +9 -0
- package/dist/learning/operations.js +33 -0
- package/dist/learning/repository.js +48 -0
- package/dist/learning/service.js +367 -0
- package/dist/learning/transport.js +25 -0
- package/dist/preferences.js +77 -11
- package/dist/rewards.js +230 -0
- package/dist/task-schema.js +142 -0
- package/dist/tasksets.js +3 -0
- package/dist/telemetry/index.js +4 -0
- package/dist/telemetry-analysis.js +183 -0
- package/dist/telemetry-bundle.js +60 -0
- package/dist/telemetry-catalog.js +50 -0
- package/dist/telemetry.js +112 -0
- package/dist/types/builtin-benchmarks/harness-refiner.d.ts +7 -0
- package/dist/types/builtin-benchmarks/harness-refiner.d.ts.map +1 -1
- package/dist/types/conformance.d.ts +14 -0
- package/dist/types/conformance.d.ts.map +1 -1
- package/dist/types/execution-contracts.d.ts +14 -0
- package/dist/types/execution-contracts.d.ts.map +1 -1
- package/dist/types/graders.d.ts.map +1 -1
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/javascript-verifier-contract.d.ts +9 -0
- package/dist/types/javascript-verifier-contract.d.ts.map +1 -0
- package/dist/types/javascript-verifier-node.d.ts +5 -0
- package/dist/types/javascript-verifier-node.d.ts.map +1 -0
- package/dist/types/javascript-verifier-worker-source.d.ts +2 -0
- package/dist/types/javascript-verifier-worker.d.ts +2 -0
- package/dist/types/javascript-verifier-worker.d.ts.map +1 -0
- package/dist/types/javascript-verifier.d.ts +15 -0
- package/dist/types/javascript-verifier.d.ts.map +1 -0
- package/dist/types/learned-preference.d.ts +282 -0
- package/dist/types/learned-preference.d.ts.map +1 -0
- package/dist/types/learning/admission.d.ts +335 -0
- package/dist/types/learning/admission.d.ts.map +1 -0
- package/dist/types/learning/assets.d.ts +49 -0
- package/dist/types/learning/assets.d.ts.map +1 -0
- package/dist/types/learning/contracts.d.ts +2149 -0
- package/dist/types/learning/contracts.d.ts.map +1 -0
- package/dist/types/learning/errors.d.ts +8 -0
- package/dist/types/learning/errors.d.ts.map +1 -0
- package/dist/types/learning/grade-worker.d.ts +31 -0
- package/dist/types/learning/grade-worker.d.ts.map +1 -0
- package/dist/types/learning/index.d.ts +10 -0
- package/dist/types/learning/index.d.ts.map +1 -0
- package/dist/types/learning/operations.d.ts +2061 -0
- package/dist/types/learning/operations.d.ts.map +1 -0
- package/dist/types/learning/repository.d.ts +1143 -0
- package/dist/types/learning/repository.d.ts.map +1 -0
- package/dist/types/learning/service.d.ts +22 -0
- package/dist/types/learning/service.d.ts.map +1 -0
- package/dist/types/learning/transport.d.ts +2139 -0
- package/dist/types/learning/transport.d.ts.map +1 -0
- package/dist/types/preferences.d.ts +55 -7
- package/dist/types/preferences.d.ts.map +1 -1
- package/dist/types/review-conformance.d.ts +5 -5
- package/dist/types/rewards.d.ts +611 -0
- package/dist/types/rewards.d.ts.map +1 -0
- package/dist/types/task-schema.d.ts +18 -0
- package/dist/types/task-schema.d.ts.map +1 -0
- package/dist/types/tasksets.d.ts +28 -0
- package/dist/types/tasksets.d.ts.map +1 -1
- package/dist/types/telemetry/index.d.ts +5 -0
- package/dist/types/telemetry/index.d.ts.map +1 -0
- package/dist/types/telemetry-analysis.d.ts +116 -0
- package/dist/types/telemetry-analysis.d.ts.map +1 -0
- package/dist/types/telemetry-bundle.d.ts +309 -0
- package/dist/types/telemetry-bundle.d.ts.map +1 -0
- package/dist/types/telemetry-catalog.d.ts +269 -0
- package/dist/types/telemetry-catalog.d.ts.map +1 -0
- package/dist/types/telemetry.d.ts +266 -0
- package/dist/types/telemetry.d.ts.map +1 -0
- package/package.json +40 -3
- package/schemas/learning/v1/asset.schema.json +89 -0
- package/schemas/learning/v1/batch.schema.json +132 -0
- package/schemas/learning/v1/binding.schema.json +207 -0
- package/schemas/learning/v1/command-request.schema.json +2414 -0
- package/schemas/learning/v1/decision.schema.json +440 -0
- package/schemas/learning/v1/definition.schema.json +397 -0
- package/schemas/learning/v1/evidence.schema.json +317 -0
- package/schemas/learning/v1/example-submission.schema.json +253 -0
- package/schemas/learning/v1/feedback-submission.schema.json +114 -0
- package/schemas/learning/v1/feedback.schema.json +233 -0
- package/schemas/learning/v1/grade.schema.json +412 -0
- package/schemas/learning/v1/iteration.schema.json +236 -0
- package/schemas/learning/v1/package.schema.json +776 -0
- package/schemas/learning/v1/policy.schema.json +373 -0
- package/schemas/learning/v1/read-request.schema.json +101 -0
- package/schemas/learning/v1/reward.schema.json +302 -0
- package/schemas/learning/v1/source.schema.json +198 -0
- package/schemas/telemetry/v1/evidence-completeness.schema.json +82 -0
- package/schemas/telemetry/v1/evidence-reference.schema.json +41 -0
- package/schemas/telemetry/v1/metric-definition.schema.json +96 -0
- package/schemas/telemetry/v1/metric-observation.schema.json +182 -0
- package/schemas/telemetry/v1/run-metric-summary.schema.json +98 -0
- package/schemas/telemetry/v1/run-telemetry-batch.schema.json +405 -0
- package/schemas/telemetry/v1/run-telemetry-event.schema.json +201 -0
- package/schemas/telemetry/v1/telemetry-cohort.schema.json +100 -0
- package/schemas/telemetry/v1/telemetry-export-bundle.schema.json +655 -0
package/CONTRACT.md
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
model-driven refinement/review policy, improvements, traces, tools, model
|
|
5
5
|
identities, and shared hashing.
|
|
6
6
|
`@openpond/evals` owns Tasksets, graders, evaluation runs and receipts,
|
|
7
|
-
execution orchestration, conformance fixtures,
|
|
7
|
+
execution orchestration, conformance fixtures, Work-evidence eligibility, and
|
|
8
|
+
portable Run telemetry/metric semantics.
|
|
8
9
|
Evals depends on Harness for exact release identities but does not re-export
|
|
9
10
|
Harness APIs; Harness never depends on Evals. Host applications own persistence, provider sessions, secret
|
|
10
11
|
leases, connected-app authorization, model streaming, artifact bytes, and
|
|
@@ -26,6 +27,8 @@ runtime processes.
|
|
|
26
27
|
| user feedback on Work output | `WorkFeedbackReceipt` | Append a new receipt bound to the evidence receipt and, when selected, the exact content-addressed output-revision descriptor. Corrections are separate artifacts and never mutate prior receipts. |
|
|
27
28
|
| bounded cross-Work review | `HarnessEvaluationReviewReceipt` | Select only currently authorized immutable evidence, advance one watermark, group one stable claim, route to the smallest correct layer, and name the next authority without performing downstream effects. |
|
|
28
29
|
| model-improvement qualification | `ModelImprovementQualificationReceipt` | Bind the originating review, exact Harness, Taskset, real baseline Evaluation, Model, Environment/tool/permission/policy hashes, Verifier, source policies, privacy, budget, and non-frozen signal. Weak or confounded evidence emits `no_training`; training and activation remain host effects. |
|
|
30
|
+
| trainer/runtime telemetry | `RunTelemetryEvent` + `MetricObservation` | Emit compact ordered events and observations with exact Run lineage, bounded attributes/dimensions, source authority, visibility, and stable idempotency identity. Tenant identity, provider credentials, storage, retention, billing, and durable indexes remain host projections. |
|
|
31
|
+
| local/hosted Run investigation export | `TelemetryExportBundle` | Export metric definitions, ordered evidence, bounded references, completeness, and a content hash. Apply visibility and redaction before crossing authority boundaries; never include raw privileged trace bytes. |
|
|
29
32
|
|
|
30
33
|
## Compatibility policy
|
|
31
34
|
|
|
@@ -48,6 +51,15 @@ runtime processes.
|
|
|
48
51
|
immutable objects and rejects lifecycle, tool, grader-interface, or required
|
|
49
52
|
Environment-tool drift before issuing the receipt.
|
|
50
53
|
- The initial support target is Node.js ESM on Node 22.14 through Node 24.
|
|
54
|
+
- Telemetry schema literals are shared across `@openpond/evals/telemetry` and
|
|
55
|
+
the `openpond-evals` Python distribution. Generated JSON Schemas and positive
|
|
56
|
+
and negative fixtures are the cross-language conformance authority.
|
|
57
|
+
- Telemetry producer sequence is monotonic within a Run. Receivers deduplicate
|
|
58
|
+
exact retries, accept late delivery, and reject conflicting reuse of an
|
|
59
|
+
idempotency key or `(runId, sequence)` pair.
|
|
60
|
+
- Core metrics reject unknown dimensions. Taskset- or Environment-specific
|
|
61
|
+
extensions require an explicit `MetricDefinition`; arbitrary metric names or
|
|
62
|
+
unbounded labels are not portable telemetry.
|
|
51
63
|
- Portable paths are relative and at most 2,000 characters. Individual assets
|
|
52
64
|
are at most 250 MB. Tasksets, traces, and evidence arrays have schema-level
|
|
53
65
|
upper bounds.
|
package/LEARNING.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Task evidence and reusable Rewards
|
|
2
|
+
|
|
3
|
+
`@openpond/evals/learning` owns the portable data and domain rules for task
|
|
4
|
+
definitions, sources, submissions, feedback, admission, immutable task batches,
|
|
5
|
+
learning policies and grading jobs. `@openpond/evals/rewards` owns immutable
|
|
6
|
+
Reward releases and exact versioned bindings. The package does not contain a
|
|
7
|
+
database, credentials, cloud client or execution infrastructure.
|
|
8
|
+
|
|
9
|
+
Use `openpond-sdk/learning` to submit the same commands to an authenticated local
|
|
10
|
+
or hosted execution owner. Plain HTTP producers use `POST /v1/learning/commands`
|
|
11
|
+
with `{ "scope": "<profile-or-team>", "command": { ... } }` and a Bearer token.
|
|
12
|
+
Reads use `POST /v1/learning/read`. Scope is a requested ownership boundary; the
|
|
13
|
+
host must authorize it from the credential and assign the actor itself.
|
|
14
|
+
|
|
15
|
+
## Data flow
|
|
16
|
+
|
|
17
|
+
1. Publish a Reward, then a binding, task definition and source. Use
|
|
18
|
+
`publish_resources` to publish dependent resources atomically. Pin an existing
|
|
19
|
+
release by `{ id, revision, contentHash }`; edits create the next revision with
|
|
20
|
+
an expected current revision.
|
|
21
|
+
2. Submit task examples under a stable source/example/attempt identity. Preserve
|
|
22
|
+
the producer idempotency key on retries. Reusing a key with different content
|
|
23
|
+
fails with a conflict. Invalid task-specific evidence remains reviewable;
|
|
24
|
+
accepting the submission does not approve it for training.
|
|
25
|
+
3. Queue durable grading of the observed output or a proposed supervised target.
|
|
26
|
+
Hosts execute the binding through `TaskGradeExecutor`; the built-in executor
|
|
27
|
+
supports portable deterministic checks and reports other implementations as
|
|
28
|
+
unavailable. Publication and schema validity are not execution receipts.
|
|
29
|
+
4. Record a reviewer decision referencing completed grader-run IDs. The service
|
|
30
|
+
checks the exact task, evidence, binding and output hashes. A failed observed
|
|
31
|
+
response may reveal a valid task. Supervised learning additionally requires a
|
|
32
|
+
separately approved, schema-valid target whose required checks passed.
|
|
33
|
+
5. Seal reviewed evidence into a batch. The service reserves both task-family and
|
|
34
|
+
exact-input identities across splits in the same transaction. Unresolved
|
|
35
|
+
families, stale evidence, stale decisions and held-out/training overlap fail.
|
|
36
|
+
`compileTaskBatch` creates the existing `openpond.tasksetRelease.v2` package.
|
|
37
|
+
|
|
38
|
+
Observed output, verifier expected output, private evaluator context and an
|
|
39
|
+
approved supervised target have separate fields. The public policy view excludes
|
|
40
|
+
expected output and private context. Compiled packages retain the approved target
|
|
41
|
+
in typed learning metadata for a training adapter; they do not replace verifier
|
|
42
|
+
ground truth with a demonstration.
|
|
43
|
+
|
|
44
|
+
Feedback addresses source/example/attempt identity and may arrive before the
|
|
45
|
+
example. Input, ground-truth and family corrections create new evidence revisions.
|
|
46
|
+
Existing batches retain their exact historical evidence. Proposed-target feedback
|
|
47
|
+
must be graded and reviewed before becoming a supervised target.
|
|
48
|
+
|
|
49
|
+
## JSON and schema profile
|
|
50
|
+
|
|
51
|
+
Generated HTTP/producer schemas are in `schemas/learning/v1`. They describe the
|
|
52
|
+
structural contract. Use the domain service for authorization, revision/hash
|
|
53
|
+
identity, admission and transactional constraints; JSON Schema alone cannot prove
|
|
54
|
+
those relationships. Input/output schemas use object envelopes and JSON Schema
|
|
55
|
+
2020-12 through Ajv, with a bounded portable profile:
|
|
56
|
+
|
|
57
|
+
- Local `#/$defs/...` references; no remote loading or recursive schemas.
|
|
58
|
+
- No regex, formats, custom keywords or runtime code inside schema validation.
|
|
59
|
+
- At most 32 KiB of schema, bounded expansion/alternatives and validation caches.
|
|
60
|
+
- Plain JSON values, finite numbers, no accessors/serializers/cycles, bounded depth,
|
|
61
|
+
node count and UTF-8 bytes. Host request limits apply in addition to field limits.
|
|
62
|
+
|
|
63
|
+
This profile follows [Ajv's security guidance](https://ajv.js.org/security.html)
|
|
64
|
+
for untrusted schemas and deliberately rejects unsupported capabilities.
|
|
65
|
+
|
|
66
|
+
## Host responsibilities
|
|
67
|
+
|
|
68
|
+
Authored verifier code and rubrics use immutable `asset` resources. Publish source
|
|
69
|
+
and its Reward with `publish_resources`; the service checks UTF-8 size, SHA-256,
|
|
70
|
+
full reference identity, scope and evaluator visibility in the same transaction.
|
|
71
|
+
Editing source creates a new asset identity. Existing Rewards retain their bytes.
|
|
72
|
+
|
|
73
|
+
`@openpond/evals/javascript-verifier/node` executes ESM verifier source in a
|
|
74
|
+
worker containing a fresh QuickJS WebAssembly interpreter. The verifier receives
|
|
75
|
+
JSON data and returns `{ score, passed, feedback, evidenceRefs? }`. It has no host
|
|
76
|
+
functions or import loader. Memory, stack, source/result sizes and execution time
|
|
77
|
+
are bounded; cancellation settles only after the worker has terminated. The
|
|
78
|
+
interpreter and worker are embedded in the package, so a clean install needs no
|
|
79
|
+
separate WASM download or native compiler. Browser/worker hosts can use the
|
|
80
|
+
portable `@openpond/evals/javascript-verifier` entry point directly.
|
|
81
|
+
|
|
82
|
+
This boundary follows the [QuickJS runtime isolation and resource APIs](https://github.com/justjake/quickjs-emscripten).
|
|
83
|
+
Node's [VM documentation](https://nodejs.org/api/vm.html) explicitly excludes
|
|
84
|
+
untrusted-code isolation; the local Taskset adapter now uses the same public
|
|
85
|
+
interpreter worker as task-evidence grading.
|
|
86
|
+
|
|
87
|
+
Implement `LearningRepository.transaction` with serialized writes and atomic
|
|
88
|
+
rollback. Persist immutable historical revisions, exact operation receipts and
|
|
89
|
+
unique split reservations. Never share a transaction object after it closes.
|
|
90
|
+
List results are cursor-paginated at no more than 100 resources.
|
|
91
|
+
|
|
92
|
+
Authorize every operation. Source credentials can submit only to their assigned
|
|
93
|
+
source; human admission/correction/sealing require a reviewer. Derive identities
|
|
94
|
+
from authentication, never from a producer-supplied actor field.
|
|
95
|
+
|
|
96
|
+
Grading workers use leases, stable job identity, bounded timeout/spend and terminal
|
|
97
|
+
receipts. Execution adapters must deduplicate submission and confirm cleanup.
|
|
98
|
+
Cancellation remains `cancelling` until the execution owner confirms termination;
|
|
99
|
+
a UI cancellation request is not proof that compute stopped. Restart recovery
|
|
100
|
+
must use the same durable jobs. Unexpected host failures remain server errors;
|
|
101
|
+
`LearningDomainError` exposes rejected requests as typed 4xx failures.
|
|
102
|
+
|
|
103
|
+
Policy and iteration contracts distinguish training parent, optional teacher and
|
|
104
|
+
upstream trigger. The contracts themselves do not launch training, schedule jobs,
|
|
105
|
+
qualify a model, accept a candidate or promote a serving endpoint. Hosts must
|
|
106
|
+
implement those transitions and record actual execution/evaluation receipts.
|
package/README.md
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# `@openpond/evals`
|
|
2
2
|
|
|
3
|
+
See [task evidence and learning](./LEARNING.md) for reusable Rewards, task-format publication, SDK/HTTP intake, grading, review and approved batches.
|
|
4
|
+
|
|
3
5
|
Portable evaluation and benchmark contracts plus pure helpers for Tasksets,
|
|
4
6
|
graders, run manifests, attempt and evaluation receipts, paired benchmark
|
|
5
7
|
comparisons, execution adapters, conformance fixtures, Work-evidence
|
|
6
|
-
eligibility,
|
|
8
|
+
eligibility, no-training/SFT/preference/RL qualification receipts, and portable
|
|
9
|
+
training telemetry. The package depends on
|
|
7
10
|
[`@openpond/harness`](../harness/README.md) for exact Harness identities but
|
|
8
11
|
does not re-export Harness APIs. Applications import the two packages directly,
|
|
9
12
|
which keeps refinement and evaluation authority visibly separate.
|
|
@@ -34,7 +37,7 @@ import {
|
|
|
34
37
|
```
|
|
35
38
|
|
|
36
39
|
Subpath exports are available at `/harness`, `/tasksets`, `/benchmarks`, `/graders`, `/runs`,
|
|
37
|
-
`/conformance`, `/evidence`, `/preferences`, `/review`, and
|
|
40
|
+
`/conformance`, `/evidence`, `/telemetry`, `/preferences`, `/review`, and
|
|
38
41
|
`/model-improvement-qualification`. The package is an evaluation protocol library,
|
|
39
42
|
not a hosted client. It does not execute OpenPond Desktop or Sandbox sessions,
|
|
40
43
|
resolve credentials, or persist artifacts.
|
|
@@ -122,6 +125,29 @@ semantics. Infrastructure failures must remain reward-ineligible.
|
|
|
122
125
|
Package semver and schema literals are independent. See [CONTRACT.md](./CONTRACT.md)
|
|
123
126
|
for compatibility aliases, migration rules, size limits, and the field map.
|
|
124
127
|
|
|
128
|
+
## Training telemetry
|
|
129
|
+
|
|
130
|
+
The `@openpond/evals/telemetry` subpath defines the cross-runtime Run event,
|
|
131
|
+
metric, cohort, evidence-completeness, and export-bundle protocol. It includes a
|
|
132
|
+
bounded core metric catalog, deterministic builders, duplicate and late-delivery
|
|
133
|
+
merge semantics, chart-ready aggregation, cohort filtering, and
|
|
134
|
+
visibility-aware export helpers. The sibling `openpond-evals` Python
|
|
135
|
+
distribution implements the producer-facing models, builders, and asynchronous
|
|
136
|
+
buffered emitter used by GPU workers and external trainers; both languages
|
|
137
|
+
validate the same fixtures and schema literals.
|
|
138
|
+
|
|
139
|
+
Telemetry records what an admitted Run did; it does not configure the Taskset
|
|
140
|
+
or execute training. Core observations are accepted only when their metric ID
|
|
141
|
+
and bounded dimensions match the catalog. Custom metrics require an explicit
|
|
142
|
+
versioned definition. Events carry immutable Run/Model/Harness/Taskset lineage,
|
|
143
|
+
producer sequence, source authority, and evidence visibility.
|
|
144
|
+
|
|
145
|
+
Portable export bundles contain definitions, events, observations, bounded
|
|
146
|
+
evidence references, completeness state, and a content hash. Raw trace bytes,
|
|
147
|
+
credentials, provider handles, tenant identity, billing policy, and hosted
|
|
148
|
+
indexes remain host-owned. The package contains no trainer, optimizer,
|
|
149
|
+
provisioner, persistence client, or diagnostic agent.
|
|
150
|
+
|
|
125
151
|
## Release preparation
|
|
126
152
|
|
|
127
153
|
```bash
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "openpond.runTelemetryBatch.v1",
|
|
3
|
+
"events": [
|
|
4
|
+
{
|
|
5
|
+
"schemaVersion": "openpond.runTelemetryEvent.v1",
|
|
6
|
+
"eventId": "event-invalid",
|
|
7
|
+
"sequence": -1,
|
|
8
|
+
"occurredAt": "not-a-timestamp",
|
|
9
|
+
"source": "unknown_source",
|
|
10
|
+
"type": "optimizer_step_completed",
|
|
11
|
+
"visibility": "team_visible",
|
|
12
|
+
"lineage": {},
|
|
13
|
+
"attributes": {}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"observations": []
|
|
17
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "openpond.runTelemetryBatch.v1",
|
|
3
|
+
"events": [
|
|
4
|
+
{
|
|
5
|
+
"schemaVersion": "openpond.runTelemetryEvent.v1",
|
|
6
|
+
"eventId": "event-optimizer-step-1",
|
|
7
|
+
"sequence": 1,
|
|
8
|
+
"occurredAt": "2026-08-25T20:00:00.000Z",
|
|
9
|
+
"source": "optimizer",
|
|
10
|
+
"type": "optimizer_step_completed",
|
|
11
|
+
"visibility": "team_visible",
|
|
12
|
+
"lineage": {
|
|
13
|
+
"modelProjectId": "project-1",
|
|
14
|
+
"runId": "run-1",
|
|
15
|
+
"modelVersionId": "version-1",
|
|
16
|
+
"harnessReleaseHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
17
|
+
"tasksetReleaseHash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
18
|
+
"environmentReleaseHash": null,
|
|
19
|
+
"checkpointId": null,
|
|
20
|
+
"step": 1,
|
|
21
|
+
"rolloutGroupId": "group-1",
|
|
22
|
+
"attemptId": null,
|
|
23
|
+
"scenarioId": "scenario-1"
|
|
24
|
+
},
|
|
25
|
+
"attributes": {
|
|
26
|
+
"learningRate": 0.00001,
|
|
27
|
+
"runner": "openpond_direct_grpo_v1"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"observations": [
|
|
32
|
+
{
|
|
33
|
+
"schemaVersion": "openpond.metricObservation.v1",
|
|
34
|
+
"observationId": "observation-learning-rate-1",
|
|
35
|
+
"metricId": "optimizer.learning_rate",
|
|
36
|
+
"eventId": "event-optimizer-step-1",
|
|
37
|
+
"sequence": 2,
|
|
38
|
+
"observedAt": "2026-08-25T20:00:00.000Z",
|
|
39
|
+
"value": 0.00001,
|
|
40
|
+
"lineage": {
|
|
41
|
+
"modelProjectId": "project-1",
|
|
42
|
+
"runId": "run-1",
|
|
43
|
+
"modelVersionId": "version-1",
|
|
44
|
+
"harnessReleaseHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
45
|
+
"tasksetReleaseHash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
46
|
+
"environmentReleaseHash": null,
|
|
47
|
+
"checkpointId": null,
|
|
48
|
+
"step": 1,
|
|
49
|
+
"rolloutGroupId": "group-1",
|
|
50
|
+
"attemptId": null,
|
|
51
|
+
"scenarioId": "scenario-1"
|
|
52
|
+
},
|
|
53
|
+
"dimensions": {
|
|
54
|
+
"split": "train"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
package/dist/graders.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { FailureClassSchema, ReleaseHashSchema, ReleaseIdSchema, contentHash } from "@openpond/harness";
|
|
3
|
+
import { validateTaskSchema, validateTaskValue } from "./task-schema.js";
|
|
3
4
|
export const GraderEvidenceContentSchema = z.object({
|
|
4
5
|
schemaVersion: z.literal("openpond.graderEvidence.v1"),
|
|
5
6
|
graderId: ReleaseIdSchema,
|
|
@@ -48,22 +49,42 @@ function gradeDeterministic(grader, task, attempt) {
|
|
|
48
49
|
const outputField = string(config.outputField) ?? "text";
|
|
49
50
|
const actual = string(attempt.output[outputField]);
|
|
50
51
|
const expected = string(config.expectedValue) ?? string(task.expectedOutput?.[string(config.expectedField) ?? "text"]);
|
|
52
|
+
if (expected === null || !normalize(expected))
|
|
53
|
+
return unavailable("Content grading requires a nonempty expected value.");
|
|
51
54
|
passed = actual !== null && expected !== null && normalize(actual) === normalize(expected);
|
|
52
55
|
}
|
|
53
56
|
else if (grader.kind === "schema") {
|
|
54
|
-
|
|
57
|
+
if (config.jsonSchema !== undefined) {
|
|
58
|
+
const schema = validateTaskSchema(config.jsonSchema);
|
|
59
|
+
if (!schema.valid)
|
|
60
|
+
return unavailable(schema.issues[0].message);
|
|
61
|
+
passed = validateTaskValue(config.jsonSchema, attempt.output).valid;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const required = strings(config.requiredKeys);
|
|
65
|
+
if (!required.length)
|
|
66
|
+
return unavailable("Schema grading requires a JSON Schema or explicit required keys.");
|
|
67
|
+
passed = required.every((key) => Object.hasOwn(attempt.output, key));
|
|
68
|
+
}
|
|
55
69
|
}
|
|
56
70
|
else if (grader.kind === "artifact") {
|
|
57
71
|
const contains = string(config.refIncludes) ?? "";
|
|
72
|
+
if (!contains)
|
|
73
|
+
return unavailable("Artifact grading requires a declared artifact reference.");
|
|
58
74
|
passed = attempt.artifactRefs.some((ref) => ref.includes(contains));
|
|
59
75
|
}
|
|
60
76
|
else if (grader.kind === "runtime_event") {
|
|
61
|
-
|
|
77
|
+
const requiredEvents = strings(config.requiredEvents);
|
|
78
|
+
if (!requiredEvents.length)
|
|
79
|
+
return unavailable("Runtime event grading requires declared events.");
|
|
80
|
+
passed = requiredEvents.every((required) => attempt.runtimeEventRefs.some((ref) => ref.includes(required)));
|
|
62
81
|
}
|
|
63
82
|
else {
|
|
64
83
|
const fields = strings(config.fields);
|
|
65
84
|
const compared = fields.length ? fields : Object.keys(task.expectedOutput ?? {});
|
|
66
|
-
|
|
85
|
+
if (!compared.length || compared.some((field) => !task.expectedOutput || !Object.hasOwn(task.expectedOutput, field)))
|
|
86
|
+
return unavailable("State grading requires expected values for every compared field.");
|
|
87
|
+
passed = compared.every((field) => Object.hasOwn(attempt.output, field) && contentHash(attempt.output[field]) === contentHash(task.expectedOutput[field]));
|
|
67
88
|
}
|
|
68
89
|
return {
|
|
69
90
|
score: passed ? 1 : 0,
|
|
@@ -81,7 +102,7 @@ function evidence(grader, result) {
|
|
|
81
102
|
graderId: grader.id,
|
|
82
103
|
graderVersion: grader.version,
|
|
83
104
|
...result,
|
|
84
|
-
rewardEligible: grader.rewardEligible && result.score !== null,
|
|
105
|
+
rewardEligible: grader.rewardEligible && result.rewardEligible && result.score !== null,
|
|
85
106
|
});
|
|
86
107
|
return GraderEvidenceSchema.parse({ ...content, contentHash: contentHash(content) });
|
|
87
108
|
}
|
|
@@ -89,5 +110,5 @@ function unavailable(message) {
|
|
|
89
110
|
return { score: null, passed: false, rewardEligible: false, failureClass: "grader_failure", feedback: [message], visibleEvidenceRefs: [], privilegedEvidenceRefs: [] };
|
|
90
111
|
}
|
|
91
112
|
function string(value) { return typeof value === "string" ? value : null; }
|
|
92
|
-
function strings(value) { return Array.isArray(value) ? value.filter((item) => typeof item === "string") : []; }
|
|
113
|
+
function strings(value) { return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : []; }
|
|
93
114
|
function normalize(value) { return value.normalize("NFKC").trim().replace(/[,,]/g, "").replace(/[.\s]+$/g, "").replace(/\s+/g, " "); }
|
package/dist/index.js
CHANGED
|
@@ -6,9 +6,17 @@ export * from "./execution-contracts.js";
|
|
|
6
6
|
export * from "./execution-receipts.js";
|
|
7
7
|
export * from "./graders.js";
|
|
8
8
|
export * from "./harness.js";
|
|
9
|
+
export * from "./learned-preference.js";
|
|
9
10
|
export * from "./runs.js";
|
|
10
11
|
export * from "./model-improvement-qualification.js";
|
|
11
12
|
export * from "./preferences.js";
|
|
12
13
|
export * from "./review-conformance.js";
|
|
13
14
|
export * from "./rollouts.js";
|
|
15
|
+
export * from "./telemetry.js";
|
|
16
|
+
export * from "./telemetry-catalog.js";
|
|
17
|
+
export * from "./telemetry-analysis.js";
|
|
18
|
+
export * from "./telemetry-bundle.js";
|
|
14
19
|
export * from "./tasksets.js";
|
|
20
|
+
export * from "./task-schema.js";
|
|
21
|
+
export * from "./rewards.js";
|
|
22
|
+
export * from "./learning/index.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const JavaScriptVerifierResultSchema = z.object({
|
|
3
|
+
score: z.number().finite().min(0).max(1),
|
|
4
|
+
passed: z.boolean(),
|
|
5
|
+
feedback: z.string().max(20_000),
|
|
6
|
+
evidenceRefs: z.array(z.string().max(240)).max(1_000).default([]),
|
|
7
|
+
}).strict();
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Worker } from "node:worker_threads";
|
|
2
|
+
import { JavaScriptVerifierResultSchema } from "./javascript-verifier-contract.js";
|
|
3
|
+
import { javascriptVerifierWorkerSource } from "./javascript-verifier-worker-source.js";
|
|
4
|
+
import { assertBoundedTaskJson } from "./task-schema.js";
|
|
5
|
+
/** Resolves/rejects only after the execution owner has stopped the worker. */
|
|
6
|
+
export async function executeJavaScriptVerifierInWorker(input) {
|
|
7
|
+
input.signal?.throwIfAborted();
|
|
8
|
+
if (!Number.isInteger(input.timeoutMs) || input.timeoutMs < 1 || input.timeoutMs > 300_000)
|
|
9
|
+
throw new Error("verifier_timeout_invalid");
|
|
10
|
+
assertBoundedTaskJson(input.value, 4_194_304);
|
|
11
|
+
if (new TextEncoder().encode(input.source).byteLength > 524_288)
|
|
12
|
+
throw new Error("verifier_source_too_large");
|
|
13
|
+
const { signal, ...workerData } = input;
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const worker = new Worker(javascriptVerifierWorkerSource, {
|
|
16
|
+
eval: true, workerData, execArgv: [], env: {},
|
|
17
|
+
resourceLimits: { maxOldGenerationSizeMb: 64, maxYoungGenerationSizeMb: 16, stackSizeMb: 4 },
|
|
18
|
+
});
|
|
19
|
+
let settling = false;
|
|
20
|
+
const finish = (outcome) => {
|
|
21
|
+
if (settling)
|
|
22
|
+
return;
|
|
23
|
+
settling = true;
|
|
24
|
+
clearTimeout(timer);
|
|
25
|
+
signal?.removeEventListener("abort", cancel);
|
|
26
|
+
void worker.terminate().then(() => {
|
|
27
|
+
if ("error" in outcome)
|
|
28
|
+
reject(outcome.error);
|
|
29
|
+
else
|
|
30
|
+
resolve(outcome.result);
|
|
31
|
+
}, reject);
|
|
32
|
+
};
|
|
33
|
+
const cancel = () => finish({ error: signal?.reason instanceof Error ? signal.reason : new Error("verifier_cancelled") });
|
|
34
|
+
const timer = setTimeout(() => finish({ error: new Error("verifier_timeout") }), input.timeoutMs);
|
|
35
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
36
|
+
worker.once("error", (error) => finish({ error }));
|
|
37
|
+
worker.once("exit", () => { if (!settling)
|
|
38
|
+
finish({ error: new Error("verifier_worker_exited_without_result") }); });
|
|
39
|
+
worker.once("message", (message) => {
|
|
40
|
+
try {
|
|
41
|
+
if (!message || typeof message !== "object" || !("ok" in message))
|
|
42
|
+
throw new Error("verifier_worker_invalid_response");
|
|
43
|
+
if (message.ok !== true)
|
|
44
|
+
throw new Error("error" in message && typeof message.error === "string" ? message.error : "verifier_execution_failed");
|
|
45
|
+
if (!("result" in message))
|
|
46
|
+
throw new Error("verifier_worker_invalid_response");
|
|
47
|
+
finish({ result: JavaScriptVerifierResultSchema.parse(message.result) });
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
finish({ error: error instanceof Error ? error : new Error("verifier_worker_invalid_response") });
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
if (signal?.aborted)
|
|
54
|
+
cancel();
|
|
55
|
+
});
|
|
56
|
+
}
|