@tangle-network/agent-eval 0.126.7 → 0.127.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 +44 -0
- package/README.md +2 -2
- package/dist/analyst/index.d.ts +51 -39
- package/dist/analyst/index.js +4 -4
- package/dist/belief-state/index.d.ts +34 -36
- package/dist/belief-state/index.js +2 -2
- package/dist/benchmarks/index.d.ts +30 -12
- package/dist/benchmarks/index.js +12 -10
- package/dist/builder-eval/index.js +1 -1
- package/dist/campaign/index.d.ts +432 -146
- package/dist/campaign/index.js +11 -9
- package/dist/{chunk-ARU2PZFM.js → chunk-424XHVKV.js} +43 -23
- package/dist/chunk-424XHVKV.js.map +1 -0
- package/dist/{chunk-NUKSVU3W.js → chunk-5DTSBUL2.js} +2 -2
- package/dist/{chunk-BTACVO2W.js → chunk-65QETEKG.js} +542 -258
- package/dist/chunk-65QETEKG.js.map +1 -0
- package/dist/{chunk-CGG5SLH3.js → chunk-ARCFIY7U.js} +2 -2
- package/dist/{chunk-P22LJ3Y2.js → chunk-CLELFRQG.js} +6 -4
- package/dist/chunk-CLELFRQG.js.map +1 -0
- package/dist/{chunk-LUNF2SEL.js → chunk-DJKY2TSY.js} +3 -3
- package/dist/chunk-DPUHNQLN.js +232 -0
- package/dist/chunk-DPUHNQLN.js.map +1 -0
- package/dist/{chunk-IPYXE555.js → chunk-EJGRPCO3.js} +36 -13
- package/dist/chunk-EJGRPCO3.js.map +1 -0
- package/dist/{chunk-K6IAZZ6L.js → chunk-FA3MFYNA.js} +132 -110
- package/dist/chunk-FA3MFYNA.js.map +1 -0
- package/dist/chunk-IG35YDN3.js +614 -0
- package/dist/chunk-IG35YDN3.js.map +1 -0
- package/dist/{chunk-DPZAEKA6.js → chunk-IMGJZBFG.js} +84 -56
- package/dist/chunk-IMGJZBFG.js.map +1 -0
- package/dist/{chunk-H5UD2323.js → chunk-IN455XKS.js} +53 -1
- package/dist/chunk-IN455XKS.js.map +1 -0
- package/dist/{chunk-PJQFMIOX.js → chunk-MHELPNRP.js} +31 -1
- package/dist/chunk-MHELPNRP.js.map +1 -0
- package/dist/{chunk-IILEIWGW.js → chunk-NL33OXEP.js} +41 -36
- package/dist/chunk-NL33OXEP.js.map +1 -0
- package/dist/{chunk-474LBSOX.js → chunk-OD5NQ2CS.js} +41 -16
- package/dist/chunk-OD5NQ2CS.js.map +1 -0
- package/dist/{chunk-QOTFXW5L.js → chunk-P5W7RQKK.js} +2 -2
- package/dist/{chunk-IR3KBHOY.js → chunk-P6FYH6K4.js} +39 -3
- package/dist/chunk-P6FYH6K4.js.map +1 -0
- package/dist/{chunk-J5SQWP6Y.js → chunk-PBE2LOSS.js} +18 -2
- package/dist/chunk-PBE2LOSS.js.map +1 -0
- package/dist/{chunk-E3IADPLG.js → chunk-PRB53E3J.js} +50 -224
- package/dist/chunk-PRB53E3J.js.map +1 -0
- package/dist/{chunk-X4UCIOTZ.js → chunk-S5YLIBFX.js} +2 -2
- package/dist/{chunk-7VYEGHWF.js → chunk-SZLVEKMJ.js} +41 -20
- package/dist/chunk-SZLVEKMJ.js.map +1 -0
- package/dist/{chunk-LKKT3IVV.js → chunk-TSN7JT6D.js} +6 -4
- package/dist/{chunk-LKKT3IVV.js.map → chunk-TSN7JT6D.js.map} +1 -1
- package/dist/{chunk-M7AH34KV.js → chunk-UTA2TGC4.js} +32 -16
- package/dist/chunk-UTA2TGC4.js.map +1 -0
- package/dist/{chunk-MAX3TN3C.js → chunk-UWZZKKU7.js} +7 -19
- package/dist/chunk-UWZZKKU7.js.map +1 -0
- package/dist/{chunk-ZVCHKKOP.js → chunk-WED5KLZQ.js} +39 -15
- package/dist/chunk-WED5KLZQ.js.map +1 -0
- package/dist/{chunk-OCFJACJU.js → chunk-X6VOPMLD.js} +74 -14
- package/dist/chunk-X6VOPMLD.js.map +1 -0
- package/dist/{chunk-MOXWMGPC.js → chunk-Y5CYOL42.js} +159 -70
- package/dist/chunk-Y5CYOL42.js.map +1 -0
- package/dist/{chunk-FO7HEH76.js → chunk-YJBNWCAA.js} +2 -2
- package/dist/chunk-ZPUEEM5U.js +179 -0
- package/dist/chunk-ZPUEEM5U.js.map +1 -0
- package/dist/{chunk-KE2VWPZX.js → chunk-ZUUWPZCV.js} +3 -3
- package/dist/cli.js +4 -4
- package/dist/contract/index.d.ts +421 -124
- package/dist/contract/index.js +242 -115
- package/dist/contract/index.js.map +1 -1
- package/dist/control.d.ts +34 -32
- package/dist/control.js +2 -2
- package/dist/hosted/index.d.ts +142 -41
- package/dist/hosted/index.js +23 -1
- package/dist/index.d.ts +364 -255
- package/dist/index.js +315 -226
- package/dist/index.js.map +1 -1
- package/dist/meta-eval/index.d.ts +32 -32
- package/dist/meta-eval/index.js +2 -2
- package/dist/multishot/index.d.ts +1 -0
- package/dist/openapi.json +1 -1
- package/dist/pipelines/index.js +2 -2
- package/dist/reporting.d.ts +97 -74
- package/dist/reporting.js +5 -4
- package/dist/rl.d.ts +177 -131
- package/dist/rl.js +232 -126
- package/dist/rl.js.map +1 -1
- package/dist/rollout/index.d.ts +53 -63
- package/dist/rollout/index.js +7 -5
- package/dist/{run-campaign-FFRM3RH5.js → run-campaign-3A2EBYBE.js} +4 -3
- package/dist/supervisor-run/index.d.ts +7 -15
- package/dist/supervisor-run/index.js +2 -2
- package/dist/traces.d.ts +66 -41
- package/dist/traces.js +9 -5
- package/dist/wire/index.d.ts +1 -0
- package/dist/wire/index.js +2 -2
- package/docs/concepts.md +18 -1
- package/docs/hosted-ingest-spec.md +37 -40
- package/docs/insight-report.md +57 -7
- package/docs/research-report-methodology.md +20 -21
- package/docs/rollout.md +13 -8
- package/package.json +4 -3
- package/dist/chunk-474LBSOX.js.map +0 -1
- package/dist/chunk-7VYEGHWF.js.map +0 -1
- package/dist/chunk-ARU2PZFM.js.map +0 -1
- package/dist/chunk-BTACVO2W.js.map +0 -1
- package/dist/chunk-DPZAEKA6.js.map +0 -1
- package/dist/chunk-E3IADPLG.js.map +0 -1
- package/dist/chunk-H5UD2323.js.map +0 -1
- package/dist/chunk-IILEIWGW.js.map +0 -1
- package/dist/chunk-IPYXE555.js.map +0 -1
- package/dist/chunk-IR3KBHOY.js.map +0 -1
- package/dist/chunk-J5SQWP6Y.js.map +0 -1
- package/dist/chunk-K6IAZZ6L.js.map +0 -1
- package/dist/chunk-M7AH34KV.js.map +0 -1
- package/dist/chunk-MAX3TN3C.js.map +0 -1
- package/dist/chunk-MOXWMGPC.js.map +0 -1
- package/dist/chunk-OCFJACJU.js.map +0 -1
- package/dist/chunk-P22LJ3Y2.js.map +0 -1
- package/dist/chunk-PJQFMIOX.js.map +0 -1
- package/dist/chunk-ZVCHKKOP.js.map +0 -1
- package/dist/chunk-ZZUXHH3R.js +0 -99
- package/dist/chunk-ZZUXHH3R.js.map +0 -1
- /package/dist/{chunk-NUKSVU3W.js.map → chunk-5DTSBUL2.js.map} +0 -0
- /package/dist/{chunk-CGG5SLH3.js.map → chunk-ARCFIY7U.js.map} +0 -0
- /package/dist/{chunk-LUNF2SEL.js.map → chunk-DJKY2TSY.js.map} +0 -0
- /package/dist/{chunk-QOTFXW5L.js.map → chunk-P5W7RQKK.js.map} +0 -0
- /package/dist/{chunk-X4UCIOTZ.js.map → chunk-S5YLIBFX.js.map} +0 -0
- /package/dist/{chunk-FO7HEH76.js.map → chunk-YJBNWCAA.js.map} +0 -0
- /package/dist/{chunk-KE2VWPZX.js.map → chunk-ZUUWPZCV.js.map} +0 -0
- /package/dist/{run-campaign-FFRM3RH5.js.map → run-campaign-3A2EBYBE.js.map} +0 -0
package/dist/traces.js
CHANGED
|
@@ -27,8 +27,8 @@ import {
|
|
|
27
27
|
scoreTraceInsightReadiness,
|
|
28
28
|
tokenizeDomainWords,
|
|
29
29
|
traceAnalystOnRunComplete
|
|
30
|
-
} from "./chunk-
|
|
31
|
-
import "./chunk-
|
|
30
|
+
} from "./chunk-X6VOPMLD.js";
|
|
31
|
+
import "./chunk-IN455XKS.js";
|
|
32
32
|
import {
|
|
33
33
|
extractUsage,
|
|
34
34
|
extractUsageFromResponse,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
TRACE_ANALYST_ACTOR_DESCRIPTION,
|
|
50
50
|
TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION,
|
|
51
51
|
analyzeTraces
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-5DTSBUL2.js";
|
|
53
53
|
import {
|
|
54
54
|
DEFAULT_REDACTION_RULES,
|
|
55
55
|
REDACTION_VERSION,
|
|
@@ -66,15 +66,17 @@ import {
|
|
|
66
66
|
applyToolSpanOtlpAttributes,
|
|
67
67
|
asString,
|
|
68
68
|
buildTraceAnalystTools,
|
|
69
|
+
classifyOtlpSpanRole,
|
|
69
70
|
extractOtlpAttributes,
|
|
70
71
|
firstStringAttr,
|
|
71
72
|
inferOtlpKind,
|
|
73
|
+
isOtlpModelCall,
|
|
72
74
|
projectOtlpFlatLine,
|
|
73
75
|
readOtlpStatus,
|
|
74
76
|
stringField,
|
|
75
77
|
traceAnalystFunctionGroup,
|
|
76
78
|
traceSpanKindToOpenInferenceKind
|
|
77
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-P6FYH6K4.js";
|
|
78
80
|
import {
|
|
79
81
|
RunIntegrityError,
|
|
80
82
|
assertRunCaptured,
|
|
@@ -91,7 +93,7 @@ import {
|
|
|
91
93
|
TraceEmitter,
|
|
92
94
|
llmSpanFromProvider
|
|
93
95
|
} from "./chunk-VQMK5FMP.js";
|
|
94
|
-
import "./chunk-
|
|
96
|
+
import "./chunk-NL33OXEP.js";
|
|
95
97
|
import {
|
|
96
98
|
FAILURE_CLASSES,
|
|
97
99
|
TRACE_SCHEMA_VERSION,
|
|
@@ -193,6 +195,7 @@ export {
|
|
|
193
195
|
buildTraceInsightContext,
|
|
194
196
|
buildTraceInsightPrompt,
|
|
195
197
|
captureFetchToRawSink,
|
|
198
|
+
classifyOtlpSpanRole,
|
|
196
199
|
contextInputTokens,
|
|
197
200
|
convertTraceStoresToOtlp,
|
|
198
201
|
createOtelExporter,
|
|
@@ -216,6 +219,7 @@ export {
|
|
|
216
219
|
inferOtlpKind,
|
|
217
220
|
isJudgeSpan,
|
|
218
221
|
isLlmSpan,
|
|
222
|
+
isOtlpModelCall,
|
|
219
223
|
isRetrievalSpan,
|
|
220
224
|
isSandboxSpan,
|
|
221
225
|
isToolSpan,
|
package/dist/wire/index.d.ts
CHANGED
|
@@ -640,6 +640,7 @@ type ProviderRedactor = (event: RawProviderEvent) => RawProviderEvent;
|
|
|
640
640
|
* OpenAI-compatible `/v1/chat/completions` client with:
|
|
641
641
|
* - Exponential-backoff retry on 429 + 5xx gateway errors (502/503/504).
|
|
642
642
|
* - Retry on transient network errors (fetch failed, AbortError, ECONNRESET).
|
|
643
|
+
* - One retry at temperature 1 when a model explicitly requires it.
|
|
643
644
|
* - Graceful json_schema → json_object degrade on 400 with schema-reject body.
|
|
644
645
|
* - Fenced-JSON stripping (```json ... ```) for models that wrap structured output.
|
|
645
646
|
* - Configurable base URL + api key / bearer, works with LiteLLM proxies, OpenAI
|
package/dist/wire/index.js
CHANGED
|
@@ -34,8 +34,8 @@ import {
|
|
|
34
34
|
runRpcOnce,
|
|
35
35
|
startServer,
|
|
36
36
|
startServerAsync
|
|
37
|
-
} from "../chunk-
|
|
38
|
-
import "../chunk-
|
|
37
|
+
} from "../chunk-YJBNWCAA.js";
|
|
38
|
+
import "../chunk-PBE2LOSS.js";
|
|
39
39
|
import "../chunk-WS3NZZQQ.js";
|
|
40
40
|
import "../chunk-VI2UW6B6.js";
|
|
41
41
|
import "../chunk-PC4UYEBM.js";
|
package/docs/concepts.md
CHANGED
|
@@ -43,6 +43,18 @@ Agent sessions, worker coordination, sandbox execution, and runtime-specific pro
|
|
|
43
43
|
|
|
44
44
|
Traces, datasets, optimization, statistics, and reports build on these objects.
|
|
45
45
|
|
|
46
|
+
## Release check results
|
|
47
|
+
|
|
48
|
+
Every entry in `GateResult.contributingGates` has a `status` of `pass`, `fail`, or `not_evaluated`.
|
|
49
|
+
`pass` and `fail` mean the check ran with sufficient input.
|
|
50
|
+
`not_evaluated` means the check lacked enough evidence to run.
|
|
51
|
+
`defaultProductionGate` always requires held-out significance.
|
|
52
|
+
Its other checks are optional until their input is configured or their name is included in `requiredChecks`.
|
|
53
|
+
A required check with missing or insufficient evidence remains `not_evaluated` and holds the release decision.
|
|
54
|
+
An absent optional check records `not_evaluated` and never appears as a successful check.
|
|
55
|
+
Run history is shared input only.
|
|
56
|
+
Enable reward-hacking and canary monitoring independently with `rewardHacking` and `canary`.
|
|
57
|
+
|
|
46
58
|
When the thing being evaluated is an agent that should keep working, use
|
|
47
59
|
[`runAgentControlLoop`](./control-runtime.md). It turns validators into a
|
|
48
60
|
runtime loop: observe typed state, validate it, decide the next action, act,
|
|
@@ -138,10 +150,15 @@ const verifier = new MultiLayerVerifier([
|
|
|
138
150
|
|
|
139
151
|
const report = await verifier.run({ env: { runner, workdir, ... } })
|
|
140
152
|
report.allPass // boolean: every layer passed
|
|
141
|
-
report.
|
|
153
|
+
report.taskScore // complete task score, or undefined
|
|
154
|
+
report.blendedScore // diagnostic weighted aggregate, possibly partial
|
|
142
155
|
report.layers // per-layer status, findings, duration
|
|
143
156
|
```
|
|
144
157
|
|
|
158
|
+
Use `taskScore` when creating task labels or training data.
|
|
159
|
+
An errored, timed-out, skipped, or incomplete scoring panel leaves `taskScore` undefined.
|
|
160
|
+
Use `blendedScore` only to inspect the measurements that did complete.
|
|
161
|
+
|
|
145
162
|
Two rules that will save you bugs:
|
|
146
163
|
|
|
147
164
|
1. **Run both gates.** Build gates catch code that doesn't compile; structural assertions catch missing files. Run both unconditionally: they catch orthogonal failures.
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
# Hosted-ingest wire spec: `2026-
|
|
1
|
+
# Hosted-ingest wire spec: `2026-07-24.v1`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
**new minors only add optional fields. Breaking changes mean a major
|
|
6
|
-
bump and a new `HostedWireVersion` literal.**
|
|
3
|
+
This is the only hosted-ingest wire format implemented by the current package.
|
|
4
|
+
Clients and servers reject every other wire version.
|
|
7
5
|
|
|
8
6
|
This is the contract between `@tangle-network/agent-eval` and any hosted
|
|
9
7
|
or self-hosted orchestrator. A builder can:
|
|
@@ -26,12 +24,12 @@ Two endpoints, both `POST`, both JSON. Headers on every request:
|
|
|
26
24
|
| `Authorization` | `Bearer <tenant-key>` (the orchestrator issues this) |
|
|
27
25
|
| `Content-Type` | `application/json` |
|
|
28
26
|
| `X-Tangle-Tenant-Id` | The tenant's stable id (the orchestrator's primary key for the tenant) |
|
|
29
|
-
| `X-Tangle-Wire-Version` | `2026-
|
|
30
|
-
| `Idempotency-Key`
|
|
27
|
+
| `X-Tangle-Wire-Version` | `2026-07-24.v1` (this spec) |
|
|
28
|
+
| `Idempotency-Key` | Non-empty request key, at most 256 characters; clients generate one per call and reuse it across retries |
|
|
31
29
|
|
|
32
|
-
Responses are JSON of shape `{ accepted: number, rejected: Array<{ index, reason }> }`.
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
Responses are JSON of shape `{ accepted: number, rejected: Array<{ index, reason }> }`.
|
|
31
|
+
Clients validate the complete response before returning it.
|
|
32
|
+
The server can return 202 for asynchronous acceptance or 200 for synchronous acceptance.
|
|
35
33
|
|
|
36
34
|
### `POST /v1/ingest/eval-runs`
|
|
37
35
|
|
|
@@ -75,6 +73,7 @@ interface EvalRunEvent {
|
|
|
75
73
|
totalCostUsd: number
|
|
76
74
|
totalDurationMs: number
|
|
77
75
|
errorMessage?: string // present when status === 'errored'
|
|
76
|
+
insightReport?: InsightReport // current report contract
|
|
78
77
|
}
|
|
79
78
|
```
|
|
80
79
|
|
|
@@ -86,7 +85,7 @@ interface EvalRunGenerationSnapshot {
|
|
|
86
85
|
surfaceHash: string // stable hash of the candidate surface (pivot key)
|
|
87
86
|
surface?: MutableSurface // OMITTED to avoid PII when consumer prefers
|
|
88
87
|
cells: EvalRunCellScore[]
|
|
89
|
-
compositeMean: number
|
|
88
|
+
compositeMean: number | null // null when no cell has a task-quality label
|
|
90
89
|
costUsd: number
|
|
91
90
|
durationMs: number
|
|
92
91
|
}
|
|
@@ -98,12 +97,14 @@ interface EvalRunGenerationSnapshot {
|
|
|
98
97
|
interface EvalRunCellScore {
|
|
99
98
|
scenarioId: string
|
|
100
99
|
rep: number // 0 for the default; > 0 when reps > 1
|
|
101
|
-
compositeMean: number
|
|
102
|
-
dimensions: Record< //
|
|
100
|
+
compositeMean: number | null // null when the cell is unscored
|
|
101
|
+
dimensions: Record< // successful scores; failed or missing judges are absent
|
|
103
102
|
string,
|
|
104
103
|
Record<string, number>
|
|
105
104
|
>
|
|
106
|
-
|
|
105
|
+
terminalOutcome: 'succeeded' | 'failed' | 'cancelled' | 'incomplete' | 'unknown'
|
|
106
|
+
executionErrorCount: number | null // null when the producer cannot classify errors
|
|
107
|
+
errorMessage?: string // present for a dispatch or judge error
|
|
107
108
|
}
|
|
108
109
|
```
|
|
109
110
|
|
|
@@ -116,10 +117,14 @@ interface TraceSpanEvent {
|
|
|
116
117
|
spanId: string
|
|
117
118
|
parentSpanId?: string
|
|
118
119
|
name: string
|
|
119
|
-
startTimeUnixNano:
|
|
120
|
-
endTimeUnixNano:
|
|
120
|
+
startTimeUnixNano: string // canonical unsigned 64-bit integer encoded in base 10
|
|
121
|
+
endTimeUnixNano: string // canonical unsigned 64-bit integer encoded in base 10
|
|
121
122
|
attributes: Record<string, string | number | boolean>
|
|
122
|
-
events?: Array<{
|
|
123
|
+
events?: Array<{
|
|
124
|
+
timeUnixNano: string // canonical unsigned 64-bit integer encoded in base 10
|
|
125
|
+
name: string
|
|
126
|
+
attributes?: Record<string, string | number | boolean>
|
|
127
|
+
}>
|
|
123
128
|
status?: { code: 'OK' | 'ERROR' | 'UNSET', message? }
|
|
124
129
|
|
|
125
130
|
// Tangle additions (all optional) for pivoting
|
|
@@ -143,12 +148,14 @@ Any orchestrator implementing this spec MUST:
|
|
|
143
148
|
a clear error message). The major component is the breaking-change axis.
|
|
144
149
|
3. **Validate tenant isolation**: queries with `tenantId` X never return
|
|
145
150
|
data tagged with `tenantId` Y. Test this adversarially.
|
|
146
|
-
4. **Honor idempotency**:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
4. **Honor idempotency**: require an `Idempotency-Key`; when it matches a prior request to the same endpoint from the same tenant in the last 24 hours, return the same response without processing the body again.
|
|
152
|
+
5. **Deduplicate spans**: store at most one span for each `(tenantId, traceId, spanId)` identity.
|
|
153
|
+
Accept an exact duplicate as already stored and reject a conflicting payload with the same identity.
|
|
154
|
+
6. **Keep run state monotonic**: accept forward lifecycle transitions, but never replace `finished` or `errored` with a late event.
|
|
155
|
+
Delayed events can add a missing generation without replacing terminal totals, labels, or status.
|
|
156
|
+
7. **Persist eval-runs durably**: at least the event + cell scores must
|
|
150
157
|
survive an orchestrator restart. Trace spans MAY be best-effort.
|
|
151
|
-
|
|
158
|
+
8. **Provide read access**: GET endpoints for the tenant to list + fetch
|
|
152
159
|
their own runs. Wire format for reads is NOT part of this spec: each
|
|
153
160
|
orchestrator can pick its own (REST + JSON, gRPC, GraphQL).
|
|
154
161
|
|
|
@@ -163,9 +170,9 @@ Servers SHOULD also:
|
|
|
163
170
|
|
|
164
171
|
## Reference implementation
|
|
165
172
|
|
|
166
|
-
`examples/hosted-ingest-server
|
|
167
|
-
|
|
168
|
-
|
|
173
|
+
`examples/hosted-ingest-server/` is a Hono receiver for local development and contract tests.
|
|
174
|
+
It validates auth, request and response shapes, versions, exact nanosecond strings, request keys, span identity, and monotonic run state.
|
|
175
|
+
It is not production storage because process restart clears its in-memory data.
|
|
169
176
|
|
|
170
177
|
```sh
|
|
171
178
|
TENANT_KEY=dev-token TENANT_ID=acme pnpm tsx examples/hosted-ingest-server/server.ts
|
|
@@ -185,19 +192,9 @@ receiver's `GET /v1/runs` lists it back.
|
|
|
185
192
|
|
|
186
193
|
---
|
|
187
194
|
|
|
188
|
-
##
|
|
195
|
+
## Version
|
|
189
196
|
|
|
190
|
-
`HostedWireVersion` is `"2026-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
(`2026-05-26.v2`).
|
|
195
|
-
- Changing the shape of an existing field, removing a field, or
|
|
196
|
-
changing semantics of an existing field → major wire bump
|
|
197
|
-
(`2026-11-XX.v1`); a server may accept both versions during a
|
|
198
|
-
transition window.
|
|
199
|
-
|
|
200
|
-
Servers MUST reject requests with `X-Tangle-Wire-Version` they don't
|
|
201
|
-
support, with a 400 listing the versions they DO accept.
|
|
202
|
-
|
|
203
|
-
The version string IS the spec id: pin against it.
|
|
197
|
+
`HostedWireVersion` is `"2026-07-24.v1"`.
|
|
198
|
+
The current clients emit only this value.
|
|
199
|
+
Servers return 400 for every other value and list the accepted version.
|
|
200
|
+
There are no compatibility readers or migration branches.
|
package/docs/insight-report.md
CHANGED
|
@@ -16,7 +16,7 @@ This page walks every section with a real (synthetic) example and explains how t
|
|
|
16
16
|
```ts
|
|
17
17
|
interface InsightReport {
|
|
18
18
|
n: number // runs analyzed
|
|
19
|
-
execution: ExecutionInsight // duration, tokens,
|
|
19
|
+
execution: ExecutionInsight // duration, tokens, errors, terminal outcomes
|
|
20
20
|
composite: ScalarDistribution // always
|
|
21
21
|
perDimension: Record<string, ScalarDistribution> // when judgeScores carry dimensions
|
|
22
22
|
costQuality: { cost: ScalarDistribution; pareto: ParetoFigureSpec } // always
|
|
@@ -36,14 +36,28 @@ interface InsightReport {
|
|
|
36
36
|
## `execution`: runtime facts, separate from quality
|
|
37
37
|
|
|
38
38
|
Always present.
|
|
39
|
-
It reports duration, optional queue time, direct input, output, reasoning, cache-read, and cache-write tokens, model-call coverage, model cohorts,
|
|
39
|
+
It reports duration, optional queue time, direct input, output, reasoning, cache-read, and cache-write tokens, model-call coverage, model cohorts, execution errors, terminal outcomes, and separately reported orchestration aggregates.
|
|
40
40
|
These fields describe what ran; they do not claim whether the task succeeded.
|
|
41
|
+
`executionErrors` counts child or internal errors reported by the producer.
|
|
42
|
+
`terminalOutcomes` reads only `RunRecord.terminalOutcome`, which must come from root-run or process evidence.
|
|
43
|
+
A child tool error can therefore appear in a run whose terminal outcome is `succeeded`.
|
|
44
|
+
Current OTel and code-agent adapters also preserve process, guardrail, judge, propagated-parent, and unknown error counts in `RunRecord.outcome.raw`.
|
|
45
|
+
These counters are diagnostic and never become task-quality scores.
|
|
41
46
|
|
|
42
47
|
```jsonc
|
|
43
48
|
{
|
|
44
49
|
"execution": {
|
|
45
50
|
"durationMs": { "n": 30, "p50": 5400, "p95": 82000, "min": 900, "max": 190000 },
|
|
46
|
-
"queueMs": {
|
|
51
|
+
"queueMs": {
|
|
52
|
+
"n": 0,
|
|
53
|
+
"mean": null,
|
|
54
|
+
"p50": null,
|
|
55
|
+
"p95": null,
|
|
56
|
+
"stddev": null,
|
|
57
|
+
"min": null,
|
|
58
|
+
"max": null,
|
|
59
|
+
"histogram": []
|
|
60
|
+
},
|
|
47
61
|
"tokenUsage": {
|
|
48
62
|
"totals": { "input": 50132, "output": 471783, "reasoning": 12000, "cached": 60489565, "cacheWrite": 3032227 },
|
|
49
63
|
"input": { "n": 30, "p50": 25, "p95": 56 },
|
|
@@ -62,12 +76,40 @@ These fields describe what ran; they do not claim whether the task succeeded.
|
|
|
62
76
|
},
|
|
63
77
|
"modelCalls": { "runs": 20, "events": 42, "reportingRuns": 30 },
|
|
64
78
|
"models": [{ "model": "claude-opus@2026-07-01", "runs": 20 }],
|
|
65
|
-
"
|
|
79
|
+
"executionErrors": {
|
|
80
|
+
"runs": 2,
|
|
81
|
+
"fraction": 0.067,
|
|
82
|
+
"events": 3,
|
|
83
|
+
"reportingRuns": 30,
|
|
84
|
+
"errorSpanEvents": 3,
|
|
85
|
+
"errorSpanReportingRuns": 30,
|
|
86
|
+
"byTerminalOutcome": {
|
|
87
|
+
"succeeded": { "withErrors": 1, "withoutErrors": 26, "unreported": 0 },
|
|
88
|
+
"failed": { "withErrors": 0, "withoutErrors": 1, "unreported": 0 },
|
|
89
|
+
"cancelled": { "withErrors": 0, "withoutErrors": 0, "unreported": 0 },
|
|
90
|
+
"incomplete": { "withErrors": 0, "withoutErrors": 0, "unreported": 0 },
|
|
91
|
+
"unknown": { "withErrors": 1, "withoutErrors": 1, "unreported": 0 }
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"terminalOutcomes": {
|
|
95
|
+
"succeeded": 27,
|
|
96
|
+
"failed": 1,
|
|
97
|
+
"cancelled": 0,
|
|
98
|
+
"incomplete": 0,
|
|
99
|
+
"unknown": 2
|
|
100
|
+
}
|
|
66
101
|
}
|
|
67
102
|
}
|
|
68
103
|
```
|
|
69
104
|
|
|
70
105
|
Use `distribution.n` for optional fields to distinguish an uncaptured category from a recorded zero.
|
|
106
|
+
When `distribution.n` is zero, `mean`, percentiles, standard deviation, minimum, and maximum are `null`.
|
|
107
|
+
Use `executionErrors.reportingRuns` to assess error-telemetry coverage.
|
|
108
|
+
`errorSpanEvents` preserves the exact child-span error count separately from other reported execution errors.
|
|
109
|
+
The error fraction uses `reportingRuns` as its denominator and is `null` when no run reported error telemetry, so missing telemetry is not treated as a clean run.
|
|
110
|
+
`byTerminalOutcome` is a cross-tab, not a causal recovery claim.
|
|
111
|
+
It keeps reported errors, reported zeroes, and missing error telemetry separate for every terminal result.
|
|
112
|
+
Missing terminal evidence counts as `unknown`, not `failed`.
|
|
71
113
|
Never add `aggregateUsage` to direct `tokenUsage`: orchestration spans may repeat model-call usage from other traces.
|
|
72
114
|
Cost remains in `costQuality`, where observed, estimated, and uncaptured USD stay separate.
|
|
73
115
|
|
|
@@ -97,7 +139,9 @@ Always present. The basic "where are my numbers" view.
|
|
|
97
139
|
}
|
|
98
140
|
```
|
|
99
141
|
|
|
100
|
-
|
|
142
|
+
Read `composite.mean` only when `composite.n > 0`.
|
|
143
|
+
A `null` mean means task quality was not measured, not that quality was zero.
|
|
144
|
+
When a measured mean is below 0.5, inspect the lowest-scoring runs before tuning.
|
|
101
145
|
|
|
102
146
|
**Read next:** `perDimension`. If `clarity` is high but `concision` is low, your prompts get the right ideas in too many words: different fix than "wrong ideas."
|
|
103
147
|
|
|
@@ -204,13 +248,19 @@ Populated when baseline + candidate candidates are present (auto-detected from t
|
|
|
204
248
|
"ci95": [0.04, 0.10], // bootstrap CI on the delta
|
|
205
249
|
"pValue": 0.0008, // paired t-test
|
|
206
250
|
"n": 40, // paired observations
|
|
207
|
-
"
|
|
251
|
+
"unpairedBaselineRuns": 2,
|
|
252
|
+
"unpairedCandidateRuns": 1,
|
|
253
|
+
"cohensD": 0.41, // paired Cohen's dz; null when delta variance is zero
|
|
208
254
|
"mde": 0.06, // min detectable effect at current n, 80% power
|
|
209
|
-
"requiredN": 38 // n needed
|
|
255
|
+
"requiredN": 38 // paired n needed at 80% power; null when dz is undefined
|
|
210
256
|
}
|
|
211
257
|
}
|
|
212
258
|
```
|
|
213
259
|
|
|
260
|
+
Rows pair only when `(experimentId, scenarioId, seed)` matches.
|
|
261
|
+
Missing `scenarioId` and duplicate identities fail loudly.
|
|
262
|
+
Unmatched rows are reported and excluded from paired statistics.
|
|
263
|
+
|
|
214
264
|
**Decision rule:**
|
|
215
265
|
- `ci95[0] > threshold` → **SHIP.** Lower bound above your delta threshold means the lift is real at 95% confidence.
|
|
216
266
|
- `ci95[0] ≤ threshold < ci95[1]` → **INCONCLUSIVE.** Expand the corpus or wait for more data.
|
|
@@ -28,10 +28,10 @@ corresponding function or option so the doc and the code don't drift.
|
|
|
28
28
|
|
|
29
29
|
## Pairing
|
|
30
30
|
|
|
31
|
-
Pairs are joined by `(experimentId, seed)` so the comparator and candidate
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
with non-finite scores are
|
|
31
|
+
Pairs are joined by `(experimentId, scenarioId, seed)` so the comparator and candidate share the same experiment, scenario, and repetition.
|
|
32
|
+
This is the same join used by `gainHistogram`; see `pairRunRecords` in `src/paired-arms.ts`.
|
|
33
|
+
Missing or duplicate identities are rejected.
|
|
34
|
+
Records on the wrong split or with non-finite scores are excluded before pairing, and unmatched valid rows are reported.
|
|
35
35
|
|
|
36
36
|
## Decision rule
|
|
37
37
|
|
|
@@ -44,36 +44,35 @@ In order: first match wins:
|
|
|
44
44
|
not sufficient*; even a `promote` gate must clear the paired test below.
|
|
45
45
|
4. Paired N < `RESEARCH_REPORT_HARD_PAIR_FLOOR` → `needs_more_data` with a
|
|
46
46
|
"below hard floor" reason. Bootstrap CIs degenerate at this size.
|
|
47
|
-
5.
|
|
48
|
-
|
|
47
|
+
5. `split: 'search'` → `hold`.
|
|
48
|
+
Search results guide optimization but cannot authorize a release.
|
|
49
|
+
6. ROPE configured AND paired-delta CI ⊂ ROPE → `equivalent`.
|
|
50
|
+
7. Paired-delta CI upper bound < 0 → `reject` (CI excludes a non-negative
|
|
49
51
|
effect). Note: this uses **paired delta only**: not the marginal mean.
|
|
50
|
-
|
|
52
|
+
8. Paired N < `minPairs` (soft floor) → `needs_more_data` with the MDE at
|
|
51
53
|
current N attached so the verdict is actionable.
|
|
52
|
-
|
|
54
|
+
9. BH-adjusted q ≤ `fdr` AND CI lower bound > 0 → `promote`. The BH q-value
|
|
53
55
|
controls FDR across all candidates in the same sweep; the bootstrap CI
|
|
54
56
|
provides an effect-size guarantee independent of the test.
|
|
55
|
-
|
|
57
|
+
10. Otherwise → `hold`.
|
|
56
58
|
|
|
57
59
|
## Statistical primitives used
|
|
58
60
|
|
|
59
61
|
| Quantity | Function | Source file |
|
|
60
62
|
|---|---|---|
|
|
61
63
|
| Marginal CI on score mean | `confidenceInterval` | `statistics.ts` |
|
|
62
|
-
| Cohen's
|
|
64
|
+
| Paired Cohen's dz vs comparator | `pairedCohensDz` | `statistics.ts` |
|
|
63
65
|
| Wilcoxon signed-rank (paired) | `wilcoxonSignedRank` | `statistics.ts` |
|
|
64
|
-
| BH-FDR q-values | `benjaminiHochberg` | `
|
|
65
|
-
| Paired bootstrap CI on median delta | `pairedBootstrap` | `
|
|
66
|
-
| Bayesian-bootstrap
|
|
67
|
-
| Minimum detectable paired effect | `pairedMde` | `
|
|
66
|
+
| BH-FDR q-values | `benjaminiHochberg` | `statistics.ts` |
|
|
67
|
+
| Paired bootstrap CI on median delta | `pairedBootstrap` | `statistics.ts` |
|
|
68
|
+
| Bayesian-bootstrap Pr(Δ>0), Pr(Δ∈ROPE) | `bayesianBootstrapMeanSamples` | `summary-report.ts` (private) |
|
|
69
|
+
| Minimum detectable paired effect | `pairedMde` | `statistics.ts` |
|
|
68
70
|
| Run fingerprint | `hashJson(canonicalize(...))` | `pre-registration.ts` |
|
|
69
71
|
|
|
70
|
-
The Pr(Δ>0) and Pr(Δ∈ROPE) summaries use
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
**median** delta: the median is more robust to the heavy-tailed score
|
|
75
|
-
distributions seen in agent benchmarks; the mean lets us read off the
|
|
76
|
-
Bayesian-style probability of superiority in a single number.
|
|
72
|
+
The Pr(Δ>0) and Pr(Δ∈ROPE) summaries use Rubin's Bayesian bootstrap.
|
|
73
|
+
Each posterior draw assigns the observed paired deltas Dirichlet(1, ..., 1) weights, implemented as normalized independent Exponential(1) draws.
|
|
74
|
+
The posterior summaries apply to the **mean** delta.
|
|
75
|
+
The separate frequentist bootstrap CI applies to the **median** delta because the median is more robust to heavy-tailed agent scores.
|
|
77
76
|
|
|
78
77
|
## MDE
|
|
79
78
|
|
package/docs/rollout.md
CHANGED
|
@@ -25,24 +25,29 @@ Rule applied: where fields conflicted, RunRecord-derived semantics won; the ledg
|
|
|
25
25
|
| `schema: "tangle.rollout.v1"` | ledger | wire key is `schema` (PR #410's `format` key retired) |
|
|
26
26
|
| `rollout_id` / `parent_rollout_id` | ledger | minted lines use `runId` as `rollout_id` (deterministic); multi-agent producers mint UUIDs and point workers at their supervisor |
|
|
27
27
|
| `run_id` | both | `RunRecord.runId` |
|
|
28
|
-
| `experiment_id`, `candidate_id` | PR #410 |
|
|
28
|
+
| `experiment_id`, `candidate_id` | PR #410 | required keys; `null` means the producer did not record the value |
|
|
29
29
|
| `generation`, `candidate_index` | ledger | kept as improvement-loop coordinates; now `integer \| null` (`null` = not an improvement loop, `-1` = baseline) |
|
|
30
30
|
| `role` | ledger | enum extended with `agent` for solo eval runs (mint default) |
|
|
31
|
-
| `task.split` | conflict | **RunRecord semantics win**:
|
|
31
|
+
| `task.split` | conflict | **RunRecord semantics win**: `search` is the trainable pool; `dev` and `holdout` follow `RunSplitTag`; `canary` is retained for release checks |
|
|
32
32
|
| `task.seed`, `task.rep` | ledger | seed from `RunRecord.seed`; rep 0 for minted solo runs |
|
|
33
33
|
| `policy.*` | ledger | + `prompt_hash`, `config_hash`, `agent_profile_cell_id` from PR #410's RunRecord provenance |
|
|
34
34
|
| `messages` | ledger | canonical OpenAI chat-with-tools incl. `reasoning_content`; minted lines inline the final llm span's conversation |
|
|
35
35
|
| `steps` | PR #410 | optional trace-span projections (llm/tool), absent on harness-store-derived lines |
|
|
36
|
-
| `outcome.reward` | conflict | **merged**: `number \| null`; `null` means no verdict exists (a labeled gap, never 0);
|
|
37
|
-
| `outcome.realness_gated` | PR #410 |
|
|
38
|
-
| `outcome.reward_source` / `verdict` / `metrics`
|
|
36
|
+
| `outcome.reward` | conflict | **merged**: `number \| null`; `null` means no verdict exists (a labeled gap, never 0); minting requires an explicit RunRecord task score and rejects execution-only records instead of labeling them 0; realness-gated scores are forced to 0 |
|
|
37
|
+
| `outcome.realness_gated` | PR #410 | required boolean; the anti-Goodhart decision travels with the row and every training export refuses gated lines |
|
|
38
|
+
| `outcome.reward_source` / `verdict` / `metrics` | ledger | unchanged; mint fills `metrics` from `RunRecord.outcome.raw` |
|
|
39
|
+
| `outcome.is_completed` / `is_truncated` / `error` | conflict | mint derives terminal fields from the required `RunRecord.terminalOutcome`; producers use the explicit `unknown` value when terminal evidence is unavailable |
|
|
39
40
|
| `cost.*` | ledger | superset of PR #410's costUsd/totalTokens; `cost.usd` is `null` when `costProvenance.kind === 'uncaptured'` (never a fake 0) |
|
|
40
41
|
| `artifacts.*`, `provenance.*` | ledger | `provenance.capture` gains `mint` alongside `settle-time` / `backfill` |
|
|
41
42
|
| gap discipline | ledger | records without trace spans become labeled gap lines (`messages: []`, `provenance.gap`) AND are listed in `missingTraces`; PR #410's silent skip retired |
|
|
42
43
|
|
|
43
44
|
## Export filters (fail-closed)
|
|
44
45
|
|
|
45
|
-
- SFT
|
|
46
|
-
-
|
|
47
|
-
-
|
|
46
|
+
- SFT, reward rows, Verifiers, and RFT default to completed, non-truncated, error-free, ungated `search` runs with reward greater than `0`.
|
|
47
|
+
- `minimumQualityExclusive` can raise the quality floor.
|
|
48
|
+
- Held-out rows require `allowHeldOutTrainingData: true`.
|
|
49
|
+
- SFT also requires a non-empty transcript.
|
|
50
|
+
- Reward rows require a non-empty user prompt.
|
|
51
|
+
- Verifiers requires both prompt and completion turns.
|
|
52
|
+
- RFT requires prompt turns before the first assistant turn.
|
|
48
53
|
- Release (`rollout-release`): trainable split only; proposer lines dropped unless `--include-proposers`; every string value scrubbed by the 9 deterministic rules (idempotent, so a second pass counts zero); `--push` requires `huggingface-cli` + `HF_TOKEN` and never prints the token.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-eval",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.127.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": {
|
|
@@ -172,11 +172,12 @@
|
|
|
172
172
|
"devDependencies": {
|
|
173
173
|
"@biomejs/biome": "^2.5.5",
|
|
174
174
|
"@types/node": "^26.1.1",
|
|
175
|
+
"esbuild": "^0.28.1",
|
|
175
176
|
"husky": "^9.1.7",
|
|
176
177
|
"lint-staged": "^17.2.0",
|
|
177
178
|
"openapi3-ts": "^4.6.0",
|
|
178
179
|
"tsup": "^8.0.0",
|
|
179
|
-
"typescript": "^
|
|
180
|
+
"typescript": "^6.0.3",
|
|
180
181
|
"vitest": "^4.1.10",
|
|
181
182
|
"yaml": "2.9.0"
|
|
182
183
|
},
|
|
@@ -205,5 +206,5 @@
|
|
|
205
206
|
]
|
|
206
207
|
},
|
|
207
208
|
"license": "MIT",
|
|
208
|
-
"packageManager": "pnpm@10.
|
|
209
|
+
"packageManager": "pnpm@10.34.5"
|
|
209
210
|
}
|