@tangle-network/agent-eval 0.205.2 → 0.207.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/CHANGELOG.md +11 -0
- package/dist/adapters/http.d.ts +1 -1
- package/dist/analyst/index.d.ts +1 -1
- package/dist/analyst/index.js +1 -1
- package/dist/{benchmark-command-DuDTN5ID.js → benchmark-command-DtP94cOB.js} +2 -2
- package/dist/{benchmark-command-DuDTN5ID.js.map → benchmark-command-DtP94cOB.js.map} +1 -1
- package/dist/benchmarks/index.d.ts +2 -2
- package/dist/campaign/index.d.ts +3 -3
- package/dist/campaign/index.js +2 -2
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/contract/index.d.ts +4 -4
- package/dist/{define-agent-eval-CKB6wyML.d.ts → define-agent-eval-B2YV-RDE.d.ts} +3 -3
- package/dist/{define-agent-eval-CKB6wyML.d.ts.map → define-agent-eval-B2YV-RDE.d.ts.map} +1 -1
- package/dist/{index-BRdZ0oJo.d.ts → index-CojsA_EE.d.ts} +2 -2
- package/dist/{index-BRdZ0oJo.d.ts.map → index-CojsA_EE.d.ts.map} +1 -1
- package/dist/{index-R8Xhod8e.d.ts → index-DVDiJIhi.d.ts} +3 -3
- package/dist/{index-R8Xhod8e.d.ts.map → index-DVDiJIhi.d.ts.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/meta-eval/index.d.ts +69 -0
- package/dist/meta-eval/index.d.ts.map +1 -1
- package/dist/meta-eval/index.js +135 -1
- package/dist/meta-eval/index.js.map +1 -1
- package/dist/openapi.json +1 -1
- package/dist/rl.d.ts +12 -12
- package/dist/rl.d.ts.map +1 -1
- package/dist/rl.js +17 -17
- package/dist/rl.js.map +1 -1
- package/dist/search/index.d.ts +8 -2
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +1 -1
- package/dist/{search-kernel-DNpsHb8P.d.ts → search-kernel-CZ8KJQRw.d.ts} +6 -3
- package/dist/{search-kernel-DNpsHb8P.d.ts.map → search-kernel-CZ8KJQRw.d.ts.map} +1 -1
- package/dist/systemone-protocol-DKoi1NdK.d.ts +132 -0
- package/dist/systemone-protocol-DKoi1NdK.d.ts.map +1 -0
- package/dist/systemone-protocol.d.ts +2 -0
- package/dist/systemone-protocol.js +214 -0
- package/dist/systemone-protocol.js.map +1 -0
- package/dist/{jev-review-Cw06AKuF.d.ts → systemone-review-DGTKkLMG.d.ts} +16 -16
- package/dist/systemone-review-DGTKkLMG.d.ts.map +1 -0
- package/dist/{jev-review-DZEjDzlF.js → systemone-review-DTClwgmE.js} +11 -11
- package/dist/systemone-review-DTClwgmE.js.map +1 -0
- package/dist/systemone.d.ts +60 -0
- package/dist/systemone.d.ts.map +1 -0
- package/dist/{jev.js → systemone.js} +16 -16
- package/dist/systemone.js.map +1 -0
- package/dist/{tree-By7LtLUu.js → tree-CN8mlzUO.js} +11 -3
- package/dist/{tree-By7LtLUu.js.map → tree-CN8mlzUO.js.map} +1 -1
- package/docs/changes/jev-evidence-review.md +1 -1
- package/docs/changes/systemone-provider-neutral.md +36 -0
- package/docs/public-api.md +96 -70
- package/docs/search-ledger.md +9 -3
- package/docs/{jev-behavior-review.md → systemone-behavior-review.md} +17 -17
- package/docs/{jev-integrations.md → systemone-integrations.md} +4 -4
- package/docs/{jev-replay.md → systemone-replay.md} +6 -6
- package/docs/{jev.md → systemone.md} +96 -33
- package/package.json +9 -9
- package/dist/jev-protocol-BQLxwbqD.d.ts +0 -99
- package/dist/jev-protocol-BQLxwbqD.d.ts.map +0 -1
- package/dist/jev-protocol.d.ts +0 -2
- package/dist/jev-protocol.js +0 -114
- package/dist/jev-protocol.js.map +0 -1
- package/dist/jev-review-Cw06AKuF.d.ts.map +0 -1
- package/dist/jev-review-DZEjDzlF.js.map +0 -1
- package/dist/jev.d.ts +0 -60
- package/dist/jev.d.ts.map +0 -1
- package/dist/jev.js.map +0 -1
|
@@ -4,17 +4,17 @@ Use native evaluations to assess bounded hypotheses about recorded behavior. Do
|
|
|
4
4
|
classifier whether an agent is "malicious" or a whole run is "safe". Observable policy breaches,
|
|
5
5
|
model-supported hypotheses, missing evidence and unusual behavior are different results.
|
|
6
6
|
|
|
7
|
-
The optional `/
|
|
7
|
+
The optional `/systemone` helpers are ordinary functions:
|
|
8
8
|
|
|
9
|
-
- `
|
|
9
|
+
- `prepareSystemOneReview`: validate and freeze caller-defined native questions, evidence references,
|
|
10
10
|
coverage and decision thresholds before spending. The digest binds the definition, input and
|
|
11
11
|
authored question/option order. Optional undefined object fields are absent on the wire.
|
|
12
|
-
- `
|
|
12
|
+
- `assessSystemOneReview`: validate native answers and interpret designated alternative masses as
|
|
13
13
|
`supported`, `refuted` or `unresolved`. Re-scoring makes no network call.
|
|
14
|
-
- `
|
|
14
|
+
- `systemOneReviewFindings`: map that report into the existing `AnalystFinding` contract. It keeps
|
|
15
15
|
unresolved checks visible and labels supported claims as model-supported hypotheses.
|
|
16
16
|
|
|
17
|
-
These helpers do not constrain `
|
|
17
|
+
These helpers do not constrain `systemOneEvaluator`, `systemOneJudge`, `systemOneAnalyst`, or the provider-independent
|
|
18
18
|
`createEvaluator`/`asJudge`/`asAnalyst` APIs. Use an ordinary custom mapper for different policies.
|
|
19
19
|
No model, taxonomy, severity, operating threshold, global safety score or storage backend is chosen
|
|
20
20
|
by the generic implementation.
|
|
@@ -26,16 +26,16 @@ Supply the native request on each invocation. This example's `question`, `eviden
|
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
28
|
import {
|
|
29
|
-
|
|
30
|
-
} from '@tangle-network/agent-eval/
|
|
29
|
+
prepareSystemOneReview, assessSystemOneReview, systemOneEvaluator,
|
|
30
|
+
} from '@tangle-network/agent-eval/systemone'
|
|
31
31
|
|
|
32
|
-
const evaluate =
|
|
32
|
+
const evaluate = systemOneEvaluator({
|
|
33
33
|
evaluate: nativeTransport, // One Router /v1/systemone attempt; preserve signal/idempotency key.
|
|
34
34
|
receipt: readRouterReceipt,
|
|
35
35
|
maximumCharge: enforcedMaximumCharge,
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
-
const review =
|
|
38
|
+
const review = prepareSystemOneReview({
|
|
39
39
|
version: policy.version,
|
|
40
40
|
request: {
|
|
41
41
|
model: selectedModel,
|
|
@@ -59,7 +59,7 @@ const review = prepareJevReview({
|
|
|
59
59
|
})
|
|
60
60
|
const result = await evaluate(review.request, executionContext)
|
|
61
61
|
await persistAuthorizedObservation({ review, result })
|
|
62
|
-
const report =
|
|
62
|
+
const report = assessSystemOneReview(review, result.value)
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
The example assumes a native Choice question with `supported`, `refuted` and `insufficient`
|
|
@@ -71,8 +71,8 @@ not a requirement imposed on other evaluators.
|
|
|
71
71
|
|
|
72
72
|
## Optional behavior recipe
|
|
73
73
|
|
|
74
|
-
`examples/
|
|
75
|
-
`behaviorReviewAnalyst`, which composes the existing `
|
|
74
|
+
`examples/systemone-behavior-review.ts` provides replaceable question definitions and
|
|
75
|
+
`behaviorReviewAnalyst`, which composes the existing `systemOneAnalyst`. Copy/adapt the recipe in an
|
|
76
76
|
application; it is not a default policy installed by importing the package. Select only relevant
|
|
77
77
|
checks and provide thresholds, severity, exact policy and evidence for every selected check.
|
|
78
78
|
|
|
@@ -126,7 +126,7 @@ probability with its frozen binary threshold rule; it must not silently drop the
|
|
|
126
126
|
`/rl` already has `detectRewardHacking` for reward divergence, distribution shift, reward
|
|
127
127
|
disagreement and judge drift. Those diagnostic scores are not probabilities. Keep the raw,
|
|
128
128
|
ungated proxy and independently measured task outcome so a previous rejection does not hide the
|
|
129
|
-
disagreement. Do not substitute the
|
|
129
|
+
disagreement. Do not substitute the System One monitor as the only independent outcome.
|
|
130
130
|
|
|
131
131
|
The analyst system already has deterministic control-integrity and behavioral/efficiency
|
|
132
132
|
checks, plus deep trace analyst definitions such as intent divergence and knowledge poisoning.
|
|
@@ -134,7 +134,7 @@ Run exact checks for facts code can establish; use a bounded semantic review for
|
|
|
134
134
|
escalate selected cases to the existing deeper analyst. None is replaced by this recipe.
|
|
135
135
|
|
|
136
136
|
A prepared review can be a custom registry input or built from a filtered trace store. Existing
|
|
137
|
-
`asAnalyst`/`
|
|
137
|
+
`asAnalyst`/`systemOneAnalyst` forward the shared paid-call account, cancellation and deadline. The
|
|
138
138
|
recipe verifies persisted definition identity before inference, records the native observation
|
|
139
139
|
before mapping, and returns ordinary findings. Graphs consume these through their existing
|
|
140
140
|
analyst-registry adapter. No new supervisor, scheduler, ledger, or trace database is introduced.
|
|
@@ -158,7 +158,7 @@ It decides `pass`, `hack` or `unknown` for one claim from signals the caller com
|
|
|
158
158
|
- `farmingSignal`: one value of a parameter the scope declares, repeated across a lane's sweep of claims.
|
|
159
159
|
- `graderReferenceSignal`: the claim page justifies itself by the checker or by the printed letter.
|
|
160
160
|
- `refereeSignal`: a model reads the source and the claim's parameters, never the claimant's prose (`sourceScopeRefereeMessages`, `parseSourceScopeReferee`).
|
|
161
|
-
- `
|
|
161
|
+
- `systemOneSignal`: typed questions over the same brief (`claimIntegritySystemOneReview`). The caller supplies calibrated thresholds.
|
|
162
162
|
- `monitorSignal`: `askTraceQuestions` with `claimIntegrityTraceQuestions`, on escalation only.
|
|
163
163
|
- `checkerReadSignal`: context for a reader; it never moves a verdict.
|
|
164
164
|
|
|
@@ -172,7 +172,7 @@ Keep verdicts, scopes and questions away from the agent that filed the claim: an
|
|
|
172
172
|
## Security and validation boundaries
|
|
173
173
|
|
|
174
174
|
TypeSafe's Jev 1.13 documentation explicitly warns that adversarial state content can move the
|
|
175
|
-
answer. Delimiters and explicit criteria are useful instructions, not a proof of injection
|
|
175
|
+
answer; treat every System One model the same way. Delimiters and explicit criteria are useful instructions, not a proof of injection
|
|
176
176
|
resistance. These monitors are advisory evidence, not the sole authorization/safety barrier.
|
|
177
177
|
Trusted policy and references must come from outside the evaluated agent; tenant scope, redaction,
|
|
178
178
|
credential handling and controls remain with existing application/security owners.
|
|
@@ -192,7 +192,7 @@ attacks, not only the worker under a fixed monitor.
|
|
|
192
192
|
|
|
193
193
|
The new tests exercise pure mapping, canonical identity, metadata isolation and real
|
|
194
194
|
Eval/AnalystRegistry accounting composition with an injected model boundary. They do not prove
|
|
195
|
-
that
|
|
195
|
+
that a System One model detects these behaviors correctly or is robust against adversarial prompts. No live
|
|
196
196
|
provider, product UI rollout, runtime hook installation or production enforcement is added here.
|
|
197
197
|
|
|
198
198
|
Sources reviewed: https://docs.typesafe.ai/confidence and
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Ten useful integrations, one evaluator
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
answers.
|
|
3
|
+
A System One model evaluates bounded questions. Applications supply state, questions and the policy interpreting
|
|
4
|
+
answers. systemOneEvaluator handles the native model; createEvaluator supports other classifiers.
|
|
5
5
|
asJudge and asAnalyst adapt the same operation to existing consumers.
|
|
6
6
|
|
|
7
7
|
| Use | Outcome | Existing execution path |
|
|
@@ -10,12 +10,12 @@ asJudge and asAnalyst adapt the same operation to existing consumers.
|
|
|
10
10
|
| Recommendation triage | Prioritize evidence-linked Intelligence recommendations | Product triage selects existing engine findings and preserves their identities. |
|
|
11
11
|
| Trace diagnosis | Narrow likely failures before deeper investigation | AnalystRegistry, scoped evidence, and the existing deep analyst. |
|
|
12
12
|
| Behavioral review | Flag observable policy concerns, not hidden intent | Optional behavior-review recipe plus deterministic reward/control checks. |
|
|
13
|
-
| Rubric judging | Compare product or agent outputs |
|
|
13
|
+
| Rubric judging | Compare product or agent outputs | systemOneJudge/asJudge with caller mappings and independent final assessment. |
|
|
14
14
|
| Context selection | Select useful retrieved evidence | Native assessments, then deterministic packing with mandatory context protected. |
|
|
15
15
|
| Skill selection | Select from authorized capabilities | Caller alternatives, including no-selection; existing runtime executes actions. |
|
|
16
16
|
| Next verification | Choose a test, retrieval or review that resolves uncertainty | Existing graph checkpoints and awaited boundaries, not new permissions. |
|
|
17
17
|
| Candidate selection | Choose among generated plans or artifacts | Existing matrix/graph, exact checks first, semantic assessment second. |
|
|
18
|
-
| Configuration experiments | Compare questions, context, models and thresholds | examples/
|
|
18
|
+
| Configuration experiments | Compare questions, context, models and thresholds | examples/systemone-decision-benchmark.ts using runAgentMatrix and cost receipts. |
|
|
19
19
|
|
|
20
20
|
These are compositions, not ten new frameworks. Product triage and the benchmark recipe are concrete
|
|
21
21
|
adoption work; other rows reuse existing APIs or identify application policies to configure. An API
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Inspect recorded
|
|
1
|
+
# Inspect recorded System One evidence without new inference
|
|
2
2
|
|
|
3
3
|
The historical decoder from #897 is already the protocol owner. This example
|
|
4
4
|
uses that implementation; it adds no parser, SDK, ledger, database or replay
|
|
@@ -7,7 +7,7 @@ policy.
|
|
|
7
7
|
From a repository checkout with dependencies installed:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
pnpm exec tsx examples/
|
|
10
|
+
pnpm exec tsx examples/systemone-replay.ts request.json response.json
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Supply the original native request and response as separate JSON files. The
|
|
@@ -18,8 +18,8 @@ metadata such as generation IDs and decimal receipt strings. Neither input file
|
|
|
18
18
|
is rewritten. This is offline inspection, not replay of a paid provider request.
|
|
19
19
|
|
|
20
20
|
Historical null state and null score levels remain readable through
|
|
21
|
-
`
|
|
22
|
-
`
|
|
21
|
+
`parseSystemOneRecordedRequest`. They are still invalid for new paid calls through
|
|
22
|
+
`parseSystemOneRequest`. Do not cast a historical request to the live type, or change
|
|
23
23
|
its stored rubric just to satisfy today's admission schema.
|
|
24
24
|
|
|
25
25
|
A mismatch, unreadable file or malformed record returns exit code 1 with a
|
|
@@ -30,9 +30,9 @@ terminal or output destination and retain its existing access controls.
|
|
|
30
30
|
The same helper is importable from the example:
|
|
31
31
|
|
|
32
32
|
```ts
|
|
33
|
-
import {
|
|
33
|
+
import { inspectSystemOneFiles } from './examples/systemone-replay'
|
|
34
34
|
|
|
35
|
-
const observation = await
|
|
35
|
+
const observation = await inspectSystemOneFiles('request.json', 'response.json')
|
|
36
36
|
// Apply an application-owned deterministic mapping to the retained answers.
|
|
37
37
|
```
|
|
38
38
|
|
|
@@ -1,35 +1,50 @@
|
|
|
1
|
-
#
|
|
1
|
+
# System One evaluations: products, judges, and analysts
|
|
2
|
+
|
|
3
|
+
System One is a typed decision protocol: a request carries `state` and named questions (noul
|
|
4
|
+
yes/no, choice, or score rubric), and the answer is a probability for every allowed option.
|
|
5
|
+
TypeSafe published it with Jev; Cloudflare Workers AI (Clef, Clef-flash) and Perplexity's
|
|
6
|
+
Decisions API (pplx-decider) serve models on the same wire format. This package owns what a
|
|
7
|
+
valid result means. It names no endpoint, credential or model. Tangle Router owns the provider
|
|
8
|
+
routes behind `POST /v1/systemone`, with their prices, limits and served-model checks, so a
|
|
9
|
+
consumer changes models by changing one id.
|
|
2
10
|
|
|
3
11
|
Configure a transport once. Supply your own model, state, and questions on every
|
|
4
12
|
call. Interpret the answers in ordinary code; no campaign or agent is required.
|
|
5
13
|
|
|
6
14
|
```ts
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
import { systemOneEvaluator } from '@tangle-network/agent-eval/systemone'
|
|
16
|
+
|
|
17
|
+
const evaluate = systemOneEvaluator({
|
|
18
|
+
evaluate: async (request, { signal, idempotencyKey }) => {
|
|
19
|
+
const response = await fetch(`${routerOrigin}/v1/systemone`, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
signal,
|
|
22
|
+
headers: {
|
|
23
|
+
Authorization: `Bearer ${scopedRouterKey}`,
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
'Idempotency-Key': idempotencyKey,
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify(request),
|
|
28
|
+
})
|
|
29
|
+
if (!response.ok) throw new Error(`System One request failed: ${response.status}`)
|
|
30
|
+
return response.json()
|
|
31
|
+
},
|
|
21
32
|
pricing: reviewedTokenPricing, // An estimate, not a provider-observed charge.
|
|
22
33
|
})
|
|
23
34
|
|
|
24
35
|
const result = await evaluate({
|
|
25
|
-
model: selectedModel,
|
|
36
|
+
model: selectedModel, // a native_evaluation id from Router's /v1/models
|
|
26
37
|
state: { requirements, evidence },
|
|
27
38
|
questions: {
|
|
28
|
-
supported: noul
|
|
29
|
-
next:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
supported: { type: 'noul', instructions: 'Does the evidence support the claim?' },
|
|
40
|
+
next: {
|
|
41
|
+
type: 'choice',
|
|
42
|
+
instructions: 'Choose the next step using the evidence',
|
|
43
|
+
criteria: {
|
|
44
|
+
inspect: 'Evidence is missing or contradictory',
|
|
45
|
+
finish: 'The requirements are satisfied',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
33
48
|
},
|
|
34
49
|
}, { signal, costLedger })
|
|
35
50
|
|
|
@@ -38,21 +53,68 @@ result.value.answers.next.probabilities.inspect // number
|
|
|
38
53
|
result.receipt // Existing CostLedger receipt, separate from native answers.
|
|
39
54
|
```
|
|
40
55
|
|
|
41
|
-
The named configuration and evidence values belong to the application.
|
|
42
|
-
|
|
56
|
+
The named configuration and evidence values belong to the application. TypeSafe's SDK
|
|
57
|
+
builders produce the same JSON and are optional. Structured criteria, null instructions and choice or noul
|
|
43
58
|
descriptions, and omitted optional fields are supported. `state` and each score
|
|
44
|
-
level must be text or JSON; TypeSafe rejects null there, so the parser does too.
|
|
59
|
+
level must be text or JSON; TypeSafe rejects null there, so the parser does too. Providers
|
|
60
|
+
add their own limits: Clef requires non-null `instructions`, 1–64 questions with ids matching
|
|
61
|
+
`^[A-Za-z0-9_.-]{1,100}$`, and 2–255 choice options. Static TypeScript questions preserve
|
|
45
62
|
exact answer names and choice-label unions. Runtime JSON must be validated; its
|
|
46
63
|
labels cannot become compile-time literals automatically.
|
|
47
64
|
|
|
48
|
-
##
|
|
65
|
+
## Providers, rounding and confidence
|
|
66
|
+
|
|
67
|
+
The wire format is the same for every provider; how each reports its numbers is not. A
|
|
68
|
+
provider's raw result goes through `normalizeSystemOneResult(raw, request, profile)` and then
|
|
69
|
+
the strict `parseSystemOneResult`. The route owner supplies the profile.
|
|
70
|
+
|
|
71
|
+
| Recorded 2026-10-04 | Rounding | `confidence` as returned | Profile |
|
|
72
|
+
| --- | --- | --- | --- |
|
|
73
|
+
| TypeSafe `jev-1.13.0` | 2 decimals. Probabilities sum to 1; the score is not always their expectation (8.79 against 8.86). | `systemOneConfidence` (153 of 153 recorded answers within rounding) | `{ decimals: 2, confidence: 'canonical' }` |
|
|
74
|
+
| Cloudflare `clef`, `clef-flash` | 4 decimals, each probability rounded on its own. Wrapped in Workers AI's `{ result, success, errors, messages }`. | (Σp² − 1/n)/(1 − 1/n) | `{ decimals: 4, confidence: 'provider-defined' }` |
|
|
75
|
+
|
|
76
|
+
The recordings are `tests/fixtures/systemone/providers-2026-10-04.json`, checked by
|
|
77
|
+
`tests/systemone-providers.test.ts`. Without normalization, the strict parser refuses both
|
|
78
|
+
recorded TypeSafe score answers and both recorded Clef score answers.
|
|
79
|
+
|
|
80
|
+
- An answer that already passes the strict checks keeps its probabilities and score.
|
|
81
|
+
- An answer that fails them only within the declared rounding is repaired. A distribution whose
|
|
82
|
+
sum is more than 1e-4 from 1 is divided by its sum. A score becomes the expectation of the
|
|
83
|
+
distribution.
|
|
84
|
+
- Error beyond the rounding throws `SystemOneResponseError`; it is a provider defect. The
|
|
85
|
+
bounds are n half-units for the sum and half a unit plus one unit per level index for the score.
|
|
86
|
+
- With `confidence: 'provider-defined'`, the provider's value moves to `provider_confidence` and
|
|
87
|
+
`confidence` becomes `systemOneConfidence(probabilities)`, so every route reports the same
|
|
88
|
+
function of its probabilities: TypeSafe's published formulas
|
|
89
|
+
(https://docs.typesafe.ai/confidence).
|
|
90
|
+
- Noul answers never change. `noul` is the probability of yes for every provider.
|
|
91
|
+
|
|
92
|
+
Probabilities are not made equivalent across models. A Clef 0.8 and a Jev 0.8 are different
|
|
93
|
+
statements, so a threshold belongs to one model: change `{ model, threshold }` together and audit
|
|
94
|
+
the pair with `auditProbabilityPolicy` against independent outcomes.
|
|
95
|
+
|
|
96
|
+
Score each question type with its proper scoring rule from `/meta-eval`, on `probabilities` and
|
|
97
|
+
`noul`, never on `confidence`:
|
|
98
|
+
|
|
99
|
+
| Question | Rule |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `noul` | `brierScore` (binary) |
|
|
102
|
+
| `choice` | `multiclassBrierScore` (sum form, range 0 to 2) |
|
|
103
|
+
| `score` | `rankedProbabilityScore` (levels in order, range 0 to 1) |
|
|
104
|
+
|
|
105
|
+
Top-label ECE comes from `calibrationFromPairs` on (top probability, top answer correct) pairs, with
|
|
106
|
+
`range: { lo: 0, hi: 1 }` and `binning: 'equal-frequency'` for equal-mass bins.
|
|
107
|
+
When items share a source (one task, one pull request), interval estimates resample whole sources:
|
|
108
|
+
`clusterBootstrapMean` takes per-item values or per-item paired differences with their cluster id.
|
|
109
|
+
|
|
110
|
+
## Any classifier, not only System One
|
|
49
111
|
|
|
50
112
|
`createEvaluator`, `asJudge`, and `asAnalyst` are provider-independent exports from
|
|
51
|
-
`@tangle-network/agent-eval/evaluation` (also re-exported from `/
|
|
113
|
+
`@tangle-network/agent-eval/evaluation` (also re-exported from `/systemone`).
|
|
52
114
|
`createEvaluator({ execute, receipt })` meters a typed asynchronous function.
|
|
53
|
-
It does not require a
|
|
115
|
+
It does not require a System One response, probability output, prompt, or provider SDK.
|
|
54
116
|
|
|
55
|
-
`
|
|
117
|
+
`systemOneEvaluator` adds native protocol validation and optional `acceptModel(requested,
|
|
56
118
|
served)` policy. It preserves the reported model instead of guessing alias rules.
|
|
57
119
|
Router independently enforces its supported model and pricing policy.
|
|
58
120
|
|
|
@@ -69,13 +131,13 @@ and analyst context. `map(value, input, analystContext)` creates evidence-backed
|
|
|
69
131
|
findings. Use the existing `makeFinding` factory and real event/span/artifact references.
|
|
70
132
|
An empty finding list is valid; an inference failure is not a clean review.
|
|
71
133
|
|
|
72
|
-
The optional `
|
|
134
|
+
The optional `systemOneJudge` and `systemOneAnalyst` conveniences accept static questions or a
|
|
73
135
|
question-producing function. State renderers may be async. Judge renderers receive
|
|
74
136
|
the evaluation context; analyst renderers and finding mappers receive the effective
|
|
75
137
|
cancellation/deadline signal. Rendering must honor that signal during external work.
|
|
76
138
|
Both conveniences accept a `record` callback for the complete observation.
|
|
77
139
|
|
|
78
|
-
For a numeric rubric, `
|
|
140
|
+
For a numeric rubric, `systemOneJudge` defaults to `normalizedSystemOneScore`: equally spaced
|
|
79
141
|
score expectations on [0,1], noul values unchanged, and an optional weighted mean.
|
|
80
142
|
It emits no canned notes. Supply `map` for choice utilities, different scales, or
|
|
81
143
|
critical-failure policies. Dynamic questions and custom mappings require explicit
|
|
@@ -98,7 +160,7 @@ none is supplied, an explicit `budgetUsd` creates an account for that invocation
|
|
|
98
160
|
Otherwise the evaluator keeps its configured ledger, including its cumulative cap
|
|
99
161
|
across direct calls, judges, and analysts. An absent analyst budget never creates a
|
|
100
162
|
fresh unlimited account that overrides the configured one. This precedence is the
|
|
101
|
-
same for
|
|
163
|
+
same for System One and other classifiers. A per-analysis budget replaces the default
|
|
102
164
|
account; it is not an additional child limit. Pass the shared run ledger explicitly
|
|
103
165
|
when the whole run must conserve one authority. Only trusted host code should choose
|
|
104
166
|
or replace that authority.
|
|
@@ -132,10 +194,11 @@ confidence as demonstrated calibration or a classification as proof of root caus
|
|
|
132
194
|
|
|
133
195
|
## Checks
|
|
134
196
|
|
|
135
|
-
Run `pnpm exec vitest run tests/
|
|
197
|
+
Run `pnpm exec vitest run tests/systemone*.test.ts tests/evaluation-authority.test.ts`,
|
|
136
198
|
`pnpm typecheck`, `pnpm build`, and `pnpm verify:package`. These are contract and
|
|
137
199
|
execution checks, not live-provider quality or deployment evidence. The product-integrity
|
|
138
200
|
rubric lives in `examples/`, not the generic implementation, and is not a default policy.
|
|
139
201
|
|
|
140
202
|
Protocol: https://docs.typesafe.ai/api
|
|
141
|
-
|
|
203
|
+
Clef: https://developers.cloudflare.com/workers-ai/models/clef/
|
|
204
|
+
SDK (optional builders): https://github.com/typesafe-ai/typesafe-sdk-js
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-eval",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.207.0",
|
|
4
4
|
"description": "Evaluate and improve AI agents from runs, traces, judges, and feedback. Compare candidates, cluster failures, measure lift, and gate releases.",
|
|
5
5
|
"homepage": "https://github.com/tangle-network/agent-eval#readme",
|
|
6
6
|
"repository": {
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"import": "./dist/index.js",
|
|
20
20
|
"default": "./dist/index.js"
|
|
21
21
|
},
|
|
22
|
-
"./
|
|
23
|
-
"types": "./dist/
|
|
24
|
-
"import": "./dist/
|
|
25
|
-
"default": "./dist/
|
|
22
|
+
"./systemone": {
|
|
23
|
+
"types": "./dist/systemone.d.ts",
|
|
24
|
+
"import": "./dist/systemone.js",
|
|
25
|
+
"default": "./dist/systemone.js"
|
|
26
26
|
},
|
|
27
27
|
"./profile-cell": {
|
|
28
28
|
"types": "./dist/profile-cell.d.ts",
|
|
@@ -177,10 +177,10 @@
|
|
|
177
177
|
"import": "./dist/evaluation.js",
|
|
178
178
|
"default": "./dist/evaluation.js"
|
|
179
179
|
},
|
|
180
|
-
"./
|
|
181
|
-
"types": "./dist/
|
|
182
|
-
"import": "./dist/
|
|
183
|
-
"default": "./dist/
|
|
180
|
+
"./systemone/protocol": {
|
|
181
|
+
"types": "./dist/systemone-protocol.d.ts",
|
|
182
|
+
"import": "./dist/systemone-protocol.js",
|
|
183
|
+
"default": "./dist/systemone-protocol.js"
|
|
184
184
|
}
|
|
185
185
|
},
|
|
186
186
|
"bin": {
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
//#region src/jev-protocol.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Structural equivalents of TypeSafe's published request schema
|
|
4
|
-
* (https://api.typesafe.ai/openapi.json); callers can use its builders unchanged.
|
|
5
|
-
*/
|
|
6
|
-
type JevJson = string | number | boolean | null | JevJson[] | {
|
|
7
|
-
[key: string]: JevJson;
|
|
8
|
-
};
|
|
9
|
-
/** What TypeSafe accepts as `state` and as a score level: text or JSON, never null. */
|
|
10
|
-
type JevState = string | {
|
|
11
|
-
[key: string]: JevJson;
|
|
12
|
-
} | JevJson[];
|
|
13
|
-
/** Instructions and choice or noul descriptions, which TypeSafe also accepts as null. */
|
|
14
|
-
type JevDescription = JevState | null;
|
|
15
|
-
type JevScoreCriteria = readonly [JevState, JevState, ...JevState[]];
|
|
16
|
-
type JevQuestion = {
|
|
17
|
-
type: 'noul';
|
|
18
|
-
instructions?: JevDescription;
|
|
19
|
-
criteria?: {
|
|
20
|
-
true?: JevDescription;
|
|
21
|
-
false?: JevDescription;
|
|
22
|
-
} | null;
|
|
23
|
-
} | {
|
|
24
|
-
type: 'score';
|
|
25
|
-
instructions?: JevDescription;
|
|
26
|
-
criteria: JevScoreCriteria;
|
|
27
|
-
} | {
|
|
28
|
-
type: 'choice';
|
|
29
|
-
instructions?: JevDescription;
|
|
30
|
-
criteria: Record<string, JevDescription>;
|
|
31
|
-
};
|
|
32
|
-
type JevQuestions = Record<string, JevQuestion>;
|
|
33
|
-
interface JevRequest<Q extends JevQuestions = JevQuestions> {
|
|
34
|
-
model: string;
|
|
35
|
-
state: JevState;
|
|
36
|
-
questions: Q;
|
|
37
|
-
}
|
|
38
|
-
/** Historical Tangle observations accepted null state and score levels. Not a live request. */
|
|
39
|
-
type JevRecordedQuestion = Exclude<JevQuestion, {
|
|
40
|
-
type: 'score';
|
|
41
|
-
}> | {
|
|
42
|
-
type: 'score';
|
|
43
|
-
instructions?: JevDescription;
|
|
44
|
-
criteria: readonly [JevDescription, JevDescription, ...JevDescription[]];
|
|
45
|
-
};
|
|
46
|
-
type JevRecordedQuestions = Record<string, JevRecordedQuestion>;
|
|
47
|
-
interface JevRecordedRequest<Q extends JevRecordedQuestions = JevRecordedQuestions> {
|
|
48
|
-
model: string;
|
|
49
|
-
state: JevDescription;
|
|
50
|
-
questions: Q;
|
|
51
|
-
}
|
|
52
|
-
type ScoreKeys<T extends readonly JevDescription[]> = number extends T['length'] ? number : Extract<keyof T, `${number}`>;
|
|
53
|
-
type JevAnswerFor<Q extends JevRecordedQuestion> = Q extends {
|
|
54
|
-
type: 'noul';
|
|
55
|
-
} ? {
|
|
56
|
-
readonly type: 'noul';
|
|
57
|
-
readonly noul: number;
|
|
58
|
-
} : Q extends {
|
|
59
|
-
type: 'score';
|
|
60
|
-
criteria: infer C extends readonly JevDescription[];
|
|
61
|
-
} ? {
|
|
62
|
-
readonly type: 'score';
|
|
63
|
-
readonly score: number;
|
|
64
|
-
readonly confidence: number;
|
|
65
|
-
readonly legend: { readonly [K in ScoreKeys<C>]: C[K]; };
|
|
66
|
-
readonly probabilities: { readonly [K in ScoreKeys<C>]: number; };
|
|
67
|
-
} : Q extends {
|
|
68
|
-
type: 'choice';
|
|
69
|
-
criteria: infer C;
|
|
70
|
-
} ? {
|
|
71
|
-
readonly type: 'choice';
|
|
72
|
-
readonly choice: keyof C & string;
|
|
73
|
-
readonly confidence: number;
|
|
74
|
-
readonly probabilities: { readonly [K in keyof C]: number; };
|
|
75
|
-
} : never;
|
|
76
|
-
type JevAnswer = JevAnswerFor<JevQuestion>;
|
|
77
|
-
interface JevResult<Q extends JevRecordedQuestions = JevQuestions> {
|
|
78
|
-
readonly model: string;
|
|
79
|
-
readonly answers: { readonly [K in keyof Q]: JevAnswerFor<Q[K]>; };
|
|
80
|
-
readonly usage: {
|
|
81
|
-
readonly input_tokens: number;
|
|
82
|
-
readonly output_tokens: number;
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
declare class JevResponseError extends Error {
|
|
86
|
-
constructor(message: string);
|
|
87
|
-
}
|
|
88
|
-
/** Validate named questions without a state, as a judge does before it has input. */
|
|
89
|
-
declare function parseJevQuestions(raw: unknown): JevQuestions;
|
|
90
|
-
declare function parseJevRequest(raw: unknown): JevRequest;
|
|
91
|
-
/** Read immutable historical evidence without rewriting it or authorizing new inference.
|
|
92
|
-
* Live transports must still call parseJevRequest, even for re-execution of an old request. */
|
|
93
|
-
declare function parseJevRecordedRequest(raw: unknown): JevRecordedRequest;
|
|
94
|
-
declare function jevUsage(raw: unknown): JevResult['usage'];
|
|
95
|
-
/** Validate native evidence, not model alias policy or the caller's scoring rules. */
|
|
96
|
-
declare function parseJevResult<Q extends JevRecordedQuestions>(raw: unknown, request: JevRecordedRequest<Q>): JevResult<Q>;
|
|
97
|
-
//#endregion
|
|
98
|
-
export { parseJevRecordedRequest as _, JevQuestion as a, JevRecordedQuestions as c, JevResponseError as d, JevResult as f, parseJevQuestions as g, jevUsage as h, JevJson as i, JevRecordedRequest as l, JevState as m, JevAnswerFor as n, JevQuestions as o, JevScoreCriteria as p, JevDescription as r, JevRecordedQuestion as s, JevAnswer as t, JevRequest as u, parseJevRequest as v, parseJevResult as y };
|
|
99
|
-
//# sourceMappingURL=jev-protocol-BQLxwbqD.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jev-protocol-BQLxwbqD.d.ts","names":[],"sources":["../src/jev-protocol.ts"],"mappings":";;;;;KAOY,6CAA6C;GAAe,cAAc;;;KAE1E;GAAuB,cAAc;IAAY;;KAEjD,iBAAiB;KACjB,6BAA6B,UAAU,aAAa;KACpD;EAEN;EACA,eAAe;EACf;IAAa,OAAO;IAAgB,QAAQ;;;EAE5C;EAAe,eAAe;EAAgB,UAAU;;EACxD;EAAgB,eAAe;EAAgB,UAAU,eAAe;;KAClE,eAAe,eAAe;UACzB,WAAW,UAAU,eAAe;EACnD;EACA,OAAO;EACP,WAAW;;;KAID,sBACR,QAAQ;EAAe;;EAErB;EACA,eAAe;EACf,oBAAoB,gBAAgB,mBAAmB;;KAEjD,uBAAuB,eAAe;UACjC,mBAAmB,UAAU,uBAAuB;EACnE;EACA,OAAO;EACP,WAAW;;KAGR,UAAU,mBAAmB,mCAAmC,uBAEjE,cAAc;KACN,aAAa,UAAU,uBAAuB;EAAY;;WACvD;WAAuB;IAClC;EAAY;EAAe,gBAAgB,mBAAmB;;WAEjD;WACA;WACA;WACA,oBAAoB,KAAK,UAAU,KAAK,EAAE;WAC1C,2BAA2B,KAAK,UAAU;IAErD;EAAY;EAAgB,gBAAgB;;WAE/B;WACA,cAAc;WACd;WACA,2BAA2B,WAAW;;KAG7C,YAAY,aAAa;UACpB,UAAU,UAAU,uBAAuB;WACjD;WACA,qBAAqB,WAAW,IAAI,aAAa,EAAE;WACnD;aAAkB;aAA+B;;;cAG/C,yBAAyB;EACpC,YAAY;;;iBA6BE,kBAAkB,eAAe;iBAyCjC,gBAAgB,eAAe;;;iBAM/B,wBAAwB,eAAe;iBAevC,SAAS,eAAe;;iBA2BxB,eAAe,UAAU,sBACvC,cACA,SAAS,mBAAmB,KAC3B,UAAU"}
|
package/dist/jev-protocol.d.ts
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { _ as parseJevRecordedRequest, a as JevQuestion, c as JevRecordedQuestions, d as JevResponseError, f as JevResult, g as parseJevQuestions, h as jevUsage, i as JevJson, l as JevRecordedRequest, m as JevState, n as JevAnswerFor, o as JevQuestions, p as JevScoreCriteria, r as JevDescription, s as JevRecordedQuestion, t as JevAnswer, u as JevRequest, v as parseJevRequest, y as parseJevResult } from "./jev-protocol-BQLxwbqD.js";
|
|
2
|
-
export { JevAnswer, JevAnswerFor, JevDescription, JevJson, JevQuestion, JevQuestions, JevRecordedQuestion, JevRecordedQuestions, JevRecordedRequest, JevRequest, JevResponseError, JevResult, JevScoreCriteria, JevState, jevUsage, parseJevQuestions, parseJevRecordedRequest, parseJevRequest, parseJevResult };
|
package/dist/jev-protocol.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { r as canonicalString } from "./canonical-BsZVgBhW.js";
|
|
2
|
-
import { isDeepStrictEqual } from "node:util";
|
|
3
|
-
//#region src/jev-protocol.ts
|
|
4
|
-
var JevResponseError = class extends Error {
|
|
5
|
-
constructor(message) {
|
|
6
|
-
super(`Jev: ${message}`);
|
|
7
|
-
this.name = "JevResponseError";
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
function object(value) {
|
|
11
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new JevResponseError("Expected an object");
|
|
12
|
-
return value;
|
|
13
|
-
}
|
|
14
|
-
function textOrJson(value, name) {
|
|
15
|
-
if (typeof value === "string") return;
|
|
16
|
-
if (value === null || typeof value !== "object") throw new TypeError(`${name} must be text or a JSON object/array`);
|
|
17
|
-
canonicalString(value);
|
|
18
|
-
}
|
|
19
|
-
function optionalTextOrJson(value, name) {
|
|
20
|
-
if (value !== null) textOrJson(value, name);
|
|
21
|
-
}
|
|
22
|
-
/** Validate named questions without a state, as a judge does before it has input. */
|
|
23
|
-
function parseJevQuestions(raw) {
|
|
24
|
-
return readQuestions(raw, false);
|
|
25
|
-
}
|
|
26
|
-
function readQuestions(raw, recorded) {
|
|
27
|
-
const questions = object(raw);
|
|
28
|
-
if (!Object.keys(questions).length) throw new TypeError("At least one question is required");
|
|
29
|
-
for (const [name, rawQuestion] of Object.entries(questions)) {
|
|
30
|
-
const question = object(rawQuestion);
|
|
31
|
-
if (question.instructions !== void 0) optionalTextOrJson(question.instructions, `${name} instructions`);
|
|
32
|
-
if (question.type === "noul") {
|
|
33
|
-
if (question.criteria != null) {
|
|
34
|
-
const criteria = object(question.criteria);
|
|
35
|
-
if (Object.keys(criteria).some((key) => key !== "true" && key !== "false")) throw new TypeError("Noul criteria must describe true and/or false");
|
|
36
|
-
for (const value of Object.values(criteria)) if (value !== void 0) optionalTextOrJson(value, `${name} criteria`);
|
|
37
|
-
}
|
|
38
|
-
} else if (question.type === "score") {
|
|
39
|
-
if (!Array.isArray(question.criteria) || question.criteria.length < 2) throw new TypeError("Score criteria require at least two ordered entries");
|
|
40
|
-
for (const value of question.criteria) {
|
|
41
|
-
if (recorded && value === null) continue;
|
|
42
|
-
textOrJson(value, `${name} score level`);
|
|
43
|
-
}
|
|
44
|
-
} else if (question.type === "choice") {
|
|
45
|
-
const criteria = object(question.criteria);
|
|
46
|
-
if (!Object.keys(criteria).length) throw new TypeError("Choice criteria cannot be empty");
|
|
47
|
-
for (const value of Object.values(criteria)) optionalTextOrJson(value, `${name} choice`);
|
|
48
|
-
} else throw new TypeError("Unsupported native question type");
|
|
49
|
-
}
|
|
50
|
-
return raw;
|
|
51
|
-
}
|
|
52
|
-
function parseJevRequest(raw) {
|
|
53
|
-
return readRequest(raw, false);
|
|
54
|
-
}
|
|
55
|
-
/** Read immutable historical evidence without rewriting it or authorizing new inference.
|
|
56
|
-
* Live transports must still call parseJevRequest, even for re-execution of an old request. */
|
|
57
|
-
function parseJevRecordedRequest(raw) {
|
|
58
|
-
canonicalString(raw);
|
|
59
|
-
return readRequest(raw, true);
|
|
60
|
-
}
|
|
61
|
-
function readRequest(raw, recorded) {
|
|
62
|
-
const request = object(raw);
|
|
63
|
-
if (typeof request.model !== "string" || !request.model.trim()) throw new TypeError("Evaluation requires a model");
|
|
64
|
-
if (!recorded || request.state !== null) textOrJson(request.state, "Evaluation state");
|
|
65
|
-
readQuestions(request.questions, recorded);
|
|
66
|
-
return raw;
|
|
67
|
-
}
|
|
68
|
-
function jevUsage(raw) {
|
|
69
|
-
const usage = object(object(raw).usage);
|
|
70
|
-
for (const key of ["input_tokens", "output_tokens"]) if (!Number.isSafeInteger(usage[key]) || Number(usage[key]) < 0) throw new JevResponseError("Missing or invalid usage");
|
|
71
|
-
return usage;
|
|
72
|
-
}
|
|
73
|
-
function probability(value) {
|
|
74
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) throw new JevResponseError("Invalid probability");
|
|
75
|
-
return value;
|
|
76
|
-
}
|
|
77
|
-
function exactKeys(value, names) {
|
|
78
|
-
if (Object.keys(value).length !== names.length || names.some((key) => !Object.hasOwn(value, key))) throw new JevResponseError("Response keys differ from the request");
|
|
79
|
-
}
|
|
80
|
-
/** Validate native evidence, not model alias policy or the caller's scoring rules. */
|
|
81
|
-
function parseJevResult(raw, request) {
|
|
82
|
-
canonicalString(raw);
|
|
83
|
-
const response = object(raw);
|
|
84
|
-
if (typeof response.model !== "string" || !response.model.trim()) throw new JevResponseError("Missing served model");
|
|
85
|
-
const answers = object(response.answers);
|
|
86
|
-
exactKeys(answers, Object.keys(request.questions));
|
|
87
|
-
for (const [name, question] of Object.entries(request.questions)) {
|
|
88
|
-
const answer = object(answers[name]);
|
|
89
|
-
if (answer.type !== question.type) throw new JevResponseError("Wrong answer type");
|
|
90
|
-
if (question.type === "noul") {
|
|
91
|
-
probability(answer.noul);
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
probability(answer.confidence);
|
|
95
|
-
const levels = question.type === "score" ? question.criteria.map((_, index) => String(index)) : Object.keys(question.criteria);
|
|
96
|
-
const probabilities = object(answer.probabilities);
|
|
97
|
-
exactKeys(probabilities, levels);
|
|
98
|
-
const sum = levels.reduce((total, level) => total + probability(probabilities[level]), 0);
|
|
99
|
-
if (Math.abs(sum - 1) > 1e-4) throw new JevResponseError("Invalid probability distribution");
|
|
100
|
-
if (question.type === "score") {
|
|
101
|
-
const legend = object(answer.legend);
|
|
102
|
-
exactKeys(legend, levels);
|
|
103
|
-
if (levels.some((level) => !isDeepStrictEqual(legend[level], question.criteria[Number(level)]))) throw new JevResponseError("Provider changed the rubric");
|
|
104
|
-
const expected = levels.reduce((total, level) => total + Number(level) * Number(probabilities[level]), 0);
|
|
105
|
-
if (typeof answer.score !== "number" || !Number.isFinite(answer.score) || Math.abs(answer.score - expected) > 1e-4) throw new JevResponseError("Score differs from its distribution");
|
|
106
|
-
} else if (typeof answer.choice !== "string" || !Object.hasOwn(probabilities, answer.choice) || levels.some((level) => Number(probabilities[level]) > Number(probabilities[String(answer.choice)]) + 1e-4)) throw new JevResponseError("Choice is not a highest-probability option");
|
|
107
|
-
}
|
|
108
|
-
jevUsage(raw);
|
|
109
|
-
return raw;
|
|
110
|
-
}
|
|
111
|
-
//#endregion
|
|
112
|
-
export { JevResponseError, jevUsage, parseJevQuestions, parseJevRecordedRequest, parseJevRequest, parseJevResult };
|
|
113
|
-
|
|
114
|
-
//# sourceMappingURL=jev-protocol.js.map
|