@full-self-browsing/lattice 1.4.0 → 1.5.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/dist/agent-run-C6miAzwI.d.ts +45 -0
- package/dist/agent-run-C6miAzwI.d.ts.map +1 -0
- package/dist/agent-run-CgPVFl0Z.js +47 -0
- package/dist/agent-run-CgPVFl0Z.js.map +1 -0
- package/dist/agents.d.ts +5 -0
- package/dist/agents.js +6 -0
- package/dist/artifact-Bg6mJGnm.d.ts +125 -0
- package/dist/artifact-Bg6mJGnm.d.ts.map +1 -0
- package/dist/artifact-DOfpeXLb.js +140 -0
- package/dist/artifact-DOfpeXLb.js.map +1 -0
- package/dist/artifacts.d.ts +2 -0
- package/dist/artifacts.js +2 -0
- package/dist/audit.d.ts +3 -0
- package/dist/audit.js +4 -0
- package/dist/catalog-CAfYwB_-.js +91 -0
- package/dist/catalog-CAfYwB_-.js.map +1 -0
- package/dist/context-pack-Bz3GXmjv.js +99 -0
- package/dist/context-pack-Bz3GXmjv.js.map +1 -0
- package/dist/context.d.ts +2 -0
- package/dist/context.js +2 -0
- package/dist/contract-S3oJGlc9.d.ts +74 -0
- package/dist/contract-S3oJGlc9.d.ts.map +1 -0
- package/dist/core.d.ts +48 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +95 -0
- package/dist/core.js.map +1 -0
- package/dist/errors-eEuEIx6X.js +407 -0
- package/dist/errors-eEuEIx6X.js.map +1 -0
- package/dist/eval.d.ts +2 -0
- package/dist/eval.js +2 -0
- package/dist/fingerprint-DodDbQKN.js +34 -0
- package/dist/fingerprint-DodDbQKN.js.map +1 -0
- package/dist/index-DpnHGHVL.d.ts +53 -0
- package/dist/index-DpnHGHVL.d.ts.map +1 -0
- package/dist/index.d.ts +90 -3533
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -15968
- package/dist/index.js.map +1 -1
- package/dist/infer-DLqp5QIM.d.ts +96 -0
- package/dist/infer-DLqp5QIM.d.ts.map +1 -0
- package/dist/lineage-DBgoPWAZ.js +137 -0
- package/dist/lineage-DBgoPWAZ.js.map +1 -0
- package/dist/local-CXOGPJ1f.js +139 -0
- package/dist/local-CXOGPJ1f.js.map +1 -0
- package/dist/local-Dy--7peL.d.ts +10 -0
- package/dist/local-Dy--7peL.d.ts.map +1 -0
- package/dist/memory-CkQEW6m5.js +62 -0
- package/dist/memory-CkQEW6m5.js.map +1 -0
- package/dist/memory-DRig5EHV.d.ts +10 -0
- package/dist/memory-DRig5EHV.d.ts.map +1 -0
- package/dist/negotiate-ClD88hkc.js +10967 -0
- package/dist/negotiate-ClD88hkc.js.map +1 -0
- package/dist/otel-BgM4e55_.d.ts +421 -0
- package/dist/otel-BgM4e55_.d.ts.map +1 -0
- package/dist/permission-context-CUKMo79F.js +134 -0
- package/dist/permission-context-CUKMo79F.js.map +1 -0
- package/dist/plan-DFm8Llep.js +125 -0
- package/dist/plan-DFm8Llep.js.map +1 -0
- package/dist/preflight-DNHWuJ46.d.ts +64 -0
- package/dist/preflight-DNHWuJ46.d.ts.map +1 -0
- package/dist/provider-C2IfKsvz.d.ts +1178 -0
- package/dist/provider-C2IfKsvz.d.ts.map +1 -0
- package/dist/providers.d.ts +4 -0
- package/dist/providers.js +4 -0
- package/dist/rate-limit-group-nDsBJqSu.d.ts +235 -0
- package/dist/rate-limit-group-nDsBJqSu.d.ts.map +1 -0
- package/dist/receipt-FYouoPHv.js +205 -0
- package/dist/receipt-FYouoPHv.js.map +1 -0
- package/dist/replay-CtIhpLek.js +964 -0
- package/dist/replay-CtIhpLek.js.map +1 -0
- package/dist/result-DLEx2WvU.d.ts +38 -0
- package/dist/result-DLEx2WvU.d.ts.map +1 -0
- package/dist/router-DU4Z3pTd.js +314 -0
- package/dist/router-DU4Z3pTd.js.map +1 -0
- package/dist/router-Yo1-aDOv.d.ts +42 -0
- package/dist/router-Yo1-aDOv.d.ts.map +1 -0
- package/dist/routing.d.ts +6 -0
- package/dist/routing.js +4 -0
- package/dist/{run-crew-CKdBjh5P.js → run-crew-B2fQLmgB.js} +7 -136
- package/dist/run-crew-B2fQLmgB.js.map +1 -0
- package/dist/run-crew-Bnve5dyI.d.ts +721 -0
- package/dist/run-crew-Bnve5dyI.d.ts.map +1 -0
- package/dist/{runtime-D25ehzCj.js → runtime-Dxiet5YS.js} +98 -641
- package/dist/runtime-Dxiet5YS.js.map +1 -0
- package/dist/scaffolds-DKQrCRqh.d.ts +535 -0
- package/dist/scaffolds-DKQrCRqh.d.ts.map +1 -0
- package/dist/scaffolds-ekPIlBeU.js +3139 -0
- package/dist/scaffolds-ekPIlBeU.js.map +1 -0
- package/dist/schema-CNfa_VEy.d.ts +15 -0
- package/dist/schema-CNfa_VEy.d.ts.map +1 -0
- package/dist/storage-DJKmsaEI.d.ts +26 -0
- package/dist/storage-DJKmsaEI.d.ts.map +1 -0
- package/dist/storage.d.ts +10 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +4 -0
- package/dist/tool-call-validation-BFoXkwbf.js +107 -0
- package/dist/tool-call-validation-BFoXkwbf.js.map +1 -0
- package/dist/tools-C4wHgGKQ.js +49 -0
- package/dist/tools-C4wHgGKQ.js.map +1 -0
- package/dist/tools.d.ts +46 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +106 -0
- package/dist/tools.js.map +1 -0
- package/dist/validate-c7EL5uuH.js +224 -0
- package/dist/validate-c7EL5uuH.js.map +1 -0
- package/package.json +99 -2
- package/dist/run-crew-CKdBjh5P.js.map +0 -1
- package/dist/runtime-D25ehzCj.js.map +0 -1
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
//#region src/contract/contract.ts
|
|
2
|
+
/**
|
|
3
|
+
* Factory for `CapabilityContract` values.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the `output()` and adapter factory style — exact-optional safe
|
|
6
|
+
* (does not emit `field: undefined` properties under `exactOptionalPropertyTypes`).
|
|
7
|
+
* Returns a frozen value with frozen nested objects so downstream code can
|
|
8
|
+
* rely on structural immutability when canonicalizing in Phase 9.
|
|
9
|
+
*/
|
|
10
|
+
function contract(input = {}) {
|
|
11
|
+
return Object.freeze({
|
|
12
|
+
kind: "capability-contract",
|
|
13
|
+
...input.budget !== void 0 ? { budget: Object.freeze({ ...input.budget }) } : {},
|
|
14
|
+
...input.invariants !== void 0 ? { invariants: Object.freeze(input.invariants.map((inv) => Object.freeze({ ...inv }))) } : {},
|
|
15
|
+
...input.qualityFloor !== void 0 ? { qualityFloor: Object.freeze({ ...input.qualityFloor }) } : {},
|
|
16
|
+
...input.requiredModalities !== void 0 ? { requiredModalities: Object.freeze([...input.requiredModalities]) } : {},
|
|
17
|
+
...input.requiredPrivacy !== void 0 ? { requiredPrivacy: input.requiredPrivacy } : {}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/contract/invariants.ts
|
|
22
|
+
let counter = 0;
|
|
23
|
+
function nextId(kind, options) {
|
|
24
|
+
counter += 1;
|
|
25
|
+
return options?.id ?? `${kind}-${counter}`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Fluent builder for tripwire invariants.
|
|
29
|
+
*
|
|
30
|
+
* Each helper returns a frozen `InvariantDeclaration` with an auto-generated
|
|
31
|
+
* id of the form `${kind}-${counter}`. Callers may override the id via the
|
|
32
|
+
* second-positional `options.id` arg.
|
|
33
|
+
*
|
|
34
|
+
* The counter is monotonic across kinds — calling `inv.mustCite("a")` then
|
|
35
|
+
* `inv.fieldFromTable("x", ["y"])` yields ids `must-cite-1` then
|
|
36
|
+
* `field-from-table-2`. This keeps ids globally unique within a process.
|
|
37
|
+
*
|
|
38
|
+
* Note on `inv.matches`: the caller supplies the StandardSchema validator,
|
|
39
|
+
* and the tripwire evaluator trusts whatever `~standard.validate` returns.
|
|
40
|
+
* This is by design — `matches` is the caller-driven escape hatch (see
|
|
41
|
+
* T-08-05 in the 08-01-PLAN threat register).
|
|
42
|
+
*/
|
|
43
|
+
const inv = {
|
|
44
|
+
mustCite(artifactName, options) {
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
id: nextId("must-cite", options),
|
|
47
|
+
kind: "must-cite",
|
|
48
|
+
artifactName
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
fieldFromTable(path, allowedValues, options) {
|
|
52
|
+
return Object.freeze({
|
|
53
|
+
id: nextId("field-from-table", options),
|
|
54
|
+
kind: "field-from-table",
|
|
55
|
+
path,
|
|
56
|
+
allowedValues: Object.freeze([...allowedValues])
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
noPII(path, options) {
|
|
60
|
+
return Object.freeze({
|
|
61
|
+
id: nextId("no-pii", options),
|
|
62
|
+
kind: "no-pii",
|
|
63
|
+
path
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
matches(path, schema, options) {
|
|
67
|
+
return Object.freeze({
|
|
68
|
+
id: nextId("matches", options),
|
|
69
|
+
kind: "matches",
|
|
70
|
+
path,
|
|
71
|
+
schema
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
__resetCounterForTests() {
|
|
75
|
+
counter = 0;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/contract/pii-detectors.ts
|
|
80
|
+
/**
|
|
81
|
+
* Luhn check digit validator.
|
|
82
|
+
*
|
|
83
|
+
* Strips non-digit characters from `digits`, requires the resulting length
|
|
84
|
+
* to be 13-19 (ISO/IEC 7812 PAN range), then walks right-to-left doubling
|
|
85
|
+
* every second digit and summing. Returns true when the sum is a multiple
|
|
86
|
+
* of 10.
|
|
87
|
+
*/
|
|
88
|
+
function luhn(digits) {
|
|
89
|
+
const cleaned = digits.replace(/\D/g, "");
|
|
90
|
+
if (cleaned.length < 13 || cleaned.length > 19) return false;
|
|
91
|
+
let sum = 0;
|
|
92
|
+
let shouldDouble = false;
|
|
93
|
+
for (let i = cleaned.length - 1; i >= 0; i -= 1) {
|
|
94
|
+
const code = cleaned.charCodeAt(i);
|
|
95
|
+
if (code < 48 || code > 57) return false;
|
|
96
|
+
let digit = code - 48;
|
|
97
|
+
if (shouldDouble) {
|
|
98
|
+
digit *= 2;
|
|
99
|
+
if (digit > 9) digit -= 9;
|
|
100
|
+
}
|
|
101
|
+
sum += digit;
|
|
102
|
+
shouldDouble = !shouldDouble;
|
|
103
|
+
}
|
|
104
|
+
return sum % 10 === 0;
|
|
105
|
+
}
|
|
106
|
+
function execFirst(regex, input) {
|
|
107
|
+
const match = regex.exec(input);
|
|
108
|
+
return match ? match[0] : void 0;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Default PII detectors used by `evaluateTripwires` for `no-pii` invariants.
|
|
112
|
+
*
|
|
113
|
+
* Order is deterministic: email, us-ssn, credit-card, us-phone. Callers who
|
|
114
|
+
* need a different set can pass their own list to `evaluateTripwires`.
|
|
115
|
+
*/
|
|
116
|
+
const defaultPiiDetectors = Object.freeze([
|
|
117
|
+
{
|
|
118
|
+
name: "email",
|
|
119
|
+
detect(input) {
|
|
120
|
+
const substring = execFirst(/[\w.+-]+@[\w-]+\.[\w.-]+/, input);
|
|
121
|
+
return substring !== void 0 ? {
|
|
122
|
+
matched: true,
|
|
123
|
+
substring
|
|
124
|
+
} : { matched: false };
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "us-ssn",
|
|
129
|
+
detect(input) {
|
|
130
|
+
const substring = execFirst(/\b\d{3}-\d{2}-\d{4}\b/, input);
|
|
131
|
+
return substring !== void 0 ? {
|
|
132
|
+
matched: true,
|
|
133
|
+
substring
|
|
134
|
+
} : { matched: false };
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "credit-card",
|
|
139
|
+
detect(input) {
|
|
140
|
+
const candidate = execFirst(/\b(?:\d[ -]?){13,19}\b/, input);
|
|
141
|
+
if (candidate === void 0) return { matched: false };
|
|
142
|
+
const trimmed = candidate.replace(/[ -]+$/, "");
|
|
143
|
+
if (!luhn(trimmed)) return { matched: false };
|
|
144
|
+
return {
|
|
145
|
+
matched: true,
|
|
146
|
+
substring: trimmed
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: "us-phone",
|
|
152
|
+
detect(input) {
|
|
153
|
+
const substring = execFirst(/\b\d{3}-\d{3}-\d{4}\b|\(\d{3}\)\s?\d{3}-\d{4}/, input);
|
|
154
|
+
return substring !== void 0 ? {
|
|
155
|
+
matched: true,
|
|
156
|
+
substring
|
|
157
|
+
} : { matched: false };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
]);
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/contract/tripwire.ts
|
|
163
|
+
/**
|
|
164
|
+
* Pure tripwire evaluator.
|
|
165
|
+
*
|
|
166
|
+
* No I/O, no Date.now, no random — same `(output, invariants)` always
|
|
167
|
+
* returns the same `TripwireResult`. Phase 9 receipts can reconstruct the
|
|
168
|
+
* verdict deterministically (T-08-04).
|
|
169
|
+
*
|
|
170
|
+
* Evaluates invariants in declaration order; the FIRST failing invariant
|
|
171
|
+
* aborts and returns its evidence. Subsequent invariants are not evaluated.
|
|
172
|
+
*
|
|
173
|
+
* @param output The provider output to inspect.
|
|
174
|
+
* @param invariants Invariants to evaluate, in declaration order.
|
|
175
|
+
* @param detectors PII detectors used for `no-pii` invariants. Defaults
|
|
176
|
+
* to `defaultPiiDetectors`. Callers can pass a custom
|
|
177
|
+
* list to override.
|
|
178
|
+
*/
|
|
179
|
+
async function evaluateTripwires(output, invariants, detectors = defaultPiiDetectors) {
|
|
180
|
+
for (const declaration of invariants) {
|
|
181
|
+
const result = await evaluateOne(output, declaration, detectors);
|
|
182
|
+
if (!result.ok) return result;
|
|
183
|
+
}
|
|
184
|
+
return { ok: true };
|
|
185
|
+
}
|
|
186
|
+
async function evaluateOne(output, declaration, detectors) {
|
|
187
|
+
switch (declaration.kind) {
|
|
188
|
+
case "must-cite": return evaluateMustCite(output, declaration);
|
|
189
|
+
case "field-from-table": return evaluateFieldFromTable(output, declaration);
|
|
190
|
+
case "no-pii": return evaluateNoPii(output, declaration, detectors);
|
|
191
|
+
case "matches": return evaluateMatches(output, declaration);
|
|
192
|
+
default: throw new Error(`Unknown invariant kind: ${JSON.stringify(declaration)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function evaluateMustCite(output, decl) {
|
|
196
|
+
const located = locateCitations(output);
|
|
197
|
+
const cites = located?.value ?? [];
|
|
198
|
+
const path = located?.path ?? "citations";
|
|
199
|
+
if (cites.some((entry) => {
|
|
200
|
+
if (typeof entry === "string") return entry === decl.artifactName;
|
|
201
|
+
if (typeof entry === "object" && entry !== null && "source" in entry) return entry.source === decl.artifactName;
|
|
202
|
+
return false;
|
|
203
|
+
})) return { ok: true };
|
|
204
|
+
return {
|
|
205
|
+
ok: false,
|
|
206
|
+
evidence: {
|
|
207
|
+
invariantId: decl.id,
|
|
208
|
+
kind: "must-cite",
|
|
209
|
+
path,
|
|
210
|
+
observed: cites,
|
|
211
|
+
message: `must-cite: no citation found for "${decl.artifactName}".`
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Locate the citations payload in `output`. Searches top-level for a
|
|
217
|
+
* `citations` or `evidence` key holding an array. Per 08-CONTEXT.md:
|
|
218
|
+
* "Path defaults to evidence if the output has a citations field; the
|
|
219
|
+
* runtime locates the citations payload in the output."
|
|
220
|
+
*
|
|
221
|
+
* Returns `undefined` when neither field is an array.
|
|
222
|
+
*/
|
|
223
|
+
function locateCitations(output) {
|
|
224
|
+
if (typeof output !== "object" || output === null) return void 0;
|
|
225
|
+
const record = output;
|
|
226
|
+
for (const key of ["citations", "evidence"]) {
|
|
227
|
+
const value = record[key];
|
|
228
|
+
if (Array.isArray(value)) return {
|
|
229
|
+
value,
|
|
230
|
+
path: key
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function evaluateFieldFromTable(output, decl) {
|
|
235
|
+
const value = resolvePath(output, decl.path);
|
|
236
|
+
if (typeof value === "string" && decl.allowedValues.includes(value)) return { ok: true };
|
|
237
|
+
return {
|
|
238
|
+
ok: false,
|
|
239
|
+
evidence: {
|
|
240
|
+
invariantId: decl.id,
|
|
241
|
+
kind: "field-from-table",
|
|
242
|
+
path: decl.path,
|
|
243
|
+
observed: value,
|
|
244
|
+
message: `field-from-table: value at "${decl.path}" not in allowedValues.`
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function evaluateNoPii(output, decl, detectors) {
|
|
249
|
+
const value = resolvePath(output, decl.path);
|
|
250
|
+
if (typeof value !== "string") return { ok: true };
|
|
251
|
+
for (const detector of detectors) {
|
|
252
|
+
const result = detector.detect(value);
|
|
253
|
+
if (result.matched) return {
|
|
254
|
+
ok: false,
|
|
255
|
+
evidence: {
|
|
256
|
+
invariantId: decl.id,
|
|
257
|
+
kind: "no-pii",
|
|
258
|
+
path: decl.path,
|
|
259
|
+
observed: {
|
|
260
|
+
detector: detector.name,
|
|
261
|
+
substring: result.substring
|
|
262
|
+
},
|
|
263
|
+
message: `no-pii: detector "${detector.name}" flagged content at "${decl.path}".`
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return { ok: true };
|
|
268
|
+
}
|
|
269
|
+
async function evaluateMatches(output, decl) {
|
|
270
|
+
const value = resolvePath(output, decl.path);
|
|
271
|
+
const validateResult = decl.schema["~standard"].validate(value);
|
|
272
|
+
const validation = validateResult instanceof Promise ? await validateResult : validateResult;
|
|
273
|
+
if ("issues" in validation && validation.issues !== void 0) {
|
|
274
|
+
const firstIssue = validation.issues[0];
|
|
275
|
+
return {
|
|
276
|
+
ok: false,
|
|
277
|
+
evidence: {
|
|
278
|
+
invariantId: decl.id,
|
|
279
|
+
kind: "matches",
|
|
280
|
+
path: decl.path,
|
|
281
|
+
observed: value,
|
|
282
|
+
message: firstIssue?.message ?? `matches: schema validation failed at "${decl.path}".`
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return { ok: true };
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Resolve a dotted/bracketed path expression against a value.
|
|
290
|
+
*
|
|
291
|
+
* Supports three segment forms:
|
|
292
|
+
* - dotted key: `a.b.c`
|
|
293
|
+
* - bracket index: `a[0].b`
|
|
294
|
+
* - wildcard: `a[*].b` (materializes the array of resolutions)
|
|
295
|
+
*
|
|
296
|
+
* Returns `undefined` for missing paths (does not throw).
|
|
297
|
+
*
|
|
298
|
+
* NOTE (T-08-03): `[*]` materializes the array; deeply nested wildcard
|
|
299
|
+
* chains could allocate O(N^k). Accepted for v1.1 — provider responses
|
|
300
|
+
* are bounded by output token caps.
|
|
301
|
+
*/
|
|
302
|
+
function resolvePath(value, path) {
|
|
303
|
+
if (path === "") return value;
|
|
304
|
+
return walk(value, tokenize(path), 0);
|
|
305
|
+
}
|
|
306
|
+
function tokenize(path) {
|
|
307
|
+
const tokens = [];
|
|
308
|
+
let i = 0;
|
|
309
|
+
let buffer = "";
|
|
310
|
+
const flushKey = () => {
|
|
311
|
+
if (buffer.length > 0) {
|
|
312
|
+
tokens.push({
|
|
313
|
+
type: "key",
|
|
314
|
+
name: buffer
|
|
315
|
+
});
|
|
316
|
+
buffer = "";
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
while (i < path.length) {
|
|
320
|
+
const ch = path[i];
|
|
321
|
+
if (ch === ".") {
|
|
322
|
+
flushKey();
|
|
323
|
+
i += 1;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
if (ch === "[") {
|
|
327
|
+
flushKey();
|
|
328
|
+
const end = path.indexOf("]", i + 1);
|
|
329
|
+
if (end === -1) {
|
|
330
|
+
buffer = path.slice(i);
|
|
331
|
+
i = path.length;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
const inner = path.slice(i + 1, end);
|
|
335
|
+
if (inner === "*") tokens.push({ type: "wildcard" });
|
|
336
|
+
else {
|
|
337
|
+
const idx = Number(inner);
|
|
338
|
+
if (Number.isInteger(idx) && idx >= 0) tokens.push({
|
|
339
|
+
type: "index",
|
|
340
|
+
index: idx
|
|
341
|
+
});
|
|
342
|
+
else tokens.push({
|
|
343
|
+
type: "key",
|
|
344
|
+
name: inner
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
i = end + 1;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
buffer += ch;
|
|
351
|
+
i += 1;
|
|
352
|
+
}
|
|
353
|
+
flushKey();
|
|
354
|
+
return tokens;
|
|
355
|
+
}
|
|
356
|
+
function walk(value, tokens, cursor) {
|
|
357
|
+
if (cursor >= tokens.length) return value;
|
|
358
|
+
if (value === void 0 || value === null) return void 0;
|
|
359
|
+
const token = tokens[cursor];
|
|
360
|
+
if (token.type === "key") {
|
|
361
|
+
if (typeof value !== "object") return void 0;
|
|
362
|
+
const next = value[token.name];
|
|
363
|
+
return walk(next, tokens, cursor + 1);
|
|
364
|
+
}
|
|
365
|
+
if (token.type === "index") {
|
|
366
|
+
if (!Array.isArray(value)) return void 0;
|
|
367
|
+
return walk(value[token.index], tokens, cursor + 1);
|
|
368
|
+
}
|
|
369
|
+
if (!Array.isArray(value)) return void 0;
|
|
370
|
+
return value.map((entry) => walk(entry, tokens, cursor + 1));
|
|
371
|
+
}
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/outputs/contracts.ts
|
|
374
|
+
const output = {
|
|
375
|
+
citations() {
|
|
376
|
+
return { kind: "citations" };
|
|
377
|
+
},
|
|
378
|
+
artifacts(options = {}) {
|
|
379
|
+
return {
|
|
380
|
+
kind: "artifacts",
|
|
381
|
+
...options
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
//#endregion
|
|
386
|
+
//#region src/results/errors.ts
|
|
387
|
+
/**
|
|
388
|
+
* Returns `true` for run errors that MUST NOT be retried by the fallback
|
|
389
|
+
* chain. Phase 8 covers two kinds:
|
|
390
|
+
*
|
|
391
|
+
* - `tripwire-violated` — the contract's invariants rejected the output;
|
|
392
|
+
* a different provider will not change the verdict, so retry burns
|
|
393
|
+
* budget for no gain (T-08-06 in 08-02-PLAN threat register).
|
|
394
|
+
* - `no-contract-match` — no route satisfies the contract at all; the
|
|
395
|
+
* run never executed and no retry will help.
|
|
396
|
+
*
|
|
397
|
+
* All other error kinds return `false` and remain eligible for fallback.
|
|
398
|
+
* The predicate is exported so Phase 12's eval gate and any user-side
|
|
399
|
+
* retry wrappers can share one source of truth.
|
|
400
|
+
*/
|
|
401
|
+
function isTerminal(error) {
|
|
402
|
+
return error.kind === "tripwire-violated" || error.kind === "no-contract-match";
|
|
403
|
+
}
|
|
404
|
+
//#endregion
|
|
405
|
+
export { inv as a, defaultPiiDetectors as i, output as n, contract as o, evaluateTripwires as r, isTerminal as t };
|
|
406
|
+
|
|
407
|
+
//# sourceMappingURL=errors-eEuEIx6X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-eEuEIx6X.js","names":[],"sources":["../src/contract/contract.ts","../src/contract/invariants.ts","../src/contract/pii-detectors.ts","../src/contract/tripwire.ts","../src/outputs/contracts.ts","../src/results/errors.ts"],"sourcesContent":["import type { CapabilityModality } from \"../providers/provider.js\";\n\nexport type {\n FieldFromTableInvariant,\n InvariantDeclaration,\n MatchesInvariant,\n MustCiteInvariant,\n NoPiiInvariant,\n} from \"./invariants.js\";\n\n// Local alias so the union can be referenced in this module without\n// re-importing through the public re-export above.\nimport type { InvariantDeclaration as InvariantDeclarationUnion } from \"./invariants.js\";\n\n/**\n * Budget invariant declaration attached to a CapabilityContract.\n *\n * Phase 7 implements `maxCostUsd` enforcement at pre-flight. The\n * `p95LatencyMs` field is declared per CONTRACT-02 but is informational\n * only in Phase 7 — latency observations are wired in a later phase.\n *\n * Phase 19 (v1.2) adds `maxIterations` and `maxWallTimeMs` for the agent\n * runtime. Both are additive and optional; non-agent callers ignore them.\n * `maxIterations` caps the number of `runAgent` iterations; `maxWallTimeMs`\n * caps wall-clock duration per `runAgent` invocation. Both are enforced\n * pre-iteration in the agent loop.\n */\nexport interface BudgetInvariant {\n readonly maxCostUsd?: number;\n readonly maxIterations?: number;\n readonly maxWallTimeMs?: number;\n readonly p95LatencyMs?: number;\n}\n\n/**\n * Quality-floor invariant.\n *\n * `suite` is a fixture-directory path string; `minScore` is in 0..1.\n * Phase 7 forwards this into the pre-flight evaluator but only enforces\n * capability-side rejects. Full enforcement lives in Phase 12 (`lattice eval`).\n */\nexport interface QualityFloorInvariant {\n readonly suite: string;\n readonly minScore: number;\n}\n\n/**\n * The full Capability Contract attached to `RunIntent.contract`.\n *\n * All fields are optional. v1.0 callers compile and run unchanged when\n * the field is omitted entirely. PROJECT.md explicitly rejects mandatory\n * contracts.\n */\nexport interface CapabilityContract {\n readonly kind: \"capability-contract\";\n readonly budget?: BudgetInvariant;\n readonly invariants?: readonly InvariantDeclarationUnion[];\n readonly qualityFloor?: QualityFloorInvariant;\n readonly requiredModalities?: readonly CapabilityModality[];\n readonly requiredPrivacy?: \"standard\" | \"sensitive\" | \"restricted\";\n}\n\n/**\n * Reject-reason taxonomy added to `RouteRejectReason.code` by Phase 7's\n * pre-flight evaluator. Closed four-value union per the locked decisions\n * in 07-CONTEXT.md.\n */\nexport type ContractRejectReasonCode =\n | \"contract-budget-exceeded\"\n | \"contract-quality-floor\"\n | \"contract-modality-missing\"\n | \"contract-privacy-mismatch\";\n\n/** Input shape accepted by `contract()`. Mirrors `CapabilityContract` minus `kind`. */\nexport interface CapabilityContractInput {\n readonly budget?: BudgetInvariant;\n readonly invariants?: readonly InvariantDeclarationUnion[];\n readonly qualityFloor?: QualityFloorInvariant;\n readonly requiredModalities?: readonly CapabilityModality[];\n readonly requiredPrivacy?: \"standard\" | \"sensitive\" | \"restricted\";\n}\n\n/**\n * Factory for `CapabilityContract` values.\n *\n * Mirrors the `output()` and adapter factory style — exact-optional safe\n * (does not emit `field: undefined` properties under `exactOptionalPropertyTypes`).\n * Returns a frozen value with frozen nested objects so downstream code can\n * rely on structural immutability when canonicalizing in Phase 9.\n */\nexport function contract(input: CapabilityContractInput = {}): CapabilityContract {\n return Object.freeze({\n kind: \"capability-contract\" as const,\n ...(input.budget !== undefined ? { budget: Object.freeze({ ...input.budget }) } : {}),\n ...(input.invariants !== undefined\n ? { invariants: Object.freeze(input.invariants.map((inv) => Object.freeze({ ...inv }))) }\n : {}),\n ...(input.qualityFloor !== undefined\n ? { qualityFloor: Object.freeze({ ...input.qualityFloor }) }\n : {}),\n ...(input.requiredModalities !== undefined\n ? { requiredModalities: Object.freeze([...input.requiredModalities]) }\n : {}),\n ...(input.requiredPrivacy !== undefined ? { requiredPrivacy: input.requiredPrivacy } : {}),\n });\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Tripwire invariant declaration variants produced by the `inv` fluent\n * builder. Each variant is a frozen value carrying a discriminant `kind`\n * and an `id` (auto-generated or caller-supplied).\n *\n * Phase 8 reshapes the Phase 7 placeholder `{ kind: \"policy\"|\"semantic\"|\"schema\" }`\n * into this discriminated union. Phase 7 never populated `invariants`\n * (see 07-04-SUMMARY decisions), so the change is additive in practice\n * but technically a breaking type change for any external caller that\n * authored a literal of the old shape.\n */\n\nexport interface MustCiteInvariant {\n readonly id: string;\n readonly kind: \"must-cite\";\n readonly artifactName: string;\n}\n\nexport interface FieldFromTableInvariant {\n readonly id: string;\n readonly kind: \"field-from-table\";\n readonly path: string;\n readonly allowedValues: readonly string[];\n}\n\nexport interface NoPiiInvariant {\n readonly id: string;\n readonly kind: \"no-pii\";\n readonly path: string;\n}\n\nexport interface MatchesInvariant<T = unknown> {\n readonly id: string;\n readonly kind: \"matches\";\n readonly path: string;\n readonly schema: StandardSchemaV1<unknown, T>;\n}\n\nexport type InvariantDeclaration =\n | MustCiteInvariant\n | FieldFromTableInvariant\n | NoPiiInvariant\n | MatchesInvariant;\n\nexport interface InvariantOptions {\n readonly id?: string;\n}\n\nlet counter = 0;\n\nfunction nextId(kind: string, options?: InvariantOptions): string {\n counter += 1;\n return options?.id ?? `${kind}-${counter}`;\n}\n\n/**\n * Fluent builder for tripwire invariants.\n *\n * Each helper returns a frozen `InvariantDeclaration` with an auto-generated\n * id of the form `${kind}-${counter}`. Callers may override the id via the\n * second-positional `options.id` arg.\n *\n * The counter is monotonic across kinds — calling `inv.mustCite(\"a\")` then\n * `inv.fieldFromTable(\"x\", [\"y\"])` yields ids `must-cite-1` then\n * `field-from-table-2`. This keeps ids globally unique within a process.\n *\n * Note on `inv.matches`: the caller supplies the StandardSchema validator,\n * and the tripwire evaluator trusts whatever `~standard.validate` returns.\n * This is by design — `matches` is the caller-driven escape hatch (see\n * T-08-05 in the 08-01-PLAN threat register).\n */\nexport const inv = {\n mustCite(artifactName: string, options?: InvariantOptions): MustCiteInvariant {\n return Object.freeze({\n id: nextId(\"must-cite\", options),\n kind: \"must-cite\" as const,\n artifactName,\n });\n },\n fieldFromTable(\n path: string,\n allowedValues: readonly string[],\n options?: InvariantOptions,\n ): FieldFromTableInvariant {\n return Object.freeze({\n id: nextId(\"field-from-table\", options),\n kind: \"field-from-table\" as const,\n path,\n allowedValues: Object.freeze([...allowedValues]),\n });\n },\n noPII(path: string, options?: InvariantOptions): NoPiiInvariant {\n return Object.freeze({\n id: nextId(\"no-pii\", options),\n kind: \"no-pii\" as const,\n path,\n });\n },\n matches<T>(\n path: string,\n schema: StandardSchemaV1<unknown, T>,\n options?: InvariantOptions,\n ): MatchesInvariant<T> {\n return Object.freeze({\n id: nextId(\"matches\", options),\n kind: \"matches\" as const,\n path,\n schema,\n });\n },\n /**\n * Test-only: reset the auto-id counter. NOT exported from the package\n * root barrel — callers must import `inv` directly from this module if\n * they ever need it, which is intentional friction.\n */\n __resetCounterForTests(): void {\n counter = 0;\n },\n} as const;\n","/**\n * Regex-based PII detectors used by the `no-pii` tripwire invariant.\n *\n * Phase 8 ships four detectors (email, US SSN, Luhn-valid credit card,\n * US phone). They are intentionally regex-only — zero new dependencies —\n * per the v1.1 scope locked in 08-CONTEXT.md.\n *\n * Each detector returns either `{ matched: true, substring }` carrying\n * ONLY the matched fragment, or `{ matched: false }`. The substring shape\n * is required so the tripwire evaluator can emit redacted evidence\n * (Phase 9 receipts must not leak the full input).\n *\n * Detector order in `defaultPiiDetectors` is deterministic so the\n * evaluator's first-violation semantics produce stable receipts.\n */\n\nexport type PiiDetectorResult =\n | { readonly matched: true; readonly substring: string }\n | { readonly matched: false };\n\nexport interface PiiDetector {\n readonly name: string;\n detect(input: string): PiiDetectorResult;\n}\n\n/**\n * Luhn check digit validator.\n *\n * Strips non-digit characters from `digits`, requires the resulting length\n * to be 13-19 (ISO/IEC 7812 PAN range), then walks right-to-left doubling\n * every second digit and summing. Returns true when the sum is a multiple\n * of 10.\n */\nfunction luhn(digits: string): boolean {\n const cleaned = digits.replace(/\\D/g, \"\");\n if (cleaned.length < 13 || cleaned.length > 19) return false;\n\n let sum = 0;\n let shouldDouble = false;\n for (let i = cleaned.length - 1; i >= 0; i -= 1) {\n const code = cleaned.charCodeAt(i);\n // Defensive: charAt cannot produce non-digits here because of the\n // `replace(/\\D/g, \"\")` above, but keep a guard for clarity.\n if (code < 48 || code > 57) return false;\n let digit = code - 48;\n if (shouldDouble) {\n digit *= 2;\n if (digit > 9) digit -= 9;\n }\n sum += digit;\n shouldDouble = !shouldDouble;\n }\n return sum % 10 === 0;\n}\n\nfunction execFirst(regex: RegExp, input: string): string | undefined {\n // Always create a fresh exec; we do not rely on regex statefulness.\n const match = regex.exec(input);\n return match ? match[0] : undefined;\n}\n\nconst emailDetector: PiiDetector = {\n name: \"email\",\n detect(input: string): PiiDetectorResult {\n // Local + domain + TLD. Requires at least one non-empty label on each\n // side and a dot in the domain part. Rejects `@bad`, `bad@`, `not-an-email`.\n const substring = execFirst(/[\\w.+-]+@[\\w-]+\\.[\\w.-]+/, input);\n return substring !== undefined ? { matched: true, substring } : { matched: false };\n },\n};\n\nconst ssnDetector: PiiDetector = {\n name: \"us-ssn\",\n detect(input: string): PiiDetectorResult {\n // 3-2-4 grouped SSN with word boundaries on both sides to avoid\n // collapsing into longer adjacent digit runs (e.g., phone numbers).\n const substring = execFirst(/\\b\\d{3}-\\d{2}-\\d{4}\\b/, input);\n return substring !== undefined ? { matched: true, substring } : { matched: false };\n },\n};\n\nconst creditCardDetector: PiiDetector = {\n name: \"credit-card\",\n detect(input: string): PiiDetectorResult {\n // Match any 13-19 character sequence of digits with optional single\n // space or dash separators, then validate with Luhn. The regex is\n // intentionally permissive on separators (banks/forms vary); Luhn\n // filters trivially-formatted strings per Pitfall #5 in CONTEXT.md.\n const candidate = execFirst(/\\b(?:\\d[ -]?){13,19}\\b/, input);\n if (candidate === undefined) return { matched: false };\n // Strip trailing space/dash that the regex may have absorbed.\n const trimmed = candidate.replace(/[ -]+$/, \"\");\n if (!luhn(trimmed)) return { matched: false };\n return { matched: true, substring: trimmed };\n },\n};\n\nconst phoneDetector: PiiDetector = {\n name: \"us-phone\",\n detect(input: string): PiiDetectorResult {\n // Dashed form first, then parenthesized form. Combined alternation so\n // the regex engine picks whichever fires first in input order.\n const substring = execFirst(/\\b\\d{3}-\\d{3}-\\d{4}\\b|\\(\\d{3}\\)\\s?\\d{3}-\\d{4}/, input);\n return substring !== undefined ? { matched: true, substring } : { matched: false };\n },\n};\n\n/**\n * Default PII detectors used by `evaluateTripwires` for `no-pii` invariants.\n *\n * Order is deterministic: email, us-ssn, credit-card, us-phone. Callers who\n * need a different set can pass their own list to `evaluateTripwires`.\n */\nexport const defaultPiiDetectors: readonly PiiDetector[] = Object.freeze([\n emailDetector,\n ssnDetector,\n creditCardDetector,\n phoneDetector,\n]);\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nimport type {\n FieldFromTableInvariant,\n InvariantDeclaration,\n MatchesInvariant,\n MustCiteInvariant,\n NoPiiInvariant,\n} from \"./invariants.js\";\nimport { defaultPiiDetectors, type PiiDetector } from \"./pii-detectors.js\";\n\n/**\n * Evidence emitted when a tripwire invariant fires.\n *\n * `observed` is the SHAPE-MATCHED redacted payload, not the raw output:\n * - for `must-cite`: the citations array as found at the located path\n * - for `field-from-table`: the actual value at `path`\n * - for `no-pii`: ONLY `{ detector, substring }` — never the full input\n * (T-08-01 in the 08-01-PLAN threat register)\n * - for `matches`: the value at `path`\n *\n * Phase 9 receipts will sign this evidence, so leaking the full PII into\n * `observed` would defeat redact-before-sign.\n */\nexport interface TripwireEvidence {\n readonly invariantId: string;\n readonly kind: \"must-cite\" | \"field-from-table\" | \"no-pii\" | \"matches\";\n readonly path: string;\n readonly observed: unknown;\n readonly message: string;\n}\n\nexport type TripwireResult =\n | { readonly ok: true }\n | { readonly ok: false; readonly evidence: TripwireEvidence };\n\n/**\n * Pure tripwire evaluator.\n *\n * No I/O, no Date.now, no random — same `(output, invariants)` always\n * returns the same `TripwireResult`. Phase 9 receipts can reconstruct the\n * verdict deterministically (T-08-04).\n *\n * Evaluates invariants in declaration order; the FIRST failing invariant\n * aborts and returns its evidence. Subsequent invariants are not evaluated.\n *\n * @param output The provider output to inspect.\n * @param invariants Invariants to evaluate, in declaration order.\n * @param detectors PII detectors used for `no-pii` invariants. Defaults\n * to `defaultPiiDetectors`. Callers can pass a custom\n * list to override.\n */\nexport async function evaluateTripwires(\n output: unknown,\n invariants: readonly InvariantDeclaration[],\n detectors: readonly PiiDetector[] = defaultPiiDetectors,\n): Promise<TripwireResult> {\n for (const declaration of invariants) {\n const result = await evaluateOne(output, declaration, detectors);\n if (!result.ok) return result;\n }\n return { ok: true };\n}\n\nasync function evaluateOne(\n output: unknown,\n declaration: InvariantDeclaration,\n detectors: readonly PiiDetector[],\n): Promise<TripwireResult> {\n switch (declaration.kind) {\n case \"must-cite\":\n return evaluateMustCite(output, declaration);\n case \"field-from-table\":\n return evaluateFieldFromTable(output, declaration);\n case \"no-pii\":\n return evaluateNoPii(output, declaration, detectors);\n case \"matches\":\n return evaluateMatches(output, declaration);\n default: {\n // Exhaustiveness guard. If a new kind is added without updating this\n // switch, TS will reject the assignment below.\n const _exhaustive: never = declaration;\n throw new Error(`Unknown invariant kind: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\nfunction evaluateMustCite(output: unknown, decl: MustCiteInvariant): TripwireResult {\n const located = locateCitations(output);\n const cites = located?.value ?? [];\n const path = located?.path ?? \"citations\";\n\n const matched = cites.some((entry) => {\n if (typeof entry === \"string\") return entry === decl.artifactName;\n if (typeof entry === \"object\" && entry !== null && \"source\" in entry) {\n return (entry as { source?: unknown }).source === decl.artifactName;\n }\n return false;\n });\n\n if (matched) return { ok: true };\n\n return {\n ok: false,\n evidence: {\n invariantId: decl.id,\n kind: \"must-cite\",\n path,\n observed: cites,\n message: `must-cite: no citation found for \"${decl.artifactName}\".`,\n },\n };\n}\n\n/**\n * Locate the citations payload in `output`. Searches top-level for a\n * `citations` or `evidence` key holding an array. Per 08-CONTEXT.md:\n * \"Path defaults to evidence if the output has a citations field; the\n * runtime locates the citations payload in the output.\"\n *\n * Returns `undefined` when neither field is an array.\n */\nfunction locateCitations(\n output: unknown,\n): { readonly value: readonly unknown[]; readonly path: string } | undefined {\n if (typeof output !== \"object\" || output === null) return undefined;\n const record = output as Record<string, unknown>;\n for (const key of [\"citations\", \"evidence\"] as const) {\n const value = record[key];\n if (Array.isArray(value)) return { value, path: key };\n }\n return undefined;\n}\n\nfunction evaluateFieldFromTable(\n output: unknown,\n decl: FieldFromTableInvariant,\n): TripwireResult {\n const value = resolvePath(output, decl.path);\n if (typeof value === \"string\" && decl.allowedValues.includes(value)) {\n return { ok: true };\n }\n return {\n ok: false,\n evidence: {\n invariantId: decl.id,\n kind: \"field-from-table\",\n path: decl.path,\n observed: value,\n message: `field-from-table: value at \"${decl.path}\" not in allowedValues.`,\n },\n };\n}\n\nfunction evaluateNoPii(\n output: unknown,\n decl: NoPiiInvariant,\n detectors: readonly PiiDetector[],\n): TripwireResult {\n const value = resolvePath(output, decl.path);\n if (typeof value !== \"string\") return { ok: true };\n\n for (const detector of detectors) {\n const result = detector.detect(value);\n if (result.matched) {\n return {\n ok: false,\n evidence: {\n invariantId: decl.id,\n kind: \"no-pii\",\n path: decl.path,\n // CRITICAL: redacted — only the detector name and the matched\n // substring, never the full input string (T-08-01).\n observed: { detector: detector.name, substring: result.substring },\n message: `no-pii: detector \"${detector.name}\" flagged content at \"${decl.path}\".`,\n },\n };\n }\n }\n return { ok: true };\n}\n\nasync function evaluateMatches(\n output: unknown,\n decl: MatchesInvariant,\n): Promise<TripwireResult> {\n const value = resolvePath(output, decl.path);\n const validateResult = decl.schema[\"~standard\"].validate(value);\n const validation: StandardSchemaV1.Result<unknown> =\n validateResult instanceof Promise ? await validateResult : validateResult;\n\n if (\"issues\" in validation && validation.issues !== undefined) {\n const firstIssue = validation.issues[0];\n return {\n ok: false,\n evidence: {\n invariantId: decl.id,\n kind: \"matches\",\n path: decl.path,\n observed: value,\n message: firstIssue?.message ?? `matches: schema validation failed at \"${decl.path}\".`,\n },\n };\n }\n return { ok: true };\n}\n\n/**\n * Resolve a dotted/bracketed path expression against a value.\n *\n * Supports three segment forms:\n * - dotted key: `a.b.c`\n * - bracket index: `a[0].b`\n * - wildcard: `a[*].b` (materializes the array of resolutions)\n *\n * Returns `undefined` for missing paths (does not throw).\n *\n * NOTE (T-08-03): `[*]` materializes the array; deeply nested wildcard\n * chains could allocate O(N^k). Accepted for v1.1 — provider responses\n * are bounded by output token caps.\n */\nfunction resolvePath(value: unknown, path: string): unknown {\n if (path === \"\") return value;\n const tokens = tokenize(path);\n return walk(value, tokens, 0);\n}\n\ntype Token =\n | { readonly type: \"key\"; readonly name: string }\n | { readonly type: \"index\"; readonly index: number }\n | { readonly type: \"wildcard\" };\n\nfunction tokenize(path: string): readonly Token[] {\n const tokens: Token[] = [];\n let i = 0;\n let buffer = \"\";\n const flushKey = (): void => {\n if (buffer.length > 0) {\n tokens.push({ type: \"key\", name: buffer });\n buffer = \"\";\n }\n };\n while (i < path.length) {\n const ch = path[i];\n if (ch === \".\") {\n flushKey();\n i += 1;\n continue;\n }\n if (ch === \"[\") {\n flushKey();\n const end = path.indexOf(\"]\", i + 1);\n if (end === -1) {\n // Malformed path — treat the rest as a literal key so we degrade\n // to `undefined` rather than throw on user input.\n buffer = path.slice(i);\n i = path.length;\n continue;\n }\n const inner = path.slice(i + 1, end);\n if (inner === \"*\") {\n tokens.push({ type: \"wildcard\" });\n } else {\n const idx = Number(inner);\n if (Number.isInteger(idx) && idx >= 0) {\n tokens.push({ type: \"index\", index: idx });\n } else {\n // Non-numeric bracket content — treat as a key (e.g. `a[b]` →\n // unusual but plausible).\n tokens.push({ type: \"key\", name: inner });\n }\n }\n i = end + 1;\n continue;\n }\n buffer += ch;\n i += 1;\n }\n flushKey();\n return tokens;\n}\n\nfunction walk(value: unknown, tokens: readonly Token[], cursor: number): unknown {\n if (cursor >= tokens.length) return value;\n if (value === undefined || value === null) return undefined;\n const token = tokens[cursor]!;\n if (token.type === \"key\") {\n if (typeof value !== \"object\") return undefined;\n const next = (value as Record<string, unknown>)[token.name];\n return walk(next, tokens, cursor + 1);\n }\n if (token.type === \"index\") {\n if (!Array.isArray(value)) return undefined;\n return walk(value[token.index], tokens, cursor + 1);\n }\n // wildcard\n if (!Array.isArray(value)) return undefined;\n return value.map((entry) => walk(entry, tokens, cursor + 1));\n}\n\n/**\n * Test-only export: lets unit tests exercise the path resolver directly.\n * Not part of the public surface; lives behind a `__` prefix to discourage\n * runtime use.\n */\nexport function __resolvePathForTests(value: unknown, path: string): unknown {\n return resolvePath(value, path);\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nimport type { ArtifactKind } from \"../artifacts/artifact.js\";\n\nexport type TextOutputContract = \"text\";\n\nexport interface CitationRef {\n readonly artifactId: string;\n readonly label?: string;\n readonly span?: {\n readonly start?: number;\n readonly end?: number;\n };\n readonly metadata?: Record<string, unknown>;\n}\n\nexport interface CitationsOutputContract {\n readonly kind: \"citations\";\n}\n\nexport interface ArtifactRefsOutputContract {\n readonly kind: \"artifacts\";\n readonly artifactKind?: ArtifactKind | string;\n}\n\nexport type SchemaOutputContract = StandardSchemaV1;\n\nexport type OutputContract =\n | TextOutputContract\n | SchemaOutputContract\n | CitationsOutputContract\n | ArtifactRefsOutputContract;\n\nexport type OutputContractMap = Record<string, OutputContract>;\n\nexport const output = {\n citations(): CitationsOutputContract {\n return { kind: \"citations\" };\n },\n\n artifacts(options: {\n readonly artifactKind?: ArtifactKind | string;\n } = {}): ArtifactRefsOutputContract {\n return { kind: \"artifacts\", ...options };\n },\n};\n","import type { TripwireEvidence } from \"../contract/tripwire.js\";\nimport type { RouteRejectReason } from \"../plan/plan.js\";\n\nexport interface ValidationIssue {\n readonly message: string;\n readonly path?: readonly (string | number | symbol)[];\n}\n\nexport interface ValidationError {\n readonly kind: \"validation\";\n readonly message: string;\n readonly output?: string;\n readonly issues: readonly ValidationIssue[];\n}\n\nexport interface ExecutionUnavailableError {\n readonly kind: \"execution_unavailable\";\n readonly message: string;\n}\n\nexport interface NoRouteError {\n readonly kind: \"no_route\";\n readonly message: string;\n readonly reasons: readonly string[];\n}\n\nexport interface ProviderExecutionError {\n readonly kind: \"provider_execution\";\n readonly message: string;\n readonly providerId?: string;\n readonly modelId?: string;\n}\n\nexport interface TimeoutError {\n readonly kind: \"timeout\";\n readonly message: string;\n}\n\n/**\n * Phase 7 addition: emitted by the runtime when no candidate route can\n * satisfy the caller-supplied `CapabilityContract` (budget, modality,\n * privacy, or quality-floor invariants).\n *\n * `noRouteReasons` carries the full deterministic-router rejection list\n * so callers can inspect per-candidate detail. Phase 9 (receipts) will\n * persist this array for deterministic verdict reconstruction.\n */\nexport interface NoContractMatchError {\n readonly kind: \"no-contract-match\";\n readonly message: string;\n readonly noRouteReasons: readonly RouteRejectReason[];\n}\n\n/**\n * Phase 8 addition: emitted when a `CapabilityContract.invariants` tripwire\n * fires after the provider returned a schema-valid output. Carries the\n * `TripwireEvidence` produced by `evaluateTripwires`.\n *\n * `terminal: true` is a structural marker — combined with the `isTerminal()`\n * predicate it tells the fallback chain in `runWithConfig` to refuse retry.\n * `NoContractMatchError` does NOT carry the field (to avoid breaking Phase 7\n * callers) but `isTerminal()` still returns true for it via the kind check.\n */\nexport interface TripwireViolationError {\n readonly kind: \"tripwire-violated\";\n readonly message: string;\n readonly invariantId: string;\n readonly evidence: TripwireEvidence;\n readonly terminal: true;\n}\n\nexport type LatticeRunError =\n | ValidationError\n | ExecutionUnavailableError\n | NoRouteError\n | ProviderExecutionError\n | TimeoutError\n | NoContractMatchError\n | TripwireViolationError;\n\n/**\n * Returns `true` for run errors that MUST NOT be retried by the fallback\n * chain. Phase 8 covers two kinds:\n *\n * - `tripwire-violated` — the contract's invariants rejected the output;\n * a different provider will not change the verdict, so retry burns\n * budget for no gain (T-08-06 in 08-02-PLAN threat register).\n * - `no-contract-match` — no route satisfies the contract at all; the\n * run never executed and no retry will help.\n *\n * All other error kinds return `false` and remain eligible for fallback.\n * The predicate is exported so Phase 12's eval gate and any user-side\n * retry wrappers can share one source of truth.\n */\nexport function isTerminal(error: LatticeRunError): boolean {\n return error.kind === \"tripwire-violated\" || error.kind === \"no-contract-match\";\n}\n"],"mappings":"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"}
|
package/dist/eval.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as EvalRegressionKind, i as EvalRegression, n as AgentRunSnapshot, o as evalAgentRun, r as EvalOptions, t as AgentEvalResult } from "./agent-run-C6miAzwI.js";
|
|
2
|
+
export { type AgentEvalResult, type AgentRunSnapshot, type EvalOptions, type EvalRegression, type EvalRegressionKind, evalAgentRun };
|
package/dist/eval.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/storage/fingerprint.ts
|
|
2
|
+
const textEncoder = new TextEncoder();
|
|
3
|
+
async function fingerprintArtifactValue(value) {
|
|
4
|
+
const bytes = await valueToBytes(value);
|
|
5
|
+
if (bytes === void 0) return;
|
|
6
|
+
const digest = await crypto.subtle.digest("SHA-256", toArrayBuffer(bytes));
|
|
7
|
+
return {
|
|
8
|
+
algorithm: "sha256",
|
|
9
|
+
value: toHex(new Uint8Array(digest))
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
async function valueToBytes(value) {
|
|
13
|
+
if (typeof value === "string") return textEncoder.encode(value);
|
|
14
|
+
if (value instanceof Uint8Array) return value;
|
|
15
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
16
|
+
if (isBlobLike(value)) return new Uint8Array(await value.arrayBuffer());
|
|
17
|
+
const serialized = JSON.stringify(value);
|
|
18
|
+
return serialized === void 0 ? void 0 : textEncoder.encode(serialized);
|
|
19
|
+
}
|
|
20
|
+
function isBlobLike(value) {
|
|
21
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
22
|
+
}
|
|
23
|
+
function toHex(bytes) {
|
|
24
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
25
|
+
}
|
|
26
|
+
function toArrayBuffer(bytes) {
|
|
27
|
+
const copy = new Uint8Array(bytes.byteLength);
|
|
28
|
+
copy.set(bytes);
|
|
29
|
+
return copy.buffer;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { fingerprintArtifactValue as t };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=fingerprint-DodDbQKN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint-DodDbQKN.js","names":[],"sources":["../src/storage/fingerprint.ts"],"sourcesContent":["import type { ArtifactFingerprint } from \"../artifacts/artifact.js\";\n\nconst textEncoder = new TextEncoder();\n\nexport async function fingerprintArtifactValue(\n value: unknown,\n): Promise<ArtifactFingerprint | undefined> {\n const bytes = await valueToBytes(value);\n\n if (bytes === undefined) {\n return undefined;\n }\n\n const digest = await crypto.subtle.digest(\"SHA-256\", toArrayBuffer(bytes));\n\n return {\n algorithm: \"sha256\",\n value: toHex(new Uint8Array(digest)),\n };\n}\n\nasync function valueToBytes(value: unknown): Promise<Uint8Array | undefined> {\n if (typeof value === \"string\") {\n return textEncoder.encode(value);\n }\n\n if (value instanceof Uint8Array) {\n return value;\n }\n\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n\n if (isBlobLike(value)) {\n return new Uint8Array(await value.arrayBuffer());\n }\n\n const serialized = JSON.stringify(value);\n\n return serialized === undefined ? undefined : textEncoder.encode(serialized);\n}\n\nfunction isBlobLike(value: unknown): value is Blob {\n return typeof Blob !== \"undefined\" && value instanceof Blob;\n}\n\nfunction toHex(bytes: Uint8Array): string {\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nfunction toArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n const copy = new Uint8Array(bytes.byteLength);\n copy.set(bytes);\n\n return copy.buffer as ArrayBuffer;\n}\n"],"mappings":";AAEA,MAAM,cAAc,IAAI,aAAa;AAErC,eAAsB,yBACpB,OAC0C;CAC1C,MAAM,QAAQ,MAAM,aAAa,MAAM;AAEvC,KAAI,UAAU,KAAA,EACZ;CAGF,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,cAAc,MAAM,CAAC;AAE1E,QAAO;EACL,WAAW;EACX,OAAO,MAAM,IAAI,WAAW,OAAO,CAAC;EACrC;;AAGH,eAAe,aAAa,OAAiD;AAC3E,KAAI,OAAO,UAAU,SACnB,QAAO,YAAY,OAAO,MAAM;AAGlC,KAAI,iBAAiB,WACnB,QAAO;AAGT,KAAI,iBAAiB,YACnB,QAAO,IAAI,WAAW,MAAM;AAG9B,KAAI,WAAW,MAAM,CACnB,QAAO,IAAI,WAAW,MAAM,MAAM,aAAa,CAAC;CAGlD,MAAM,aAAa,KAAK,UAAU,MAAM;AAExC,QAAO,eAAe,KAAA,IAAY,KAAA,IAAY,YAAY,OAAO,WAAW;;AAG9E,SAAS,WAAW,OAA+B;AACjD,QAAO,OAAO,SAAS,eAAe,iBAAiB;;AAGzD,SAAS,MAAM,OAA2B;AACxC,QAAO,MAAM,KAAK,QAAQ,SAAS,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG;;AAGjF,SAAS,cAAc,OAAgC;CACrD,MAAM,OAAO,IAAI,WAAW,MAAM,WAAW;AAC7C,MAAK,IAAI,MAAM;AAEf,QAAO,KAAK"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { L as ModelCapabilityProfile } from "./provider-C2IfKsvz.js";
|
|
2
|
+
|
|
3
|
+
//#region src/capabilities/lookup.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Strip the OpenRouter variant suffix (`:free` or `:thinking`) from an
|
|
6
|
+
* OpenRouter-shaped id (`vendor/model:variant`). Other adapter id shapes
|
|
7
|
+
* pass through verbatim — does not, for example, alter
|
|
8
|
+
* `anthropic:claude-opus-4` (direct-adapter canonical key) or
|
|
9
|
+
* `openai/gpt-4o:beta` (unrecognized variant per Pitfall 4).
|
|
10
|
+
*
|
|
11
|
+
* Exported because Phase 34 (adapter quirks) and Phase 36 (output
|
|
12
|
+
* sanitizers) need the same normalization. Phase 33 D-11 scope.
|
|
13
|
+
*/
|
|
14
|
+
declare function stripOpenRouterVariant(id: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* D-09 strict lookup — return the capability profile for the exact
|
|
17
|
+
* `${adapter}:${modelId}` canonical key. Returns `undefined` if the key
|
|
18
|
+
* is not registered. No fuzzy matching — use `findCapabilityProfile`
|
|
19
|
+
* for that.
|
|
20
|
+
*
|
|
21
|
+
* Examples:
|
|
22
|
+
* getCapabilityProfile("openrouter:openai/gpt-oss-120b") -> profile
|
|
23
|
+
* getCapabilityProfile("anthropic:claude-opus-4") -> profile
|
|
24
|
+
* getCapabilityProfile("not-a-real-key") -> undefined
|
|
25
|
+
*
|
|
26
|
+
* The lookup is case-sensitive on the canonical key. Threat T-33-02-01
|
|
27
|
+
* mitigation: backing store is `Map<string, ModelCapabilityProfile>`,
|
|
28
|
+
* not a plain object literal, so `__proto__` and other prototype-chain
|
|
29
|
+
* keys are safe (Map uses SameValueZero, not property lookup).
|
|
30
|
+
*/
|
|
31
|
+
declare function getCapabilityProfile(canonicalKey: string): ModelCapabilityProfile | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* D-10 fuzzy lookup — strip the OpenRouter variant suffix (if any) and
|
|
34
|
+
* return ALL matching profiles across every adapter, in deterministic
|
|
35
|
+
* order: direct adapters first (anthropic, openai, gemini, xai,
|
|
36
|
+
* openai-compat, lm-studio), then OpenRouter.
|
|
37
|
+
*
|
|
38
|
+
* Useful for pre-routing capability inspection where the adapter has
|
|
39
|
+
* not yet been chosen — the consumer can iterate the returned list
|
|
40
|
+
* and pick the first compatible one. Returns `[]` when no match is
|
|
41
|
+
* found across any adapter.
|
|
42
|
+
*
|
|
43
|
+
* Suffix-strip is OpenRouter-shape-only per D-11. Direct-adapter ids
|
|
44
|
+
* pass through verbatim:
|
|
45
|
+
* findCapabilityProfile("openai/gpt-oss-120b:free")
|
|
46
|
+
* -> [openrouter:openai/gpt-oss-120b]
|
|
47
|
+
* findCapabilityProfile("claude-opus-4")
|
|
48
|
+
* -> [anthropic:claude-opus-4, ...] (no suffix-strip)
|
|
49
|
+
*/
|
|
50
|
+
declare function findCapabilityProfile(id: string): ModelCapabilityProfile[];
|
|
51
|
+
//#endregion
|
|
52
|
+
export { getCapabilityProfile as n, stripOpenRouterVariant as r, findCapabilityProfile as t };
|
|
53
|
+
//# sourceMappingURL=index-DpnHGHVL.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-DpnHGHVL.d.ts","names":[],"sources":["../src/capabilities/lookup.ts"],"mappings":";;;;;AA0DA;;;;;AAoEA;;;iBApEgB,sBAAA,CAAuB,EAAA;;;;;;;;;;;;;;;;;iBAoEvB,oBAAA,CACd,YAAA,WACC,sBAAA;;;;;;;;;;;;;;;;;;;iBAsBa,qBAAA,CAAsB,EAAA,WAAa,sBAAA"}
|