@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
|
@@ -1,142 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function inferMediaType(value, options) {
|
|
7
|
-
if (options.mediaType !== void 0) return options.mediaType;
|
|
8
|
-
if (isBlobLike(value) && value.type !== "") return value.type;
|
|
9
|
-
if (typeof value === "string") return mime.getType(value) ?? options.defaultMediaType;
|
|
10
|
-
return options.defaultMediaType;
|
|
11
|
-
}
|
|
12
|
-
function measureArtifactValue(value, kind) {
|
|
13
|
-
if (kind === "text" && typeof value === "string") return measureString(value);
|
|
14
|
-
if (kind === "json") {
|
|
15
|
-
const serialized = JSON.stringify(value);
|
|
16
|
-
return serialized === void 0 ? void 0 : measureString(serialized);
|
|
17
|
-
}
|
|
18
|
-
if (isBlobLike(value)) return { bytes: value.size };
|
|
19
|
-
}
|
|
20
|
-
function measureString(value) {
|
|
21
|
-
return {
|
|
22
|
-
characters: value.length,
|
|
23
|
-
bytes: textEncoder$1.encode(value).byteLength
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function isBlobLike(value) {
|
|
27
|
-
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region src/artifacts/artifact.ts
|
|
31
|
-
const artifact = {
|
|
32
|
-
text(value, options = {}) {
|
|
33
|
-
return createArtifact("text", "inline", value, options, "text/plain");
|
|
34
|
-
},
|
|
35
|
-
json(value, options = {}) {
|
|
36
|
-
return createArtifact("json", "inline", value, options, "application/json");
|
|
37
|
-
},
|
|
38
|
-
file(value, options = {}) {
|
|
39
|
-
return createArtifact("file", "file", value, options);
|
|
40
|
-
},
|
|
41
|
-
image(value, options = {}) {
|
|
42
|
-
return createArtifact("image", "file", value, options);
|
|
43
|
-
},
|
|
44
|
-
audio(value, options = {}) {
|
|
45
|
-
return createArtifact("audio", "file", value, options);
|
|
46
|
-
},
|
|
47
|
-
document(value, options = {}) {
|
|
48
|
-
return createArtifact("document", "file", value, options);
|
|
49
|
-
},
|
|
50
|
-
url(value, options = {}) {
|
|
51
|
-
return createArtifact("url", "url", value.toString(), options);
|
|
52
|
-
},
|
|
53
|
-
toolResult(value, options) {
|
|
54
|
-
return createArtifact("tool-result", "tool", value, {
|
|
55
|
-
...options,
|
|
56
|
-
metadata: {
|
|
57
|
-
...options.metadata,
|
|
58
|
-
toolName: options.toolName,
|
|
59
|
-
...options.callId !== void 0 ? { callId: options.callId } : {}
|
|
60
|
-
}
|
|
61
|
-
}, "application/json");
|
|
62
|
-
},
|
|
63
|
-
derive(input) {
|
|
64
|
-
const { kind, source = "generated", value, parents, transform, ...options } = input;
|
|
65
|
-
return createArtifact(kind, source, value, {
|
|
66
|
-
...options,
|
|
67
|
-
lineage: {
|
|
68
|
-
parents: parents.map(toArtifactRef),
|
|
69
|
-
transform
|
|
70
|
-
}
|
|
71
|
-
}, defaultMediaTypeForKind(kind));
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
function toArtifactRef(input) {
|
|
75
|
-
return {
|
|
76
|
-
id: input.id,
|
|
77
|
-
kind: input.kind,
|
|
78
|
-
source: input.source,
|
|
79
|
-
privacy: input.privacy,
|
|
80
|
-
...input.mediaType !== void 0 ? { mediaType: input.mediaType } : {},
|
|
81
|
-
...input.label !== void 0 ? { label: input.label } : {},
|
|
82
|
-
...input.metadata !== void 0 ? { metadata: input.metadata } : {},
|
|
83
|
-
...input.size !== void 0 ? { size: input.size } : {},
|
|
84
|
-
...input.fingerprint !== void 0 ? { fingerprint: input.fingerprint } : {},
|
|
85
|
-
...input.storage !== void 0 ? { storage: input.storage } : {},
|
|
86
|
-
...input.lineage !== void 0 ? { lineage: input.lineage } : {}
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function isArtifactRef(value) {
|
|
90
|
-
if (!isRecord(value)) return false;
|
|
91
|
-
return typeof value.id === "string" && isArtifactKind(value.kind) && isArtifactSource(value.source) && isArtifactPrivacy(value.privacy);
|
|
92
|
-
}
|
|
93
|
-
function createArtifact(kind, source, value, options, defaultMediaType) {
|
|
94
|
-
const mediaType = inferMediaType(value, {
|
|
95
|
-
kind,
|
|
96
|
-
...options.mediaType !== void 0 ? { mediaType: options.mediaType } : {},
|
|
97
|
-
...defaultMediaType !== void 0 ? { defaultMediaType } : {}
|
|
98
|
-
});
|
|
99
|
-
const size = options.size ?? measureArtifactValue(value, kind);
|
|
100
|
-
return {
|
|
101
|
-
id: options.id ?? createArtifactId(kind),
|
|
102
|
-
kind,
|
|
103
|
-
source,
|
|
104
|
-
value,
|
|
105
|
-
privacy: options.privacy ?? "standard",
|
|
106
|
-
...mediaType !== void 0 ? { mediaType } : {},
|
|
107
|
-
...options.label !== void 0 ? { label: options.label } : {},
|
|
108
|
-
...options.metadata !== void 0 ? { metadata: options.metadata } : {},
|
|
109
|
-
...size !== void 0 ? { size } : {},
|
|
110
|
-
...options.fingerprint !== void 0 ? { fingerprint: options.fingerprint } : {},
|
|
111
|
-
...options.storage !== void 0 ? { storage: options.storage } : {},
|
|
112
|
-
...options.lineage !== void 0 ? { lineage: options.lineage } : {}
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
function defaultMediaTypeForKind(kind) {
|
|
116
|
-
switch (kind) {
|
|
117
|
-
case "text": return "text/plain";
|
|
118
|
-
case "json":
|
|
119
|
-
case "tool-result": return "application/json";
|
|
120
|
-
default: return;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
function isArtifactKind(value) {
|
|
124
|
-
return value === "text" || value === "json" || value === "file" || value === "image" || value === "audio" || value === "video" || value === "document" || value === "url" || value === "tool-result";
|
|
125
|
-
}
|
|
126
|
-
function isArtifactSource(value) {
|
|
127
|
-
return value === "inline" || value === "file" || value === "url" || value === "generated" || value === `provider-upload` || value === "tool";
|
|
128
|
-
}
|
|
129
|
-
function isArtifactPrivacy(value) {
|
|
130
|
-
return value === "standard" || value === "sensitive" || value === "restricted";
|
|
131
|
-
}
|
|
132
|
-
function isRecord(value) {
|
|
133
|
-
return typeof value === "object" && value !== null;
|
|
134
|
-
}
|
|
135
|
-
function createArtifactId(kind) {
|
|
136
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return `artifact:${kind}:${crypto.randomUUID()}`;
|
|
137
|
-
return `artifact:${kind}:${Date.now()}:${Math.random().toString(16).slice(2)}`;
|
|
138
|
-
}
|
|
139
|
-
//#endregion
|
|
2
|
+
import { r as toArtifactRef } from "./artifact-DOfpeXLb.js";
|
|
3
|
+
import { t as createReceipt } from "./receipt-FYouoPHv.js";
|
|
4
|
+
import { i as standardSchemaToJsonSchema, n as validateOutputMapValues, o as parseToolUseEnvelope } from "./validate-c7EL5uuH.js";
|
|
5
|
+
import { r as runTool } from "./tools-C4wHgGKQ.js";
|
|
140
6
|
//#region src/contract/bands.ts
|
|
141
7
|
/**
|
|
142
8
|
* Priority bands. Lower number = higher priority (runs first).
|
|
@@ -272,207 +138,6 @@ function createHookPipeline(options) {
|
|
|
272
138
|
};
|
|
273
139
|
}
|
|
274
140
|
//#endregion
|
|
275
|
-
//#region src/receipts/canonical.ts
|
|
276
|
-
const encoder = new TextEncoder();
|
|
277
|
-
/**
|
|
278
|
-
* Convert costUsd (number | null) to its canonical string form.
|
|
279
|
-
* RFC 8785 requires deterministic float-to-string; using JS Number→string
|
|
280
|
-
* directly is unsafe across V8 versions (Grisu3 vs Dragonbox). We pin the
|
|
281
|
-
* format by routing through Number.prototype.toString() for FINITE numbers
|
|
282
|
-
* only, and treat NaN/Infinity as null. This matches "I-JSON only" from
|
|
283
|
-
* 09-CONTEXT.md — receipts NEVER carry non-finite floats.
|
|
284
|
-
*/
|
|
285
|
-
function stringifyCostUsd(costUsd) {
|
|
286
|
-
if (costUsd === null) return null;
|
|
287
|
-
if (!Number.isFinite(costUsd)) return null;
|
|
288
|
-
return costUsd.toString();
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Convert a runtime Usage (number costUsd) to its canonical receipt form
|
|
292
|
-
* (string costUsd). This is the single conversion site — canonical bytes
|
|
293
|
-
* NEVER see a raw float in the cost field.
|
|
294
|
-
*/
|
|
295
|
-
function usageToCanonical(usage) {
|
|
296
|
-
return {
|
|
297
|
-
promptTokens: usage.promptTokens,
|
|
298
|
-
completionTokens: usage.completionTokens,
|
|
299
|
-
costUsd: stringifyCostUsd(usage.costUsd)
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Canonicalize a receipt body to JCS bytes (RFC 8785).
|
|
304
|
-
*
|
|
305
|
-
* INVARIANT: callers MUST pass an already-redacted body. The redactor in
|
|
306
|
-
* redact.ts produces the input to this function — never the cleartext.
|
|
307
|
-
* See 09-CONTEXT.md "Redact-Then-Sign Ordering (UNRETROFITTABLE)".
|
|
308
|
-
*
|
|
309
|
-
* Throws if canonicalize returns undefined (impossible for valid bodies
|
|
310
|
-
* — surfaces a programmer error rather than silently producing zero
|
|
311
|
-
* bytes that would later fail signature verification).
|
|
312
|
-
*/
|
|
313
|
-
function canonicalizeReceiptBody(body) {
|
|
314
|
-
const json = canonicalize(body);
|
|
315
|
-
if (json === void 0) throw new Error("canonicalizeReceiptBody: canonicalize returned undefined; receipt body contained a non-canonicalizable value (function/symbol/undefined).");
|
|
316
|
-
return encoder.encode(json);
|
|
317
|
-
}
|
|
318
|
-
//#endregion
|
|
319
|
-
//#region src/receipts/envelope.ts
|
|
320
|
-
const PAYLOAD_TYPE = "application/vnd.lattice.receipt+json";
|
|
321
|
-
const textEncoder = new TextEncoder();
|
|
322
|
-
function base64Encode(bytes) {
|
|
323
|
-
return Buffer.from(bytes).toString("base64");
|
|
324
|
-
}
|
|
325
|
-
function base64Decode(value) {
|
|
326
|
-
return new Uint8Array(Buffer.from(value, "base64"));
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* DSSE v1.0 Pre-Authentication Encoding.
|
|
330
|
-
*
|
|
331
|
-
* Reference: https://github.com/secure-systems-lab/dsse/blob/v1.0.0/protocol.md
|
|
332
|
-
*
|
|
333
|
-
* PAE = UTF-8("DSSEv1 " + len(payloadType) + " " + payloadType
|
|
334
|
-
* + " " + len(payload) + " " + payload)
|
|
335
|
-
*
|
|
336
|
-
* `payload` here is the BASE64-encoded string per DSSE v1.0 spec (NOT raw
|
|
337
|
-
* canonical bytes). Both signing and verification MUST construct PAE the
|
|
338
|
-
* same way; this module is the single source of truth.
|
|
339
|
-
*
|
|
340
|
-
* ASCII length is decimal (no zero-padding). e.g. length 1000 → "1000".
|
|
341
|
-
*/
|
|
342
|
-
function buildPae(payloadType, payloadBase64) {
|
|
343
|
-
const ascii = "DSSEv1 " + payloadType.length.toString() + " " + payloadType + " " + payloadBase64.length.toString() + " " + payloadBase64;
|
|
344
|
-
return textEncoder.encode(ascii);
|
|
345
|
-
}
|
|
346
|
-
function encodeEnvelope(input) {
|
|
347
|
-
return {
|
|
348
|
-
payloadType: PAYLOAD_TYPE,
|
|
349
|
-
payload: base64Encode(input.payloadBytes),
|
|
350
|
-
signatures: input.signatures.map((entry) => ({
|
|
351
|
-
keyid: entry.keyid,
|
|
352
|
-
sig: base64Encode(entry.sig)
|
|
353
|
-
}))
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
function decodeEnvelope(envelope) {
|
|
357
|
-
if (envelope.payloadType !== "application/vnd.lattice.receipt+json") throw new Error(`envelope payloadType mismatch: expected "${PAYLOAD_TYPE}" got "${envelope.payloadType}"`);
|
|
358
|
-
return {
|
|
359
|
-
payloadType: envelope.payloadType,
|
|
360
|
-
payloadBytes: base64Decode(envelope.payload),
|
|
361
|
-
signatures: envelope.signatures.map((entry) => ({
|
|
362
|
-
keyid: entry.keyid,
|
|
363
|
-
sig: base64Decode(entry.sig)
|
|
364
|
-
}))
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
//#endregion
|
|
368
|
-
//#region src/receipts/redact.ts
|
|
369
|
-
/**
|
|
370
|
-
* Default redaction policy id for v1.1. Free-form string per
|
|
371
|
-
* 09-CONTEXT.md — registry enforcement deferred to v1.2.
|
|
372
|
-
*/
|
|
373
|
-
const DEFAULT_REDACTION_POLICY_ID = "lattice.default.v1";
|
|
374
|
-
/**
|
|
375
|
-
* Redact a receipt body BEFORE canonicalization (and BEFORE signing).
|
|
376
|
-
*
|
|
377
|
-
* The signed digest commits to canonicalize(redact(body)). NEVER the
|
|
378
|
-
* other way around. See 09-CONTEXT.md "Redact-Then-Sign Ordering
|
|
379
|
-
* (UNRETROFITTABLE)" and PITFALLS.md Pitfall #1.
|
|
380
|
-
*
|
|
381
|
-
* For v1.1 the default policy is minimal — the heavy lifting already
|
|
382
|
-
* happened upstream:
|
|
383
|
-
* - Tripwire evaluator emits {detector, substring} for no-pii (T-08-01).
|
|
384
|
-
* - Provider responses are hashed into inputHashes/outputHash, never
|
|
385
|
-
* embedded raw.
|
|
386
|
-
* - Router reject messages do not contain PII by construction.
|
|
387
|
-
*
|
|
388
|
-
* This function therefore primarily:
|
|
389
|
-
* 1. Materializes the redactions[] manifest declaring what WAS elided
|
|
390
|
-
* upstream (so receipts are self-describing).
|
|
391
|
-
* 2. Provides the extension point future policies will use.
|
|
392
|
-
*
|
|
393
|
-
* Returns a NEW body — never mutates the input.
|
|
394
|
-
*/
|
|
395
|
-
function redactReceiptBody(body, policyId = DEFAULT_REDACTION_POLICY_ID) {
|
|
396
|
-
const redactions = [];
|
|
397
|
-
if (body.tripwireEvidence !== void 0 && body.tripwireEvidence.kind === "no-pii") redactions.push({
|
|
398
|
-
path: "tripwireEvidence.observed",
|
|
399
|
-
reason: "no-pii-detector-substring-only"
|
|
400
|
-
});
|
|
401
|
-
const sorted = [...redactions].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
402
|
-
return {
|
|
403
|
-
body: {
|
|
404
|
-
...body,
|
|
405
|
-
redactionPolicyId: policyId,
|
|
406
|
-
redactions: sorted
|
|
407
|
-
},
|
|
408
|
-
redactions: sorted
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
//#endregion
|
|
412
|
-
//#region src/receipts/receipt.ts
|
|
413
|
-
/**
|
|
414
|
-
* Build, redact, canonicalize, sign, and envelope a CapabilityReceipt.
|
|
415
|
-
*
|
|
416
|
-
* Ordering INVARIANT (09-CONTEXT.md, PITFALLS.md Pitfall #1):
|
|
417
|
-
* redact -> canonicalize -> PAE -> sign -> encode
|
|
418
|
-
*
|
|
419
|
-
* The signed digest commits to canonicalize(redact(body)). The function
|
|
420
|
-
* structure makes any other ordering impossible to write by accident —
|
|
421
|
-
* canonicalizeReceiptBody is ONLY called on the output of redactReceiptBody.
|
|
422
|
-
*
|
|
423
|
-
* Defense in depth:
|
|
424
|
-
* - body.kid is assigned from signer.kid, never from input (input has no
|
|
425
|
-
* kid field). The signed body and the envelope keyid CANNOT disagree by
|
|
426
|
-
* construction.
|
|
427
|
-
* - signer.kid is also written to envelope.signatures[0].keyid, so the
|
|
428
|
-
* verifier can cross-check (Step 7 of verifyReceipt).
|
|
429
|
-
*
|
|
430
|
-
* I-JSON guarantees: usage.costUsd is converted to string (or null) via
|
|
431
|
-
* usageToCanonical. Receipts NEVER carry raw floats in the canonical form.
|
|
432
|
-
*/
|
|
433
|
-
async function createReceipt(input, signer) {
|
|
434
|
-
const policyId = input.redactionPolicyId ?? "lattice.default.v1";
|
|
435
|
-
const receiptId = input.receiptId ?? crypto.randomUUID();
|
|
436
|
-
const issuedAt = input.issuedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
437
|
-
const { body } = redactReceiptBody({
|
|
438
|
-
version: "lattice-receipt/v1.3",
|
|
439
|
-
receiptId,
|
|
440
|
-
runId: input.runId,
|
|
441
|
-
issuedAt,
|
|
442
|
-
kid: signer.kid,
|
|
443
|
-
model: input.model,
|
|
444
|
-
route: input.route,
|
|
445
|
-
...input.modelClass !== void 0 ? { modelClass: input.modelClass } : {},
|
|
446
|
-
...input.parentReceiptCid !== void 0 ? { parentReceiptCid: input.parentReceiptCid } : {},
|
|
447
|
-
...input.lineageMerkleRoot !== void 0 ? { lineageMerkleRoot: input.lineageMerkleRoot } : {},
|
|
448
|
-
usage: usageToCanonical(input.usage),
|
|
449
|
-
contractVerdict: input.contractVerdict,
|
|
450
|
-
contractHash: input.contractHash,
|
|
451
|
-
inputHashes: input.inputHashes,
|
|
452
|
-
outputHash: input.outputHash,
|
|
453
|
-
redactionPolicyId: policyId,
|
|
454
|
-
redactions: [],
|
|
455
|
-
...input.noRouteReasons !== void 0 ? { noRouteReasons: input.noRouteReasons } : {},
|
|
456
|
-
...input.tripwireEvidence !== void 0 ? { tripwireEvidence: input.tripwireEvidence } : {},
|
|
457
|
-
...input.stepName !== void 0 ? { stepName: input.stepName } : {},
|
|
458
|
-
...input.stepIndex !== void 0 ? { stepIndex: input.stepIndex } : {},
|
|
459
|
-
...input.parentStepName !== void 0 ? { parentStepName: input.parentStepName } : {},
|
|
460
|
-
...input.previousStepName !== void 0 ? { previousStepName: input.previousStepName } : {},
|
|
461
|
-
...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
|
|
462
|
-
...input.timestamp !== void 0 ? { timestamp: input.timestamp } : {}
|
|
463
|
-
}, policyId);
|
|
464
|
-
const payloadBytes = canonicalizeReceiptBody(body);
|
|
465
|
-
const pae = buildPae(PAYLOAD_TYPE, base64Encode(payloadBytes));
|
|
466
|
-
const sig = await signer.sign(pae);
|
|
467
|
-
return encodeEnvelope({
|
|
468
|
-
payloadBytes,
|
|
469
|
-
signatures: [{
|
|
470
|
-
keyid: signer.kid,
|
|
471
|
-
sig
|
|
472
|
-
}]
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
//#endregion
|
|
476
141
|
//#region src/contract/checkpoint.ts
|
|
477
142
|
/**
|
|
478
143
|
* The tracer event name Lattice's checkpoint hook emits per step transition.
|
|
@@ -589,34 +254,89 @@ function extractReceiptId(envelope) {
|
|
|
589
254
|
}
|
|
590
255
|
}
|
|
591
256
|
//#endregion
|
|
592
|
-
//#region src/
|
|
257
|
+
//#region src/runtime/survivability.ts
|
|
593
258
|
/**
|
|
594
|
-
*
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
*
|
|
259
|
+
* Reference implementation of SurvivabilityAdapter<TState>. Records
|
|
260
|
+
* eviction events but does NOT persist; serialize / deserialize round-
|
|
261
|
+
* trip via JSON.stringify / JSON.parse. Analog to createFakeProvider
|
|
262
|
+
* in the providers/ module -- gives Lattice's vitest a complete shape-
|
|
263
|
+
* conformance target before the real (FSB-side) adapter ships in
|
|
264
|
+
* Plan 05-05.
|
|
265
|
+
*
|
|
266
|
+
* Per CONTEXT.md D-11 the noop adapter ships in Lattice (not FSB)
|
|
267
|
+
* because it covers the contract surface in Lattice's own test suite;
|
|
268
|
+
* FSB's real chrome.storage.session-backed adapter is glue layer.
|
|
601
269
|
*/
|
|
602
|
-
function
|
|
603
|
-
const
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
const maybeToJson = schema.toJSONSchema;
|
|
607
|
-
if (typeof maybeToJson === "function") try {
|
|
608
|
-
return maybeToJson();
|
|
609
|
-
} catch {}
|
|
610
|
-
return {
|
|
611
|
-
$comment: `standard-schema vendor: ${vendor.vendor}; toJSONSchema not available`,
|
|
612
|
-
type: "object"
|
|
613
|
-
};
|
|
614
|
-
}
|
|
270
|
+
function createNoopSurvivabilityAdapter(options = {}) {
|
|
271
|
+
const id = options.id ?? "noop-survivability";
|
|
272
|
+
const defaultPolicy = options.policy ?? "SAFE";
|
|
273
|
+
const hooks = /* @__PURE__ */ new Set();
|
|
615
274
|
return {
|
|
616
|
-
|
|
617
|
-
|
|
275
|
+
kind: "survivability-adapter",
|
|
276
|
+
id,
|
|
277
|
+
serialize(state) {
|
|
278
|
+
return {
|
|
279
|
+
kind: "survivability-snapshot",
|
|
280
|
+
version: "lattice-survivability/v1",
|
|
281
|
+
payload: JSON.stringify(state ?? null),
|
|
282
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
deserialize(snapshot) {
|
|
286
|
+
return JSON.parse(snapshot.payload);
|
|
287
|
+
},
|
|
288
|
+
onEviction(hook) {
|
|
289
|
+
hooks.add(hook);
|
|
290
|
+
let unsubscribed = false;
|
|
291
|
+
return () => {
|
|
292
|
+
if (unsubscribed) return;
|
|
293
|
+
unsubscribed = true;
|
|
294
|
+
hooks.delete(hook);
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
async resume(_snapshot) {
|
|
298
|
+
return defaultPolicy;
|
|
299
|
+
}
|
|
618
300
|
};
|
|
619
301
|
}
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region src/agent/format-tools.ts
|
|
304
|
+
/**
|
|
305
|
+
* formatToolsForProvider — Phase 19 (v1.2).
|
|
306
|
+
*
|
|
307
|
+
* The agent loop runs over the existing v1.1 + v1.2 `ProviderAdapter`
|
|
308
|
+
* interface unchanged (CONTEXT.md Q2). Adapters accept only a single
|
|
309
|
+
* `task: string` plus `outputs[]` — they have no native multi-turn or
|
|
310
|
+
* tool-use surface.
|
|
311
|
+
*
|
|
312
|
+
* This helper bridges that gap by encoding the running conversation +
|
|
313
|
+
* tool descriptions + a structured "respond with this envelope" instruction
|
|
314
|
+
* into the `task` string. The model is asked to either answer directly or
|
|
315
|
+
* emit a JSON envelope on a line by itself. `parseToolUse` extracts the
|
|
316
|
+
* envelope.
|
|
317
|
+
*
|
|
318
|
+
* The implementation works ACROSS all 7 logical providers (openai,
|
|
319
|
+
* openai-compat, anthropic, gemini, xai, openrouter, lm-studio) by virtue
|
|
320
|
+
* of being provider-agnostic: it uses the adapter's normalized text
|
|
321
|
+
* response (`ProviderRunResponse.rawOutputs`) and never touches the
|
|
322
|
+
* provider-specific request shape. Native tool_use (Anthropic Messages-API
|
|
323
|
+
* `tools[]`, OpenAI Chat-Completions `tools[]`, Gemini `function_declarations`)
|
|
324
|
+
* is DEFERRED to a follow-on milestone where the `ProviderAdapter` interface
|
|
325
|
+
* can be additively extended without breaking the INV-03 parity contract
|
|
326
|
+
* shipped in v1.2 Phase 17.
|
|
327
|
+
*
|
|
328
|
+
* Returned closure shape:
|
|
329
|
+
* {
|
|
330
|
+
* buildTask(conversation, system?) — encodes turns + tools + envelope
|
|
331
|
+
* instructions into a single string;
|
|
332
|
+
* parseToolUse(text) — extracts JSON tool-call envelopes
|
|
333
|
+
* from the response, returns null
|
|
334
|
+
* when the response is a final answer;
|
|
335
|
+
* describeForSystem() — returns the static tool-description
|
|
336
|
+
* block (for tracing / logging);
|
|
337
|
+
* }
|
|
338
|
+
*/
|
|
339
|
+
const toolSchemaToJsonSchema = standardSchemaToJsonSchema;
|
|
620
340
|
/**
|
|
621
341
|
* Builds the prompt-reencoded tool-use protocol handle for any provider.
|
|
622
342
|
*
|
|
@@ -690,281 +410,6 @@ function formatToolsForProvider(providerName, tools, options = {}) {
|
|
|
690
410
|
mode: "prompt-reencoded"
|
|
691
411
|
};
|
|
692
412
|
}
|
|
693
|
-
function parseToolUseEnvelope(responseText) {
|
|
694
|
-
if (typeof responseText !== "string" || responseText.length === 0) return null;
|
|
695
|
-
const candidates = extractJsonCandidates(responseText);
|
|
696
|
-
for (const candidate of candidates) {
|
|
697
|
-
const parsed = tryParseEnvelope(candidate);
|
|
698
|
-
if (parsed !== null) return parsed;
|
|
699
|
-
}
|
|
700
|
-
return null;
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* Extracts JSON-looking candidate substrings from a response text.
|
|
704
|
-
*
|
|
705
|
-
* Models routinely wrap JSON in markdown code fences (```json ... ```),
|
|
706
|
-
* prepend explanatory prose ("I'll call the search tool: { ... }"), or
|
|
707
|
-
* produce multiple JSON-shaped blobs. This extractor scans for plausible
|
|
708
|
-
* candidates ordered by likelihood.
|
|
709
|
-
*/
|
|
710
|
-
function extractJsonCandidates(text) {
|
|
711
|
-
const candidates = [];
|
|
712
|
-
const fenceRegex = /```(?:json)?\s*([\s\S]*?)```/g;
|
|
713
|
-
let fenceMatch;
|
|
714
|
-
while ((fenceMatch = fenceRegex.exec(text)) !== null) {
|
|
715
|
-
const inner = fenceMatch[1];
|
|
716
|
-
if (inner !== void 0) candidates.push(inner.trim());
|
|
717
|
-
}
|
|
718
|
-
const braceStart = text.indexOf("{");
|
|
719
|
-
const braceEnd = text.lastIndexOf("}");
|
|
720
|
-
if (braceStart !== -1 && braceEnd > braceStart) candidates.push(text.slice(braceStart, braceEnd + 1));
|
|
721
|
-
candidates.push(text.trim());
|
|
722
|
-
return candidates;
|
|
723
|
-
}
|
|
724
|
-
function tryParseEnvelope(jsonLike) {
|
|
725
|
-
let parsed;
|
|
726
|
-
try {
|
|
727
|
-
parsed = JSON.parse(jsonLike);
|
|
728
|
-
} catch {
|
|
729
|
-
return null;
|
|
730
|
-
}
|
|
731
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
732
|
-
const toolCalls = parsed["tool_calls"];
|
|
733
|
-
if (!Array.isArray(toolCalls) || toolCalls.length === 0) return null;
|
|
734
|
-
const requests = [];
|
|
735
|
-
for (const call of toolCalls) {
|
|
736
|
-
if (typeof call !== "object" || call === null) return null;
|
|
737
|
-
const callRecord = call;
|
|
738
|
-
const id = callRecord["id"];
|
|
739
|
-
const name = callRecord["name"];
|
|
740
|
-
const args = callRecord["args"];
|
|
741
|
-
if (typeof id !== "string" || typeof name !== "string") return null;
|
|
742
|
-
requests.push({
|
|
743
|
-
id,
|
|
744
|
-
name,
|
|
745
|
-
args
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
return requests;
|
|
749
|
-
}
|
|
750
|
-
//#endregion
|
|
751
|
-
//#region src/outputs/validate.ts
|
|
752
|
-
async function validateSchemaOutput(name, schema, value) {
|
|
753
|
-
const result = schema["~standard"].validate(value);
|
|
754
|
-
const validation = result instanceof Promise ? await result : result;
|
|
755
|
-
if (validation.issues) return {
|
|
756
|
-
ok: false,
|
|
757
|
-
issue: {
|
|
758
|
-
["output"]: name,
|
|
759
|
-
issues: validation.issues.map(normalizeIssue)
|
|
760
|
-
}
|
|
761
|
-
};
|
|
762
|
-
return {
|
|
763
|
-
ok: true,
|
|
764
|
-
value: validation.value
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
async function validateOutputMap(contracts, rawOutputs, plan) {
|
|
768
|
-
const outputs = {};
|
|
769
|
-
for (const [name, contract] of Object.entries(contracts)) {
|
|
770
|
-
const value = rawOutputs[name];
|
|
771
|
-
const issue = await validateOutput(name, contract, value);
|
|
772
|
-
if (!issue.ok) return {
|
|
773
|
-
ok: false,
|
|
774
|
-
error: {
|
|
775
|
-
kind: "validation",
|
|
776
|
-
message: `Invalid output "${name}".`,
|
|
777
|
-
["output"]: name,
|
|
778
|
-
issues: issue.issues
|
|
779
|
-
},
|
|
780
|
-
usage: {
|
|
781
|
-
promptTokens: 0,
|
|
782
|
-
completionTokens: 0,
|
|
783
|
-
costUsd: null
|
|
784
|
-
},
|
|
785
|
-
raw: rawOutputs,
|
|
786
|
-
partialOutputs: outputs,
|
|
787
|
-
plan
|
|
788
|
-
};
|
|
789
|
-
outputs[name] = issue.value;
|
|
790
|
-
}
|
|
791
|
-
return {
|
|
792
|
-
ok: true,
|
|
793
|
-
outputs,
|
|
794
|
-
artifacts: [],
|
|
795
|
-
usage: {
|
|
796
|
-
promptTokens: 0,
|
|
797
|
-
completionTokens: 0,
|
|
798
|
-
costUsd: null
|
|
799
|
-
},
|
|
800
|
-
plan
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
async function validateOutput(name, contract, value) {
|
|
804
|
-
if (contract === "text") {
|
|
805
|
-
if (typeof value !== "string") return {
|
|
806
|
-
ok: false,
|
|
807
|
-
issues: [{ message: "Expected text output to be a string." }]
|
|
808
|
-
};
|
|
809
|
-
return {
|
|
810
|
-
ok: true,
|
|
811
|
-
value
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
if (isStandardSchema(contract)) {
|
|
815
|
-
const result = await validateSchemaOutput(name, contract, value);
|
|
816
|
-
if (!result.ok) return {
|
|
817
|
-
ok: false,
|
|
818
|
-
issues: result.issue.issues
|
|
819
|
-
};
|
|
820
|
-
return {
|
|
821
|
-
ok: true,
|
|
822
|
-
value: result.value
|
|
823
|
-
};
|
|
824
|
-
}
|
|
825
|
-
if (contract.kind === "citations") {
|
|
826
|
-
if (!Array.isArray(value)) return {
|
|
827
|
-
ok: false,
|
|
828
|
-
issues: [{ message: "Expected citations output to be an array." }]
|
|
829
|
-
};
|
|
830
|
-
return {
|
|
831
|
-
ok: true,
|
|
832
|
-
value
|
|
833
|
-
};
|
|
834
|
-
}
|
|
835
|
-
if (contract.kind === "artifacts") {
|
|
836
|
-
if (!Array.isArray(value)) return {
|
|
837
|
-
ok: false,
|
|
838
|
-
issues: [{ message: "Expected artifacts output to be an array." }]
|
|
839
|
-
};
|
|
840
|
-
for (const item of value) {
|
|
841
|
-
if (!isArtifactRef(item)) return {
|
|
842
|
-
ok: false,
|
|
843
|
-
issues: [{ message: "Expected artifacts output item to be an artifact ref." }]
|
|
844
|
-
};
|
|
845
|
-
if (contract.artifactKind !== void 0 && item.kind !== contract.artifactKind) return {
|
|
846
|
-
ok: false,
|
|
847
|
-
issues: [{ message: `Expected artifacts output item kind to be "${contract.artifactKind}".` }]
|
|
848
|
-
};
|
|
849
|
-
}
|
|
850
|
-
return {
|
|
851
|
-
ok: true,
|
|
852
|
-
value: value.map(toArtifactRef)
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
return {
|
|
856
|
-
ok: false,
|
|
857
|
-
issues: [{ message: "Unsupported output contract." }]
|
|
858
|
-
};
|
|
859
|
-
}
|
|
860
|
-
function isStandardSchema(contract) {
|
|
861
|
-
if (typeof contract !== "object" || contract === null) return false;
|
|
862
|
-
return typeof contract["~standard"]?.validate === "function";
|
|
863
|
-
}
|
|
864
|
-
function normalizeIssue(issue) {
|
|
865
|
-
const path = issue.path?.map(normalizePathSegment).filter((segment) => segment !== void 0);
|
|
866
|
-
return {
|
|
867
|
-
message: issue.message,
|
|
868
|
-
...path !== void 0 && path.length > 0 ? { path } : {}
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
function normalizePathSegment(segment) {
|
|
872
|
-
if (typeof segment === "string" || typeof segment === "number" || typeof segment === "symbol") return segment;
|
|
873
|
-
return normalizePathKey(segment.key);
|
|
874
|
-
}
|
|
875
|
-
function normalizePathKey(key) {
|
|
876
|
-
return key;
|
|
877
|
-
}
|
|
878
|
-
//#endregion
|
|
879
|
-
//#region src/runtime/survivability.ts
|
|
880
|
-
/**
|
|
881
|
-
* Reference implementation of SurvivabilityAdapter<TState>. Records
|
|
882
|
-
* eviction events but does NOT persist; serialize / deserialize round-
|
|
883
|
-
* trip via JSON.stringify / JSON.parse. Analog to createFakeProvider
|
|
884
|
-
* in the providers/ module -- gives Lattice's vitest a complete shape-
|
|
885
|
-
* conformance target before the real (FSB-side) adapter ships in
|
|
886
|
-
* Plan 05-05.
|
|
887
|
-
*
|
|
888
|
-
* Per CONTEXT.md D-11 the noop adapter ships in Lattice (not FSB)
|
|
889
|
-
* because it covers the contract surface in Lattice's own test suite;
|
|
890
|
-
* FSB's real chrome.storage.session-backed adapter is glue layer.
|
|
891
|
-
*/
|
|
892
|
-
function createNoopSurvivabilityAdapter(options = {}) {
|
|
893
|
-
const id = options.id ?? "noop-survivability";
|
|
894
|
-
const defaultPolicy = options.policy ?? "SAFE";
|
|
895
|
-
const hooks = /* @__PURE__ */ new Set();
|
|
896
|
-
return {
|
|
897
|
-
kind: "survivability-adapter",
|
|
898
|
-
id,
|
|
899
|
-
serialize(state) {
|
|
900
|
-
return {
|
|
901
|
-
kind: "survivability-snapshot",
|
|
902
|
-
version: "lattice-survivability/v1",
|
|
903
|
-
payload: JSON.stringify(state ?? null),
|
|
904
|
-
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
905
|
-
};
|
|
906
|
-
},
|
|
907
|
-
deserialize(snapshot) {
|
|
908
|
-
return JSON.parse(snapshot.payload);
|
|
909
|
-
},
|
|
910
|
-
onEviction(hook) {
|
|
911
|
-
hooks.add(hook);
|
|
912
|
-
let unsubscribed = false;
|
|
913
|
-
return () => {
|
|
914
|
-
if (unsubscribed) return;
|
|
915
|
-
unsubscribed = true;
|
|
916
|
-
hooks.delete(hook);
|
|
917
|
-
};
|
|
918
|
-
},
|
|
919
|
-
async resume(_snapshot) {
|
|
920
|
-
return defaultPolicy;
|
|
921
|
-
}
|
|
922
|
-
};
|
|
923
|
-
}
|
|
924
|
-
//#endregion
|
|
925
|
-
//#region src/tools/tools.ts
|
|
926
|
-
function defineTool(definition) {
|
|
927
|
-
return {
|
|
928
|
-
kind: "tool",
|
|
929
|
-
...definition
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
async function runTool(tool, input, context = {}) {
|
|
933
|
-
const validation = await validateSchemaOutput(tool.name, tool.inputSchema, input);
|
|
934
|
-
if (!validation.ok) throw new Error(`Invalid input for tool "${tool.name}".`);
|
|
935
|
-
const callId = createToolCallId();
|
|
936
|
-
const output = await tool.execute(validation.value, context);
|
|
937
|
-
return {
|
|
938
|
-
callId,
|
|
939
|
-
toolName: tool.name,
|
|
940
|
-
artifact: artifact.toolResult(output, {
|
|
941
|
-
id: `artifact:tool-result:${tool.name}:${callId}`,
|
|
942
|
-
toolName: tool.name,
|
|
943
|
-
callId
|
|
944
|
-
})
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
|
-
async function importMcpTools(client, toolNames) {
|
|
948
|
-
const descriptors = await Promise.resolve(client.listTools?.() ?? []);
|
|
949
|
-
const allowed = toolNames === void 0 ? void 0 : new Set(toolNames);
|
|
950
|
-
return descriptors.filter((descriptor) => allowed === void 0 || allowed.has(descriptor.name)).map((descriptor) => defineTool({
|
|
951
|
-
name: descriptor.name,
|
|
952
|
-
...descriptor.description !== void 0 ? { description: descriptor.description } : {},
|
|
953
|
-
inputSchema: descriptor.inputSchema,
|
|
954
|
-
execute: async (input) => client.callTool({
|
|
955
|
-
name: descriptor.name,
|
|
956
|
-
arguments: input
|
|
957
|
-
})
|
|
958
|
-
}));
|
|
959
|
-
}
|
|
960
|
-
function toolArtifactRef(result) {
|
|
961
|
-
const { value: _value, ...ref } = result.artifact;
|
|
962
|
-
return ref;
|
|
963
|
-
}
|
|
964
|
-
function createToolCallId() {
|
|
965
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
966
|
-
return `${Date.now()}:${Math.random().toString(16).slice(2)}`;
|
|
967
|
-
}
|
|
968
413
|
//#endregion
|
|
969
414
|
//#region src/agent/host.ts
|
|
970
415
|
/**
|
|
@@ -1028,6 +473,7 @@ const ZERO_USAGE = {
|
|
|
1028
473
|
completionTokens: 0,
|
|
1029
474
|
costUsd: null
|
|
1030
475
|
};
|
|
476
|
+
const DEFAULT_AGENT_OUTPUTS = { answer: "text" };
|
|
1031
477
|
/**
|
|
1032
478
|
* Resolves the runtime's behaviour for a single `ai.runAgent(intent)` call.
|
|
1033
479
|
*
|
|
@@ -1073,6 +519,8 @@ async function runAgentInternal(intent, config = {}, internalOptions = {}) {
|
|
|
1073
519
|
content: intent.task
|
|
1074
520
|
}];
|
|
1075
521
|
const handle = formatToolsForProvider(providerName, intent.tools);
|
|
522
|
+
const outputContracts = intent.outputs ?? DEFAULT_AGENT_OUTPUTS;
|
|
523
|
+
const outputNames = Object.keys(outputContracts);
|
|
1076
524
|
const budget = intent.contract?.budget;
|
|
1077
525
|
const maxIterations = budget?.maxIterations ?? Number.POSITIVE_INFINITY;
|
|
1078
526
|
const maxWallTimeMs = budget?.maxWallTimeMs ?? Number.POSITIVE_INFINITY;
|
|
@@ -1166,7 +614,8 @@ async function runAgentInternal(intent, config = {}, internalOptions = {}) {
|
|
|
1166
614
|
const providerRequest = {
|
|
1167
615
|
task,
|
|
1168
616
|
artifacts: [],
|
|
1169
|
-
outputs:
|
|
617
|
+
outputs: outputNames,
|
|
618
|
+
outputContracts,
|
|
1170
619
|
...intent.policy !== void 0 ? { policy: intent.policy } : {}
|
|
1171
620
|
};
|
|
1172
621
|
response = host.transport !== void 0 ? await host.transport.call(provider, providerRequest) : await provider.execute(providerRequest);
|
|
@@ -1212,11 +661,19 @@ async function runAgentInternal(intent, config = {}, internalOptions = {}) {
|
|
|
1212
661
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1213
662
|
previousStepName: `agent-iteration-${iterationIndex}-before`
|
|
1214
663
|
});
|
|
664
|
+
const outputValidation = await validateOutputMapValues(outputContracts, response.rawOutputs);
|
|
665
|
+
if (!outputValidation.ok) return buildFailure({
|
|
666
|
+
kind: "validation",
|
|
667
|
+
reason: outputValidation.error.message,
|
|
668
|
+
cause: outputValidation.error,
|
|
669
|
+
iterations,
|
|
670
|
+
usage: cumulativeUsage
|
|
671
|
+
});
|
|
1215
672
|
await host.storage?.clear();
|
|
1216
673
|
const artifactRefs = response.artifactRefs !== void 0 ? response.artifactRefs.map(toArtifactRef) : [];
|
|
1217
674
|
return {
|
|
1218
675
|
kind: "success",
|
|
1219
|
-
output:
|
|
676
|
+
output: outputValidation.outputs,
|
|
1220
677
|
...artifactRefs.length > 0 ? { artifacts: artifactRefs } : {},
|
|
1221
678
|
usage: snapshotUsage(cumulativeUsage),
|
|
1222
679
|
iterations: Object.freeze([...iterations])
|
|
@@ -1387,6 +844,6 @@ function stableHash(input) {
|
|
|
1387
844
|
}
|
|
1388
845
|
}
|
|
1389
846
|
//#endregion
|
|
1390
|
-
export {
|
|
847
|
+
export { createNoopAgentHost as a, createNoopSurvivabilityAdapter as c, createCheckpointHook as d, BAND as f, AgentDeniedError as i, DEFAULT_CHECKPOINT_BAND as l, runAgentInternal as n, formatToolsForProvider as o, createHookPipeline as p, runtime_exports as r, toolSchemaToJsonSchema as s, runAgent as t, STEP_TRANSITION_EVENT_NAME as u };
|
|
1391
848
|
|
|
1392
|
-
//# sourceMappingURL=runtime-
|
|
849
|
+
//# sourceMappingURL=runtime-Dxiet5YS.js.map
|