@full-self-browsing/lattice 1.3.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 +78 -3234
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +365 -8434
- 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-DDznbc3G.js → run-crew-B2fQLmgB.js} +16 -23
- 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-BTi8lr_O.js → runtime-Dxiet5YS.js} +100 -640
- 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 +105 -6
- package/dist/run-crew-DDznbc3G.js.map +0 -1
- package/dist/runtime-BTi8lr_O.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,206 +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.2",
|
|
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
|
-
usage: usageToCanonical(input.usage),
|
|
448
|
-
contractVerdict: input.contractVerdict,
|
|
449
|
-
contractHash: input.contractHash,
|
|
450
|
-
inputHashes: input.inputHashes,
|
|
451
|
-
outputHash: input.outputHash,
|
|
452
|
-
redactionPolicyId: policyId,
|
|
453
|
-
redactions: [],
|
|
454
|
-
...input.noRouteReasons !== void 0 ? { noRouteReasons: input.noRouteReasons } : {},
|
|
455
|
-
...input.tripwireEvidence !== void 0 ? { tripwireEvidence: input.tripwireEvidence } : {},
|
|
456
|
-
...input.stepName !== void 0 ? { stepName: input.stepName } : {},
|
|
457
|
-
...input.stepIndex !== void 0 ? { stepIndex: input.stepIndex } : {},
|
|
458
|
-
...input.parentStepName !== void 0 ? { parentStepName: input.parentStepName } : {},
|
|
459
|
-
...input.previousStepName !== void 0 ? { previousStepName: input.previousStepName } : {},
|
|
460
|
-
...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
|
|
461
|
-
...input.timestamp !== void 0 ? { timestamp: input.timestamp } : {}
|
|
462
|
-
}, policyId);
|
|
463
|
-
const payloadBytes = canonicalizeReceiptBody(body);
|
|
464
|
-
const pae = buildPae(PAYLOAD_TYPE, base64Encode(payloadBytes));
|
|
465
|
-
const sig = await signer.sign(pae);
|
|
466
|
-
return encodeEnvelope({
|
|
467
|
-
payloadBytes,
|
|
468
|
-
signatures: [{
|
|
469
|
-
keyid: signer.kid,
|
|
470
|
-
sig
|
|
471
|
-
}]
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
//#endregion
|
|
475
141
|
//#region src/contract/checkpoint.ts
|
|
476
142
|
/**
|
|
477
143
|
* The tracer event name Lattice's checkpoint hook emits per step transition.
|
|
@@ -588,34 +254,89 @@ function extractReceiptId(envelope) {
|
|
|
588
254
|
}
|
|
589
255
|
}
|
|
590
256
|
//#endregion
|
|
591
|
-
//#region src/
|
|
257
|
+
//#region src/runtime/survivability.ts
|
|
592
258
|
/**
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
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.
|
|
600
269
|
*/
|
|
601
|
-
function
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
const maybeToJson = schema.toJSONSchema;
|
|
606
|
-
if (typeof maybeToJson === "function") try {
|
|
607
|
-
return maybeToJson();
|
|
608
|
-
} catch {}
|
|
609
|
-
return {
|
|
610
|
-
$comment: `standard-schema vendor: ${vendor.vendor}; toJSONSchema not available`,
|
|
611
|
-
type: "object"
|
|
612
|
-
};
|
|
613
|
-
}
|
|
270
|
+
function createNoopSurvivabilityAdapter(options = {}) {
|
|
271
|
+
const id = options.id ?? "noop-survivability";
|
|
272
|
+
const defaultPolicy = options.policy ?? "SAFE";
|
|
273
|
+
const hooks = /* @__PURE__ */ new Set();
|
|
614
274
|
return {
|
|
615
|
-
|
|
616
|
-
|
|
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
|
+
}
|
|
617
300
|
};
|
|
618
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;
|
|
619
340
|
/**
|
|
620
341
|
* Builds the prompt-reencoded tool-use protocol handle for any provider.
|
|
621
342
|
*
|
|
@@ -689,281 +410,6 @@ function formatToolsForProvider(providerName, tools, options = {}) {
|
|
|
689
410
|
mode: "prompt-reencoded"
|
|
690
411
|
};
|
|
691
412
|
}
|
|
692
|
-
function parseToolUseEnvelope(responseText) {
|
|
693
|
-
if (typeof responseText !== "string" || responseText.length === 0) return null;
|
|
694
|
-
const candidates = extractJsonCandidates(responseText);
|
|
695
|
-
for (const candidate of candidates) {
|
|
696
|
-
const parsed = tryParseEnvelope(candidate);
|
|
697
|
-
if (parsed !== null) return parsed;
|
|
698
|
-
}
|
|
699
|
-
return null;
|
|
700
|
-
}
|
|
701
|
-
/**
|
|
702
|
-
* Extracts JSON-looking candidate substrings from a response text.
|
|
703
|
-
*
|
|
704
|
-
* Models routinely wrap JSON in markdown code fences (```json ... ```),
|
|
705
|
-
* prepend explanatory prose ("I'll call the search tool: { ... }"), or
|
|
706
|
-
* produce multiple JSON-shaped blobs. This extractor scans for plausible
|
|
707
|
-
* candidates ordered by likelihood.
|
|
708
|
-
*/
|
|
709
|
-
function extractJsonCandidates(text) {
|
|
710
|
-
const candidates = [];
|
|
711
|
-
const fenceRegex = /```(?:json)?\s*([\s\S]*?)```/g;
|
|
712
|
-
let fenceMatch;
|
|
713
|
-
while ((fenceMatch = fenceRegex.exec(text)) !== null) {
|
|
714
|
-
const inner = fenceMatch[1];
|
|
715
|
-
if (inner !== void 0) candidates.push(inner.trim());
|
|
716
|
-
}
|
|
717
|
-
const braceStart = text.indexOf("{");
|
|
718
|
-
const braceEnd = text.lastIndexOf("}");
|
|
719
|
-
if (braceStart !== -1 && braceEnd > braceStart) candidates.push(text.slice(braceStart, braceEnd + 1));
|
|
720
|
-
candidates.push(text.trim());
|
|
721
|
-
return candidates;
|
|
722
|
-
}
|
|
723
|
-
function tryParseEnvelope(jsonLike) {
|
|
724
|
-
let parsed;
|
|
725
|
-
try {
|
|
726
|
-
parsed = JSON.parse(jsonLike);
|
|
727
|
-
} catch {
|
|
728
|
-
return null;
|
|
729
|
-
}
|
|
730
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
731
|
-
const toolCalls = parsed["tool_calls"];
|
|
732
|
-
if (!Array.isArray(toolCalls) || toolCalls.length === 0) return null;
|
|
733
|
-
const requests = [];
|
|
734
|
-
for (const call of toolCalls) {
|
|
735
|
-
if (typeof call !== "object" || call === null) return null;
|
|
736
|
-
const callRecord = call;
|
|
737
|
-
const id = callRecord["id"];
|
|
738
|
-
const name = callRecord["name"];
|
|
739
|
-
const args = callRecord["args"];
|
|
740
|
-
if (typeof id !== "string" || typeof name !== "string") return null;
|
|
741
|
-
requests.push({
|
|
742
|
-
id,
|
|
743
|
-
name,
|
|
744
|
-
args
|
|
745
|
-
});
|
|
746
|
-
}
|
|
747
|
-
return requests;
|
|
748
|
-
}
|
|
749
|
-
//#endregion
|
|
750
|
-
//#region src/outputs/validate.ts
|
|
751
|
-
async function validateSchemaOutput(name, schema, value) {
|
|
752
|
-
const result = schema["~standard"].validate(value);
|
|
753
|
-
const validation = result instanceof Promise ? await result : result;
|
|
754
|
-
if (validation.issues) return {
|
|
755
|
-
ok: false,
|
|
756
|
-
issue: {
|
|
757
|
-
["output"]: name,
|
|
758
|
-
issues: validation.issues.map(normalizeIssue)
|
|
759
|
-
}
|
|
760
|
-
};
|
|
761
|
-
return {
|
|
762
|
-
ok: true,
|
|
763
|
-
value: validation.value
|
|
764
|
-
};
|
|
765
|
-
}
|
|
766
|
-
async function validateOutputMap(contracts, rawOutputs, plan) {
|
|
767
|
-
const outputs = {};
|
|
768
|
-
for (const [name, contract] of Object.entries(contracts)) {
|
|
769
|
-
const value = rawOutputs[name];
|
|
770
|
-
const issue = await validateOutput(name, contract, value);
|
|
771
|
-
if (!issue.ok) return {
|
|
772
|
-
ok: false,
|
|
773
|
-
error: {
|
|
774
|
-
kind: "validation",
|
|
775
|
-
message: `Invalid output "${name}".`,
|
|
776
|
-
["output"]: name,
|
|
777
|
-
issues: issue.issues
|
|
778
|
-
},
|
|
779
|
-
usage: {
|
|
780
|
-
promptTokens: 0,
|
|
781
|
-
completionTokens: 0,
|
|
782
|
-
costUsd: null
|
|
783
|
-
},
|
|
784
|
-
raw: rawOutputs,
|
|
785
|
-
partialOutputs: outputs,
|
|
786
|
-
plan
|
|
787
|
-
};
|
|
788
|
-
outputs[name] = issue.value;
|
|
789
|
-
}
|
|
790
|
-
return {
|
|
791
|
-
ok: true,
|
|
792
|
-
outputs,
|
|
793
|
-
artifacts: [],
|
|
794
|
-
usage: {
|
|
795
|
-
promptTokens: 0,
|
|
796
|
-
completionTokens: 0,
|
|
797
|
-
costUsd: null
|
|
798
|
-
},
|
|
799
|
-
plan
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
async function validateOutput(name, contract, value) {
|
|
803
|
-
if (contract === "text") {
|
|
804
|
-
if (typeof value !== "string") return {
|
|
805
|
-
ok: false,
|
|
806
|
-
issues: [{ message: "Expected text output to be a string." }]
|
|
807
|
-
};
|
|
808
|
-
return {
|
|
809
|
-
ok: true,
|
|
810
|
-
value
|
|
811
|
-
};
|
|
812
|
-
}
|
|
813
|
-
if (isStandardSchema(contract)) {
|
|
814
|
-
const result = await validateSchemaOutput(name, contract, value);
|
|
815
|
-
if (!result.ok) return {
|
|
816
|
-
ok: false,
|
|
817
|
-
issues: result.issue.issues
|
|
818
|
-
};
|
|
819
|
-
return {
|
|
820
|
-
ok: true,
|
|
821
|
-
value: result.value
|
|
822
|
-
};
|
|
823
|
-
}
|
|
824
|
-
if (contract.kind === "citations") {
|
|
825
|
-
if (!Array.isArray(value)) return {
|
|
826
|
-
ok: false,
|
|
827
|
-
issues: [{ message: "Expected citations output to be an array." }]
|
|
828
|
-
};
|
|
829
|
-
return {
|
|
830
|
-
ok: true,
|
|
831
|
-
value
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
if (contract.kind === "artifacts") {
|
|
835
|
-
if (!Array.isArray(value)) return {
|
|
836
|
-
ok: false,
|
|
837
|
-
issues: [{ message: "Expected artifacts output to be an array." }]
|
|
838
|
-
};
|
|
839
|
-
for (const item of value) {
|
|
840
|
-
if (!isArtifactRef(item)) return {
|
|
841
|
-
ok: false,
|
|
842
|
-
issues: [{ message: "Expected artifacts output item to be an artifact ref." }]
|
|
843
|
-
};
|
|
844
|
-
if (contract.artifactKind !== void 0 && item.kind !== contract.artifactKind) return {
|
|
845
|
-
ok: false,
|
|
846
|
-
issues: [{ message: `Expected artifacts output item kind to be "${contract.artifactKind}".` }]
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
return {
|
|
850
|
-
ok: true,
|
|
851
|
-
value: value.map(toArtifactRef)
|
|
852
|
-
};
|
|
853
|
-
}
|
|
854
|
-
return {
|
|
855
|
-
ok: false,
|
|
856
|
-
issues: [{ message: "Unsupported output contract." }]
|
|
857
|
-
};
|
|
858
|
-
}
|
|
859
|
-
function isStandardSchema(contract) {
|
|
860
|
-
if (typeof contract !== "object" || contract === null) return false;
|
|
861
|
-
return typeof contract["~standard"]?.validate === "function";
|
|
862
|
-
}
|
|
863
|
-
function normalizeIssue(issue) {
|
|
864
|
-
const path = issue.path?.map(normalizePathSegment).filter((segment) => segment !== void 0);
|
|
865
|
-
return {
|
|
866
|
-
message: issue.message,
|
|
867
|
-
...path !== void 0 && path.length > 0 ? { path } : {}
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
function normalizePathSegment(segment) {
|
|
871
|
-
if (typeof segment === "string" || typeof segment === "number" || typeof segment === "symbol") return segment;
|
|
872
|
-
return normalizePathKey(segment.key);
|
|
873
|
-
}
|
|
874
|
-
function normalizePathKey(key) {
|
|
875
|
-
return key;
|
|
876
|
-
}
|
|
877
|
-
//#endregion
|
|
878
|
-
//#region src/runtime/survivability.ts
|
|
879
|
-
/**
|
|
880
|
-
* Reference implementation of SurvivabilityAdapter<TState>. Records
|
|
881
|
-
* eviction events but does NOT persist; serialize / deserialize round-
|
|
882
|
-
* trip via JSON.stringify / JSON.parse. Analog to createFakeProvider
|
|
883
|
-
* in the providers/ module -- gives Lattice's vitest a complete shape-
|
|
884
|
-
* conformance target before the real (FSB-side) adapter ships in
|
|
885
|
-
* Plan 05-05.
|
|
886
|
-
*
|
|
887
|
-
* Per CONTEXT.md D-11 the noop adapter ships in Lattice (not FSB)
|
|
888
|
-
* because it covers the contract surface in Lattice's own test suite;
|
|
889
|
-
* FSB's real chrome.storage.session-backed adapter is glue layer.
|
|
890
|
-
*/
|
|
891
|
-
function createNoopSurvivabilityAdapter(options = {}) {
|
|
892
|
-
const id = options.id ?? "noop-survivability";
|
|
893
|
-
const defaultPolicy = options.policy ?? "SAFE";
|
|
894
|
-
const hooks = /* @__PURE__ */ new Set();
|
|
895
|
-
return {
|
|
896
|
-
kind: "survivability-adapter",
|
|
897
|
-
id,
|
|
898
|
-
serialize(state) {
|
|
899
|
-
return {
|
|
900
|
-
kind: "survivability-snapshot",
|
|
901
|
-
version: "lattice-survivability/v1",
|
|
902
|
-
payload: JSON.stringify(state ?? null),
|
|
903
|
-
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
904
|
-
};
|
|
905
|
-
},
|
|
906
|
-
deserialize(snapshot) {
|
|
907
|
-
return JSON.parse(snapshot.payload);
|
|
908
|
-
},
|
|
909
|
-
onEviction(hook) {
|
|
910
|
-
hooks.add(hook);
|
|
911
|
-
let unsubscribed = false;
|
|
912
|
-
return () => {
|
|
913
|
-
if (unsubscribed) return;
|
|
914
|
-
unsubscribed = true;
|
|
915
|
-
hooks.delete(hook);
|
|
916
|
-
};
|
|
917
|
-
},
|
|
918
|
-
async resume(_snapshot) {
|
|
919
|
-
return defaultPolicy;
|
|
920
|
-
}
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
//#endregion
|
|
924
|
-
//#region src/tools/tools.ts
|
|
925
|
-
function defineTool(definition) {
|
|
926
|
-
return {
|
|
927
|
-
kind: "tool",
|
|
928
|
-
...definition
|
|
929
|
-
};
|
|
930
|
-
}
|
|
931
|
-
async function runTool(tool, input, context = {}) {
|
|
932
|
-
const validation = await validateSchemaOutput(tool.name, tool.inputSchema, input);
|
|
933
|
-
if (!validation.ok) throw new Error(`Invalid input for tool "${tool.name}".`);
|
|
934
|
-
const callId = createToolCallId();
|
|
935
|
-
const output = await tool.execute(validation.value, context);
|
|
936
|
-
return {
|
|
937
|
-
callId,
|
|
938
|
-
toolName: tool.name,
|
|
939
|
-
artifact: artifact.toolResult(output, {
|
|
940
|
-
id: `artifact:tool-result:${tool.name}:${callId}`,
|
|
941
|
-
toolName: tool.name,
|
|
942
|
-
callId
|
|
943
|
-
})
|
|
944
|
-
};
|
|
945
|
-
}
|
|
946
|
-
async function importMcpTools(client, toolNames) {
|
|
947
|
-
const descriptors = await Promise.resolve(client.listTools?.() ?? []);
|
|
948
|
-
const allowed = toolNames === void 0 ? void 0 : new Set(toolNames);
|
|
949
|
-
return descriptors.filter((descriptor) => allowed === void 0 || allowed.has(descriptor.name)).map((descriptor) => defineTool({
|
|
950
|
-
name: descriptor.name,
|
|
951
|
-
...descriptor.description !== void 0 ? { description: descriptor.description } : {},
|
|
952
|
-
inputSchema: descriptor.inputSchema,
|
|
953
|
-
execute: async (input) => client.callTool({
|
|
954
|
-
name: descriptor.name,
|
|
955
|
-
arguments: input
|
|
956
|
-
})
|
|
957
|
-
}));
|
|
958
|
-
}
|
|
959
|
-
function toolArtifactRef(result) {
|
|
960
|
-
const { value: _value, ...ref } = result.artifact;
|
|
961
|
-
return ref;
|
|
962
|
-
}
|
|
963
|
-
function createToolCallId() {
|
|
964
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
965
|
-
return `${Date.now()}:${Math.random().toString(16).slice(2)}`;
|
|
966
|
-
}
|
|
967
413
|
//#endregion
|
|
968
414
|
//#region src/agent/host.ts
|
|
969
415
|
/**
|
|
@@ -1027,6 +473,7 @@ const ZERO_USAGE = {
|
|
|
1027
473
|
completionTokens: 0,
|
|
1028
474
|
costUsd: null
|
|
1029
475
|
};
|
|
476
|
+
const DEFAULT_AGENT_OUTPUTS = { answer: "text" };
|
|
1030
477
|
/**
|
|
1031
478
|
* Resolves the runtime's behaviour for a single `ai.runAgent(intent)` call.
|
|
1032
479
|
*
|
|
@@ -1072,6 +519,8 @@ async function runAgentInternal(intent, config = {}, internalOptions = {}) {
|
|
|
1072
519
|
content: intent.task
|
|
1073
520
|
}];
|
|
1074
521
|
const handle = formatToolsForProvider(providerName, intent.tools);
|
|
522
|
+
const outputContracts = intent.outputs ?? DEFAULT_AGENT_OUTPUTS;
|
|
523
|
+
const outputNames = Object.keys(outputContracts);
|
|
1075
524
|
const budget = intent.contract?.budget;
|
|
1076
525
|
const maxIterations = budget?.maxIterations ?? Number.POSITIVE_INFINITY;
|
|
1077
526
|
const maxWallTimeMs = budget?.maxWallTimeMs ?? Number.POSITIVE_INFINITY;
|
|
@@ -1165,7 +614,8 @@ async function runAgentInternal(intent, config = {}, internalOptions = {}) {
|
|
|
1165
614
|
const providerRequest = {
|
|
1166
615
|
task,
|
|
1167
616
|
artifacts: [],
|
|
1168
|
-
outputs:
|
|
617
|
+
outputs: outputNames,
|
|
618
|
+
outputContracts,
|
|
1169
619
|
...intent.policy !== void 0 ? { policy: intent.policy } : {}
|
|
1170
620
|
};
|
|
1171
621
|
response = host.transport !== void 0 ? await host.transport.call(provider, providerRequest) : await provider.execute(providerRequest);
|
|
@@ -1211,10 +661,20 @@ async function runAgentInternal(intent, config = {}, internalOptions = {}) {
|
|
|
1211
661
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1212
662
|
previousStepName: `agent-iteration-${iterationIndex}-before`
|
|
1213
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
|
+
});
|
|
1214
672
|
await host.storage?.clear();
|
|
673
|
+
const artifactRefs = response.artifactRefs !== void 0 ? response.artifactRefs.map(toArtifactRef) : [];
|
|
1215
674
|
return {
|
|
1216
675
|
kind: "success",
|
|
1217
|
-
output:
|
|
676
|
+
output: outputValidation.outputs,
|
|
677
|
+
...artifactRefs.length > 0 ? { artifacts: artifactRefs } : {},
|
|
1218
678
|
usage: snapshotUsage(cumulativeUsage),
|
|
1219
679
|
iterations: Object.freeze([...iterations])
|
|
1220
680
|
};
|
|
@@ -1384,6 +844,6 @@ function stableHash(input) {
|
|
|
1384
844
|
}
|
|
1385
845
|
}
|
|
1386
846
|
//#endregion
|
|
1387
|
-
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 };
|
|
1388
848
|
|
|
1389
|
-
//# sourceMappingURL=runtime-
|
|
849
|
+
//# sourceMappingURL=runtime-Dxiet5YS.js.map
|