jev-layer 0.1.0 → 0.3.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 +73 -34
- package/CONTRIBUTING.md +146 -146
- package/LICENSE +21 -21
- package/README.md +125 -126
- package/README.ru.md +140 -117
- package/README.zh-CN.md +139 -117
- package/RELEASE.md +53 -53
- package/SECURITY.md +64 -56
- package/bin/jev.mjs +215 -213
- package/config/codex.mcp.toml +8 -8
- package/config/generic-mcp.json +13 -13
- package/config/hermes.mcp.yaml +9 -9
- package/config/jev.example.json +23 -22
- package/config/omp.mcp.json +14 -14
- package/config/providers.env.example +13 -13
- package/docs/AGENT-IMPLEMENTATION.md +306 -0
- package/docs/COMPATIBILITY.md +24 -15
- package/docs/HERMES-LOCAL-AGENT-HANDOFF.ru.md +187 -0
- package/docs/PROVIDERS.md +109 -0
- package/docs/SCHEMA-VERSIONING.md +101 -94
- package/docs/architecture.svg +77 -0
- package/docs/jev-layer-banner.svg +38 -0
- package/examples/capabilities.json +39 -39
- package/examples/route-request.json +28 -28
- package/integrations/codex/.codex-plugin/plugin.json +19 -19
- package/integrations/codex/.mcp.json +11 -11
- package/integrations/codex/AGENTS.md +1 -1
- package/integrations/codex/run-mcp.mjs +9 -9
- package/integrations/codex/skills/jev-route/SKILL.md +17 -17
- package/integrations/hermes/__init__.py +156 -51
- package/integrations/hermes/plugin.yaml +11 -5
- package/integrations/hermes/schemas.py +120 -12
- package/integrations/omp/extension.js +106 -105
- package/integrations/template/README.md +10 -10
- package/integrations/template/adapter.mjs +87 -87
- package/package.json +60 -59
- package/scripts/benchmark.mjs +35 -35
- package/scripts/browser-benchmark.mjs +92 -92
- package/scripts/browser-e2e.mjs +117 -117
- package/scripts/capability-e2e.mjs +31 -31
- package/scripts/clean-install-smoke.mjs +176 -162
- package/scripts/codex-mcp-smoke.mjs +119 -119
- package/scripts/context-filter-e2e.mjs +45 -45
- package/scripts/fail-open-smoke.mjs +120 -120
- package/scripts/feature-flags-smoke.mjs +46 -46
- package/scripts/mcp-receipt-smoke.mjs +115 -98
- package/scripts/model-route-report.mjs +15 -0
- package/scripts/openrouter-choice.mjs +59 -59
- package/scripts/replay-eval.mjs +124 -124
- package/scripts/smoke.mjs +34 -34
- package/scripts/supervision-e2e.mjs +138 -109
- package/src/browser.mjs +583 -569
- package/src/cli.mjs +33 -33
- package/src/computer.mjs +196 -0
- package/src/config.mjs +86 -75
- package/src/context-filter.mjs +56 -56
- package/src/contract.mjs +74 -72
- package/src/discovery.mjs +65 -65
- package/src/hermes-adapter.mjs +134 -0
- package/src/images.mjs +98 -0
- package/src/mcp-server.mjs +313 -210
- package/src/model-route-metrics.mjs +89 -0
- package/src/model-routing.mjs +87 -0
- package/src/providers/demo.mjs +52 -52
- package/src/providers/index.mjs +12 -0
- package/src/providers/typesafe.mjs +206 -126
- package/src/receipts.mjs +228 -226
- package/src/registry.mjs +109 -109
- package/src/relevance-filter.mjs +99 -99
- package/src/route.mjs +228 -221
- package/src/shadow-compaction.mjs +170 -0
- package/src/supervision.mjs +268 -244
- package/test/browser.test.mjs +222 -199
- package/test/capability.test.mjs +54 -54
- package/test/computer.test.mjs +195 -0
- package/test/context-filter.test.mjs +65 -65
- package/test/hermes-adapter.test.mjs +63 -0
- package/test/image-fixture.mjs +2 -0
- package/test/images.test.mjs +85 -0
- package/test/model-route-metrics.test.mjs +61 -0
- package/test/model-routing.test.mjs +59 -0
- package/test/openrouter-provider.test.mjs +55 -55
- package/test/provider-transports.test.mjs +205 -0
- package/test/providers.test.mjs +125 -0
- package/test/receipts.test.mjs +71 -71
- package/test/route.test.mjs +86 -74
- package/test/shadow-compaction.test.mjs +67 -0
- package/test/supervision.test.mjs +117 -99
package/src/receipts.mjs
CHANGED
|
@@ -1,226 +1,228 @@
|
|
|
1
|
-
import { appendFile, mkdir, readFile } from "node:fs/promises";
|
|
2
|
-
import { dirname, resolve } from "node:path";
|
|
3
|
-
import { stableJson } from "./contract.mjs";
|
|
4
|
-
import { sanitizeContext } from "./context-filter.mjs";
|
|
5
|
-
|
|
6
|
-
const MAX_RESULT_BYTES = 8_000;
|
|
7
|
-
|
|
8
|
-
export function replayCasePath(filePath = process.env.JEV_REPLAY_CASES) {
|
|
9
|
-
return resolve(filePath || ".jev/replay/cases.jsonl");
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function buildRoutingCase({ request, decision, recordedAt = new Date().toISOString() }) {
|
|
13
|
-
const correlationId = decision.correlation_id ?? decision.receipt?.correlation_id ?? decision.receipt?.request_id;
|
|
14
|
-
if (!correlationId) throw new TypeError("decision correlation_id is required");
|
|
15
|
-
return {
|
|
16
|
-
record_type: "routing_case",
|
|
17
|
-
schema_version: 1,
|
|
18
|
-
case_id: correlationId,
|
|
19
|
-
correlation_id: correlationId,
|
|
20
|
-
recorded_at: recordedAt,
|
|
21
|
-
harness: request.harness ?? "unknown",
|
|
22
|
-
request: replayRequest(request),
|
|
23
|
-
decision: decisionSummary(decision),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function buildExecutionReceipt({ request, decision, host, recordedAt = new Date().toISOString() }) {
|
|
28
|
-
const correlationId = decision.correlation_id ?? decision.receipt?.correlation_id ?? decision.receipt?.request_id;
|
|
29
|
-
if (!correlationId) throw new TypeError("decision correlation_id is required");
|
|
30
|
-
if (!host || typeof host !== "object") throw new TypeError("host execution is required");
|
|
31
|
-
const exitStatus = Number.isInteger(host.exit_status) ? host.exit_status : null;
|
|
32
|
-
const status = typeof host.status === "string"
|
|
33
|
-
? host.status
|
|
34
|
-
: exitStatus === null || exitStatus === 0 ? "completed" : "failed";
|
|
35
|
-
return {
|
|
36
|
-
record_type: "execution_receipt",
|
|
37
|
-
schema_version: 1,
|
|
38
|
-
receipt_id: `${correlationId}:execution`,
|
|
39
|
-
correlation_id: correlationId,
|
|
40
|
-
recorded_at: recordedAt,
|
|
41
|
-
harness: host.harness ?? request.harness ?? "unknown",
|
|
42
|
-
candidates: decision.candidates ?? [],
|
|
43
|
-
selected: decision.selected ?? null,
|
|
44
|
-
confidence: decision.confidence ?? null,
|
|
45
|
-
probabilities: decision.probabilities ?? {},
|
|
46
|
-
fallback: decision.fallback ?? null,
|
|
47
|
-
jev: {
|
|
48
|
-
correlation_id: correlationId,
|
|
49
|
-
request_id: decision.receipt?.request_id ?? correlationId,
|
|
50
|
-
provider: decision.receipt?.provider ?? null,
|
|
51
|
-
latency_ms: decision.receipt?.latency_ms ?? null,
|
|
52
|
-
cost_usd: decision.receipt?.cost_usd ?? decision.raw_jev?.usage?.cost ?? null,
|
|
53
|
-
status: decision.status ?? null,
|
|
54
|
-
},
|
|
55
|
-
host: {
|
|
56
|
-
capability_id: host.capability_id ?? decision.selected ?? null,
|
|
57
|
-
status,
|
|
58
|
-
result: boundedValue(host.result ?? host.host_result ?? null),
|
|
59
|
-
error: boundedValue(host.error ?? null),
|
|
60
|
-
exit_status: exitStatus,
|
|
61
|
-
duration_ms: finiteNumber(host.duration_ms),
|
|
62
|
-
started_at: host.started_at ?? null,
|
|
63
|
-
completed_at: host.completed_at ?? recordedAt,
|
|
64
|
-
browser: boundedValue(host.browser ?? null),
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export async function appendRoutingCase({ path, request, decision }) {
|
|
70
|
-
const record = buildRoutingCase({ request, decision });
|
|
71
|
-
await appendRecord(path, record);
|
|
72
|
-
return { record, path: replayCasePath(path) };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export async function appendExecutionReceipt({ path, request, decision, host }) {
|
|
76
|
-
const record = buildExecutionReceipt({ request, decision, host });
|
|
77
|
-
await appendRecord(path, record);
|
|
78
|
-
return { record, path: replayCasePath(path) };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function buildSupervisionReceipt({ request, result, recordedAt = new Date().toISOString() }) {
|
|
82
|
-
const correlationId = result.receipt?.correlation_id;
|
|
83
|
-
if (!correlationId) throw new TypeError("supervision result correlation_id is required");
|
|
84
|
-
return {
|
|
85
|
-
record_type: "supervision_case",
|
|
86
|
-
schema_version: 1,
|
|
87
|
-
case_id: correlationId,
|
|
88
|
-
correlation_id: correlationId,
|
|
89
|
-
recorded_at: recordedAt,
|
|
90
|
-
harness: request.harness ?? "unknown",
|
|
91
|
-
request: {
|
|
92
|
-
schema_version: request.schema_version ?? 1,
|
|
93
|
-
harness: request.harness ?? "unknown",
|
|
94
|
-
intent: request.intent,
|
|
95
|
-
context: sanitizeContext(request.context ?? {}),
|
|
96
|
-
actor_permissions: request.actor_permissions ?? [],
|
|
97
|
-
policy: request.policy ?? {},
|
|
98
|
-
},
|
|
99
|
-
supervision: {
|
|
100
|
-
status: result.status ?? null,
|
|
101
|
-
action: result.action ?? "continue",
|
|
102
|
-
reason: result.reason ?? null,
|
|
103
|
-
assessment: result.assessment ?? null,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
1
|
+
import { appendFile, mkdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { stableJson } from "./contract.mjs";
|
|
4
|
+
import { sanitizeContext } from "./context-filter.mjs";
|
|
5
|
+
|
|
6
|
+
const MAX_RESULT_BYTES = 8_000;
|
|
7
|
+
|
|
8
|
+
export function replayCasePath(filePath = process.env.JEV_REPLAY_CASES) {
|
|
9
|
+
return resolve(filePath || ".jev/replay/cases.jsonl");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function buildRoutingCase({ request, decision, recordedAt = new Date().toISOString() }) {
|
|
13
|
+
const correlationId = decision.correlation_id ?? decision.receipt?.correlation_id ?? decision.receipt?.request_id;
|
|
14
|
+
if (!correlationId) throw new TypeError("decision correlation_id is required");
|
|
15
|
+
return {
|
|
16
|
+
record_type: "routing_case",
|
|
17
|
+
schema_version: 1,
|
|
18
|
+
case_id: correlationId,
|
|
19
|
+
correlation_id: correlationId,
|
|
20
|
+
recorded_at: recordedAt,
|
|
21
|
+
harness: request.harness ?? "unknown",
|
|
22
|
+
request: replayRequest(request),
|
|
23
|
+
decision: decisionSummary(decision),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function buildExecutionReceipt({ request, decision, host, recordedAt = new Date().toISOString() }) {
|
|
28
|
+
const correlationId = decision.correlation_id ?? decision.receipt?.correlation_id ?? decision.receipt?.request_id;
|
|
29
|
+
if (!correlationId) throw new TypeError("decision correlation_id is required");
|
|
30
|
+
if (!host || typeof host !== "object") throw new TypeError("host execution is required");
|
|
31
|
+
const exitStatus = Number.isInteger(host.exit_status) ? host.exit_status : null;
|
|
32
|
+
const status = typeof host.status === "string"
|
|
33
|
+
? host.status
|
|
34
|
+
: exitStatus === null || exitStatus === 0 ? "completed" : "failed";
|
|
35
|
+
return {
|
|
36
|
+
record_type: "execution_receipt",
|
|
37
|
+
schema_version: 1,
|
|
38
|
+
receipt_id: `${correlationId}:execution`,
|
|
39
|
+
correlation_id: correlationId,
|
|
40
|
+
recorded_at: recordedAt,
|
|
41
|
+
harness: host.harness ?? request.harness ?? "unknown",
|
|
42
|
+
candidates: decision.candidates ?? [],
|
|
43
|
+
selected: decision.selected ?? null,
|
|
44
|
+
confidence: decision.confidence ?? null,
|
|
45
|
+
probabilities: decision.probabilities ?? {},
|
|
46
|
+
fallback: decision.fallback ?? null,
|
|
47
|
+
jev: {
|
|
48
|
+
correlation_id: correlationId,
|
|
49
|
+
request_id: decision.receipt?.request_id ?? correlationId,
|
|
50
|
+
provider: decision.receipt?.provider ?? null,
|
|
51
|
+
latency_ms: decision.receipt?.latency_ms ?? null,
|
|
52
|
+
cost_usd: decision.receipt?.cost_usd ?? decision.raw_jev?.usage?.cost ?? null,
|
|
53
|
+
status: decision.status ?? null,
|
|
54
|
+
},
|
|
55
|
+
host: {
|
|
56
|
+
capability_id: host.capability_id ?? decision.selected ?? null,
|
|
57
|
+
status,
|
|
58
|
+
result: boundedValue(host.result ?? host.host_result ?? null),
|
|
59
|
+
error: boundedValue(host.error ?? null),
|
|
60
|
+
exit_status: exitStatus,
|
|
61
|
+
duration_ms: finiteNumber(host.duration_ms),
|
|
62
|
+
started_at: host.started_at ?? null,
|
|
63
|
+
completed_at: host.completed_at ?? recordedAt,
|
|
64
|
+
browser: boundedValue(host.browser ?? null),
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function appendRoutingCase({ path, request, decision }) {
|
|
70
|
+
const record = buildRoutingCase({ request, decision });
|
|
71
|
+
await appendRecord(path, record);
|
|
72
|
+
return { record, path: replayCasePath(path) };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function appendExecutionReceipt({ path, request, decision, host }) {
|
|
76
|
+
const record = buildExecutionReceipt({ request, decision, host });
|
|
77
|
+
await appendRecord(path, record);
|
|
78
|
+
return { record, path: replayCasePath(path) };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function buildSupervisionReceipt({ request, result, recordedAt = new Date().toISOString() }) {
|
|
82
|
+
const correlationId = result.receipt?.correlation_id;
|
|
83
|
+
if (!correlationId) throw new TypeError("supervision result correlation_id is required");
|
|
84
|
+
return {
|
|
85
|
+
record_type: "supervision_case",
|
|
86
|
+
schema_version: 1,
|
|
87
|
+
case_id: correlationId,
|
|
88
|
+
correlation_id: correlationId,
|
|
89
|
+
recorded_at: recordedAt,
|
|
90
|
+
harness: request.harness ?? "unknown",
|
|
91
|
+
request: {
|
|
92
|
+
schema_version: request.schema_version ?? 1,
|
|
93
|
+
harness: request.harness ?? "unknown",
|
|
94
|
+
intent: request.intent,
|
|
95
|
+
context: sanitizeContext(request.context ?? {}),
|
|
96
|
+
actor_permissions: request.actor_permissions ?? [],
|
|
97
|
+
policy: request.policy ?? {},
|
|
98
|
+
},
|
|
99
|
+
supervision: {
|
|
100
|
+
status: result.status ?? null,
|
|
101
|
+
action: result.action ?? "continue",
|
|
102
|
+
reason: result.reason ?? null,
|
|
103
|
+
assessment: result.assessment ?? null,
|
|
104
|
+
evidence_state: result.evidence_state ?? request.context?.supervision?.evidence_state ?? null,
|
|
105
|
+
policy: result.policy ?? null,
|
|
106
|
+
jev: {
|
|
107
|
+
provider: result.receipt.provider ?? null,
|
|
108
|
+
latency_ms: result.receipt.latency_ms ?? null,
|
|
109
|
+
cost_usd: result.receipt.cost_usd ?? null,
|
|
110
|
+
dimensions: result.receipt.dimensions ?? null,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function appendSupervisionReceipt({ path, request, result }) {
|
|
117
|
+
const record = buildSupervisionReceipt({ request, result });
|
|
118
|
+
await appendRecord(path, record);
|
|
119
|
+
return { record, path: replayCasePath(path) };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function readRoutingCases(path) {
|
|
123
|
+
const resolved = replayCasePath(path);
|
|
124
|
+
let text;
|
|
125
|
+
try {
|
|
126
|
+
text = await readFile(resolved, "utf8");
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (error?.code === "ENOENT") return [];
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
return text.split(/\r?\n/).filter(Boolean).flatMap((line, index) => {
|
|
132
|
+
try {
|
|
133
|
+
const record = JSON.parse(line);
|
|
134
|
+
return record.record_type === "routing_case" ? [{ ...record, source_line: index + 1 }] : [];
|
|
135
|
+
} catch {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function readSupervisionCases(path) {
|
|
142
|
+
const resolved = replayCasePath(path);
|
|
143
|
+
let text;
|
|
144
|
+
try {
|
|
145
|
+
text = await readFile(resolved, "utf8");
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (error?.code === "ENOENT") return [];
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
return text.split(/\r?\n/).filter(Boolean).flatMap((line, index) => {
|
|
151
|
+
try {
|
|
152
|
+
const record = JSON.parse(line);
|
|
153
|
+
return record.record_type === "supervision_case" ? [{ ...record, source_line: index + 1 }] : [];
|
|
154
|
+
} catch {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function replayRequest(request) {
|
|
161
|
+
return {
|
|
162
|
+
schema_version: request.schema_version ?? 1,
|
|
163
|
+
harness: request.harness ?? "unknown",
|
|
164
|
+
intent: request.intent,
|
|
165
|
+
context: sanitizeContext(request.context ?? {}),
|
|
166
|
+
actor: request.actor,
|
|
167
|
+
actor_permissions: Array.isArray(request.actor_permissions) ? request.actor_permissions.filter((value) => typeof value === "string") : undefined,
|
|
168
|
+
policy: request.policy && typeof request.policy === "object" ? request.policy : {},
|
|
169
|
+
capabilities: Array.isArray(request.capabilities) ? request.capabilities.map(replayCapability) : [],
|
|
170
|
+
...(request.assets_omitted || Object.keys(request.assets ?? {}).length ? { assets_omitted: true } : {}),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function replayCapability(capability) {
|
|
175
|
+
const risk = capability.risk?.level ?? capability.risk ?? "medium";
|
|
176
|
+
return {
|
|
177
|
+
id: capability.id,
|
|
178
|
+
kind: capability.kind ?? capability.type ?? "tool",
|
|
179
|
+
name: capability.name,
|
|
180
|
+
description: capability.description,
|
|
181
|
+
permissions: Array.isArray(capability.permissions) ? capability.permissions.filter((value) => typeof value === "string") : [],
|
|
182
|
+
risk,
|
|
183
|
+
available: capability.available,
|
|
184
|
+
availability: capability.availability,
|
|
185
|
+
source: typeof capability.source === "string" ? capability.source : null,
|
|
186
|
+
verified: capability.verified === true,
|
|
187
|
+
metadata: capability.metadata && typeof capability.metadata === "object" ? capability.metadata : {},
|
|
188
|
+
policy: capability.policy,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function decisionSummary(decision) {
|
|
193
|
+
return {
|
|
194
|
+
status: decision.status ?? null,
|
|
195
|
+
selected: decision.selected ?? null,
|
|
196
|
+
confidence: decision.confidence ?? null,
|
|
197
|
+
probabilities: decision.probabilities ?? {},
|
|
198
|
+
fallback: decision.fallback ?? null,
|
|
199
|
+
candidates: decision.candidates ?? [],
|
|
200
|
+
receipt: {
|
|
201
|
+
correlation_id: decision.receipt?.correlation_id ?? decision.correlation_id ?? null,
|
|
202
|
+
request_id: decision.receipt?.request_id ?? null,
|
|
203
|
+
provider: decision.receipt?.provider ?? null,
|
|
204
|
+
latency_ms: decision.receipt?.latency_ms ?? null,
|
|
205
|
+
cost_usd: decision.receipt?.cost_usd ?? decision.raw_jev?.usage?.cost ?? null,
|
|
206
|
+
candidate_count: decision.receipt?.candidate_count ?? null,
|
|
207
|
+
context_bytes: decision.receipt?.context_bytes ?? null,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function appendRecord(path, record) {
|
|
213
|
+
const resolved = replayCasePath(path);
|
|
214
|
+
await mkdir(dirname(resolved), { recursive: true });
|
|
215
|
+
await appendFile(resolved, `${stableJson(record)}\n`, "utf8");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function finiteNumber(value) {
|
|
219
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function boundedValue(value) {
|
|
223
|
+
if (value === null || value === undefined) return null;
|
|
224
|
+
if (typeof value === "string") return value.length > MAX_RESULT_BYTES ? `${value.slice(0, MAX_RESULT_BYTES)}…` : value;
|
|
225
|
+
const sanitized = sanitizeContext(value);
|
|
226
|
+
const encoded = stableJson(sanitized);
|
|
227
|
+
return encoded.length > MAX_RESULT_BYTES ? `${encoded.slice(0, MAX_RESULT_BYTES)}…` : sanitized;
|
|
228
|
+
}
|