@actuarial-ts/agents 0.14.0 → 0.16.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"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"}
package/dist/review.js ADDED
@@ -0,0 +1,674 @@
1
+ /**
2
+ * Trusted agent boundary for a complete analytical review.
3
+ *
4
+ * The model can select only opaque identifiers from a host-owned catalog. It
5
+ * cannot author a plan, formula, source location, financial definition, input
6
+ * payload or tenant id. The host resolves those identifiers, performs the
7
+ * calculation, and returns a current-process VerifiedReviewSnapshot together
8
+ * with an exact scope receipt. This module validates that receipt before
9
+ * projecting review evidence back to the model.
10
+ *
11
+ * Manual priors, factor overrides, selections, waivers and adopted ranges are
12
+ * separate judgment gates. They reuse createJudgmentChain so every adopted
13
+ * decision suspends, requires a rationale, reads actor identity from trusted
14
+ * request context and enters the compliance ledger.
15
+ */
16
+ import { canonicalJson, fnv1a64, isDiagnosticToken, } from "@actuarial-ts/core";
17
+ import { analysisReferenceSchema } from "@actuarial-ts/data";
18
+ import { assertVerifiedReviewSnapshot, reviewEvidenceLinkSchema, } from "@actuarial-ts/compliance";
19
+ import { z } from "zod";
20
+ import { AgentsError } from "./errors.js";
21
+ import { createJudgmentChain, } from "./judgment.js";
22
+ import { defineActuarialTool, tenantOf, } from "./tools.js";
23
+ // ---------------------------------------------------------------------------
24
+ // Public limits and schemas
25
+ export const REVIEW_AGENT_LIMITS = Object.freeze({
26
+ maximumPresets: 64,
27
+ maximumMethods: 64,
28
+ maximumAssumptions: 256,
29
+ maximumOptions: 128,
30
+ maximumJudgments: 128,
31
+ maximumCandidatesPerJudgment: 128,
32
+ maximumEligibilityItems: 640,
33
+ maximumReasonCodes: 64,
34
+ maximumAffectedCoordinates: 1_000,
35
+ maximumRemedies: 64,
36
+ maximumTextCharacters: 20_000,
37
+ });
38
+ const token = z
39
+ .string()
40
+ .max(REVIEW_AGENT_LIMITS.maximumTextCharacters)
41
+ .refine(isDiagnosticToken);
42
+ const tag = z.string().regex(/^fnv1a64-jcs-v1:[0-9a-f]{16}$/);
43
+ const text = z
44
+ .string()
45
+ .max(REVIEW_AGENT_LIMITS.maximumTextCharacters)
46
+ .refine((value) => value.trim().length > 0, "Expected nonblank text");
47
+ const uniqueTokens = (maximum, minimum = 0) => z
48
+ .array(token)
49
+ .min(minimum)
50
+ .max(maximum)
51
+ .refine((values) => new Set(values).size === values.length, {
52
+ message: "Identifiers must be distinct",
53
+ });
54
+ export const reviewAgentDiscoveryInputSchema = z
55
+ .object({ runPresetId: token })
56
+ .strict();
57
+ export const reviewAgentExecutionInputSchema = z
58
+ .object({
59
+ runPresetId: token,
60
+ planId: token,
61
+ inputId: token,
62
+ methodIds: uniqueTokens(REVIEW_AGENT_LIMITS.maximumMethods, 1),
63
+ assumptionIds: uniqueTokens(REVIEW_AGENT_LIMITS.maximumAssumptions),
64
+ optionIds: uniqueTokens(REVIEW_AGENT_LIMITS.maximumOptions),
65
+ })
66
+ .strict();
67
+ export const REVIEW_AGENT_ELIGIBILITY_STATUSES = [
68
+ "supported",
69
+ "supported-with-warnings",
70
+ "requires-input",
71
+ "unsupported",
72
+ ];
73
+ export const REVIEW_AGENT_SUBJECT_KINDS = [
74
+ "plan",
75
+ "input",
76
+ "method",
77
+ "assumption",
78
+ "option",
79
+ ];
80
+ export const reviewAgentEligibilitySchema = z
81
+ .object({
82
+ kind: z.enum(REVIEW_AGENT_SUBJECT_KINDS),
83
+ id: token,
84
+ status: z.enum(REVIEW_AGENT_ELIGIBILITY_STATUSES),
85
+ reasonCodes: uniqueTokens(REVIEW_AGENT_LIMITS.maximumReasonCodes),
86
+ affectedCoordinates: z
87
+ .array(text)
88
+ .max(REVIEW_AGENT_LIMITS.maximumAffectedCoordinates),
89
+ remedies: z.array(text).max(REVIEW_AGENT_LIMITS.maximumRemedies),
90
+ })
91
+ .strict();
92
+ export const REVIEW_AGENT_JUDGMENT_KINDS = [
93
+ "manual-prior",
94
+ "factor-override",
95
+ "manual-selection",
96
+ "requirement-waiver",
97
+ "adopted-range",
98
+ ];
99
+ // ---------------------------------------------------------------------------
100
+ // Result contracts
101
+ const failureSchema = z
102
+ .object({
103
+ success: z.literal(false),
104
+ error: z.object({ code: z.string(), message: z.string() }).strict(),
105
+ })
106
+ .strict();
107
+ const catalogItemSchema = z.object({ id: token, label: text }).strict();
108
+ const methodSchema = catalogItemSchema
109
+ .extend({ nodeId: token, operation: token })
110
+ .strict();
111
+ const judgmentDescriptorSchema = z
112
+ .object({
113
+ id: token,
114
+ kind: z.enum(REVIEW_AGENT_JUDGMENT_KINDS),
115
+ targetId: token,
116
+ candidateIds: uniqueTokens(REVIEW_AGENT_LIMITS.maximumCandidatesPerJudgment),
117
+ })
118
+ .strict();
119
+ export const reviewAgentDiscoveryResultSchema = z.union([
120
+ z
121
+ .object({
122
+ success: z.literal(true),
123
+ data: z
124
+ .object({
125
+ runPresetId: token,
126
+ presetVersion: token,
127
+ label: text,
128
+ planId: token,
129
+ inputId: token,
130
+ profile: z.object({ id: token, version: token }).strict(),
131
+ methods: z.array(methodSchema).max(REVIEW_AGENT_LIMITS.maximumMethods),
132
+ assumptions: z
133
+ .array(catalogItemSchema)
134
+ .max(REVIEW_AGENT_LIMITS.maximumAssumptions),
135
+ options: z
136
+ .array(catalogItemSchema)
137
+ .max(REVIEW_AGENT_LIMITS.maximumOptions),
138
+ judgments: z
139
+ .array(judgmentDescriptorSchema)
140
+ .max(REVIEW_AGENT_LIMITS.maximumJudgments),
141
+ eligibility: z
142
+ .array(reviewAgentEligibilitySchema)
143
+ .max(REVIEW_AGENT_LIMITS.maximumEligibilityItems),
144
+ })
145
+ .strict(),
146
+ })
147
+ .strict(),
148
+ failureSchema,
149
+ ]);
150
+ const readinessCheckSchema = z
151
+ .object({
152
+ id: text,
153
+ status: z.enum(["satisfied", "unresolved", "waived", "not-applicable"]),
154
+ message: text,
155
+ node: text.nullable(),
156
+ coordinates: z.array(text).max(1_000),
157
+ evidence: z.array(reviewEvidenceLinkSchema).max(1_024).optional(),
158
+ facet: z.enum(["validation", "selection", "review"]).optional(),
159
+ })
160
+ .strict();
161
+ const readinessFacetsSchema = z
162
+ .object({
163
+ calculation: z.enum(["satisfied", "unresolved"]),
164
+ validation: z.enum(["satisfied", "unresolved", "not-applicable"]),
165
+ selection: z.enum(["satisfied", "unresolved", "not-applicable"]),
166
+ review: z.enum(["satisfied", "unresolved", "not-applicable"]),
167
+ externalRelease: z.literal("not-reported"),
168
+ })
169
+ .strict();
170
+ const readinessSchema = z
171
+ .object({
172
+ status: z.enum(["requirements-satisfied", "unresolved"]),
173
+ checks: z.array(readinessCheckSchema),
174
+ assurance: z.enum([
175
+ "declared-minimum-requirements-only",
176
+ "caller-defined-versioned-profile",
177
+ ]),
178
+ stage: z
179
+ .enum(["exploratory", "calculated", "validated", "selected", "published"])
180
+ .optional(),
181
+ facets: readinessFacetsSchema.optional(),
182
+ })
183
+ .strict();
184
+ export const reviewAgentExecutionResultSchema = z.union([
185
+ z
186
+ .object({
187
+ success: z.literal(true),
188
+ data: z
189
+ .object({
190
+ runPresetId: token,
191
+ presetVersion: token,
192
+ requestIdentity: tag,
193
+ planId: token,
194
+ inputId: token,
195
+ methodIds: z.array(token).max(REVIEW_AGENT_LIMITS.maximumMethods),
196
+ assumptionIds: z
197
+ .array(token)
198
+ .max(REVIEW_AGENT_LIMITS.maximumAssumptions),
199
+ optionIds: z.array(token).max(REVIEW_AGENT_LIMITS.maximumOptions),
200
+ snapshot: z
201
+ .object({
202
+ id: text,
203
+ version: text,
204
+ reference: analysisReferenceSchema,
205
+ profile: z.object({ id: text, version: text }).strict(),
206
+ readiness: readinessSchema,
207
+ limitations: z.array(z
208
+ .object({
209
+ id: text,
210
+ disposition: z.enum(["unresolved", "accepted"]),
211
+ })
212
+ .strict()),
213
+ findingCodes: z.array(text),
214
+ assurance: z
215
+ .object({
216
+ frozen: z.literal(true),
217
+ review: z.literal("not-attested"),
218
+ publication: z.literal("not-reported"),
219
+ })
220
+ .strict(),
221
+ })
222
+ .strict(),
223
+ })
224
+ .strict(),
225
+ })
226
+ .strict(),
227
+ failureSchema,
228
+ ]);
229
+ const presetMetadataSchema = z
230
+ .object({
231
+ id: token,
232
+ version: token,
233
+ label: text,
234
+ plan: z.object({ id: token, reference: analysisReferenceSchema }).strict(),
235
+ input: z.object({ id: token, reference: analysisReferenceSchema }).strict(),
236
+ profile: z.object({ id: token, version: token }).strict(),
237
+ methods: z
238
+ .array(methodSchema)
239
+ .min(1)
240
+ .max(REVIEW_AGENT_LIMITS.maximumMethods),
241
+ assumptions: z
242
+ .array(catalogItemSchema.extend({ reference: analysisReferenceSchema }).strict())
243
+ .max(REVIEW_AGENT_LIMITS.maximumAssumptions),
244
+ options: z
245
+ .array(catalogItemSchema)
246
+ .max(REVIEW_AGENT_LIMITS.maximumOptions),
247
+ judgments: z
248
+ .array(judgmentDescriptorSchema)
249
+ .max(REVIEW_AGENT_LIMITS.maximumJudgments),
250
+ })
251
+ .strict();
252
+ function distinct(values, message) {
253
+ if (new Set(values).size !== values.length)
254
+ throw new AgentsError("BAD_REVIEW_CATALOG", message);
255
+ }
256
+ function ownPreset(value) {
257
+ if (typeof value?.inspect !== "function" || typeof value?.execute !== "function")
258
+ throw new AgentsError("BAD_REVIEW_CATALOG", "Every review preset requires host inspect and execute functions");
259
+ const parsed = presetMetadataSchema.safeParse({
260
+ id: value.id,
261
+ version: value.version,
262
+ label: value.label,
263
+ plan: value.plan,
264
+ input: value.input,
265
+ profile: value.profile,
266
+ methods: value.methods,
267
+ assumptions: value.assumptions,
268
+ options: value.options,
269
+ judgments: value.judgments,
270
+ });
271
+ if (!parsed.success)
272
+ throw new AgentsError("BAD_REVIEW_CATALOG", `Invalid review preset: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
273
+ const metadata = parsed.data;
274
+ distinct(metadata.methods.map((item) => item.id), `Preset ${metadata.id} has duplicate method IDs`);
275
+ distinct(metadata.methods.map((item) => item.nodeId), `Preset ${metadata.id} maps two methods to one node`);
276
+ distinct(metadata.assumptions.map((item) => item.id), `Preset ${metadata.id} has duplicate assumption IDs`);
277
+ distinct(metadata.assumptions.map((item) => canonicalJson(item.reference)), `Preset ${metadata.id} maps more than one assumption ID to the same reference`);
278
+ distinct(metadata.options.map((item) => item.id), `Preset ${metadata.id} has duplicate option IDs`);
279
+ distinct(metadata.judgments.map((item) => item.id), `Preset ${metadata.id} has duplicate judgment IDs`);
280
+ for (const assumption of metadata.assumptions)
281
+ if (assumption.reference.kind !== "assumption")
282
+ throw new AgentsError("BAD_REVIEW_CATALOG", `Preset ${metadata.id} assumption ${assumption.id} must carry an assumption reference`);
283
+ if (metadata.plan.reference.kind !== "result")
284
+ throw new AgentsError("BAD_REVIEW_CATALOG", `Preset ${metadata.id} plan reference must be a result reference`);
285
+ return Object.freeze({
286
+ ...metadata,
287
+ methods: Object.freeze(metadata.methods.map((item) => Object.freeze(item))),
288
+ assumptions: Object.freeze(metadata.assumptions.map((item) => Object.freeze(item))),
289
+ options: Object.freeze(metadata.options.map((item) => Object.freeze(item))),
290
+ judgments: Object.freeze(metadata.judgments.map((item) => Object.freeze(item))),
291
+ inspect: value.inspect,
292
+ execute: value.execute,
293
+ });
294
+ }
295
+ function catalogOf(values) {
296
+ if (!Array.isArray(values) || values.length === 0 || values.length > REVIEW_AGENT_LIMITS.maximumPresets)
297
+ throw new AgentsError("BAD_REVIEW_CATALOG", "Review tools require a nonempty bounded preset catalog");
298
+ const result = new Map();
299
+ for (const raw of values) {
300
+ const preset = ownPreset(raw);
301
+ if (result.has(preset.id))
302
+ throw new AgentsError("BAD_REVIEW_CATALOG", `Duplicate review preset ${preset.id}`);
303
+ result.set(preset.id, preset);
304
+ }
305
+ return result;
306
+ }
307
+ function subjectKey(kind, id) {
308
+ return `${kind}\u0000${id}`;
309
+ }
310
+ function expectedSubjects(preset) {
311
+ return new Set([
312
+ subjectKey("plan", preset.plan.id),
313
+ subjectKey("input", preset.input.id),
314
+ ...preset.methods.map((item) => subjectKey("method", item.id)),
315
+ ...preset.assumptions.map((item) => subjectKey("assumption", item.id)),
316
+ ...preset.options.map((item) => subjectKey("option", item.id)),
317
+ ]);
318
+ }
319
+ async function inspectPreset(preset, tenantId) {
320
+ const parsed = z
321
+ .array(reviewAgentEligibilitySchema)
322
+ .max(REVIEW_AGENT_LIMITS.maximumEligibilityItems)
323
+ .safeParse(await preset.inspect({
324
+ tenantId,
325
+ runPresetId: preset.id,
326
+ presetVersion: preset.version,
327
+ }));
328
+ if (!parsed.success)
329
+ throw new AgentsError("REVIEW_ELIGIBILITY_MISMATCH", "Review preset returned malformed contextual eligibility");
330
+ const expected = expectedSubjects(preset);
331
+ const actual = parsed.data.map((item) => subjectKey(item.kind, item.id));
332
+ if (new Set(actual).size !== actual.length ||
333
+ actual.length !== expected.size ||
334
+ actual.some((key) => !expected.has(key)))
335
+ throw new AgentsError("REVIEW_ELIGIBILITY_MISMATCH", "Review preset must return exactly one eligibility outcome for every exposed item");
336
+ const kindOrder = new Map(REVIEW_AGENT_SUBJECT_KINDS.map((kind, index) => [kind, index]));
337
+ return [...parsed.data].sort((left, right) => kindOrder.get(left.kind) - kindOrder.get(right.kind) ||
338
+ left.id.localeCompare(right.id));
339
+ }
340
+ function sorted(values) {
341
+ return [...values].sort();
342
+ }
343
+ function exactMembers(left, right) {
344
+ return canonicalJson(sorted(left)) === canonicalJson(sorted(right));
345
+ }
346
+ function exactReference(left, right) {
347
+ return canonicalJson(left) === canonicalJson(right);
348
+ }
349
+ function requestIdentity(input) {
350
+ return `fnv1a64-jcs-v1:${fnv1a64(canonicalJson({
351
+ ...input,
352
+ methodIds: sorted(input.methodIds),
353
+ assumptionIds: sorted(input.assumptionIds),
354
+ optionIds: sorted(input.optionIds),
355
+ }))}`;
356
+ }
357
+ function selectedEligibility(eligibility, input) {
358
+ const selected = new Set([
359
+ subjectKey("plan", input.planId),
360
+ subjectKey("input", input.inputId),
361
+ ...input.methodIds.map((id) => subjectKey("method", id)),
362
+ ...input.assumptionIds.map((id) => subjectKey("assumption", id)),
363
+ ...input.optionIds.map((id) => subjectKey("option", id)),
364
+ ]);
365
+ return eligibility.filter((item) => selected.has(subjectKey(item.kind, item.id)));
366
+ }
367
+ function assertAllowedRequest(preset, input) {
368
+ if (input.planId !== preset.plan.id || input.inputId !== preset.input.id)
369
+ throw new AgentsError("REVIEW_REQUEST_MISMATCH", "The requested plan or input does not belong to the selected preset");
370
+ const allowedMethods = new Set(preset.methods.map((item) => item.id));
371
+ const allowedAssumptions = new Set(preset.assumptions.map((item) => item.id));
372
+ const allowedOptions = new Set(preset.options.map((item) => item.id));
373
+ if (input.methodIds.some((id) => !allowedMethods.has(id)))
374
+ throw new AgentsError("UNAPPROVED_REVIEW_METHOD", "One or more requested methods are not approved by the selected preset");
375
+ if (input.assumptionIds.some((id) => !allowedAssumptions.has(id)))
376
+ throw new AgentsError("UNAPPROVED_REVIEW_ASSUMPTION", "One or more requested assumptions are not approved by the selected preset");
377
+ if (input.optionIds.some((id) => !allowedOptions.has(id)))
378
+ throw new AgentsError("UNAPPROVED_REVIEW_OPTION", "One or more requested options are not approved by the selected preset");
379
+ }
380
+ function assertReceipt(preset, request, receipt) {
381
+ if (receipt === null || typeof receipt !== "object" || Array.isArray(receipt))
382
+ throw new AgentsError("REVIEW_EXECUTION_MISMATCH", "Review executor returned a malformed receipt");
383
+ const scopeField = Object.getOwnPropertyDescriptor(receipt, "scope");
384
+ const snapshotField = Object.getOwnPropertyDescriptor(receipt, "snapshot");
385
+ if (![Object.prototype, null].includes(Object.getPrototypeOf(receipt)) ||
386
+ Reflect.ownKeys(receipt).some((key) => typeof key !== "string" || !["scope", "snapshot"].includes(key)) ||
387
+ !scopeField?.enumerable ||
388
+ !("value" in scopeField) ||
389
+ !snapshotField?.enumerable ||
390
+ !("value" in snapshotField))
391
+ throw new AgentsError("REVIEW_EXECUTION_MISMATCH", "Review executor receipt must contain only scope and snapshot data fields");
392
+ const scope = z
393
+ .object({
394
+ tenantId: token,
395
+ runPresetId: token,
396
+ presetVersion: token,
397
+ requestIdentity: tag,
398
+ planId: token,
399
+ inputId: token,
400
+ methodIds: uniqueTokens(REVIEW_AGENT_LIMITS.maximumMethods, 1),
401
+ assumptionIds: uniqueTokens(REVIEW_AGENT_LIMITS.maximumAssumptions),
402
+ optionIds: uniqueTokens(REVIEW_AGENT_LIMITS.maximumOptions),
403
+ })
404
+ .strict()
405
+ .safeParse(scopeField.value);
406
+ if (!scope.success || canonicalJson(scope.data) !== canonicalJson(request))
407
+ throw new AgentsError("REVIEW_EXECUTION_MISMATCH", "Review executor result is bound to another tenant, request, definition or preset");
408
+ try {
409
+ assertVerifiedReviewSnapshot(snapshotField.value);
410
+ }
411
+ catch {
412
+ throw new AgentsError("REVIEW_EXECUTION_MISMATCH", "Review executor must return an authentic current-process verified snapshot");
413
+ }
414
+ const snapshot = snapshotField.value;
415
+ if (snapshot.profile.id !== preset.profile.id ||
416
+ snapshot.profile.version !== preset.profile.version ||
417
+ !exactReference(snapshot.run.document.analysisReview.run.plan.reference, preset.plan.reference))
418
+ throw new AgentsError("REVIEW_EXECUTION_MISMATCH", "Verified snapshot belongs to another review plan or profile");
419
+ const indexedReferences = snapshot.run.document.analysisReview.referenceIndex.definitions.map((entry) => entry.reference);
420
+ if (!indexedReferences.some((reference) => exactReference(reference, preset.input.reference)))
421
+ throw new AgentsError("REVIEW_EXECUTION_MISMATCH", "Verified snapshot does not contain the exact approved input reference");
422
+ const methods = request.methodIds.map((id) => preset.methods.find((item) => item.id === id));
423
+ const planNodes = snapshot.run.document.analysisReview.run.plan.plan.nodes;
424
+ if (methods.some((method) => !planNodes.some((node) => node.id === method.nodeId && node.operation === method.operation)))
425
+ throw new AgentsError("REVIEW_EXECUTION_MISMATCH", "Verified snapshot is missing an exact approved method node");
426
+ const requestedAssumptions = request.assumptionIds.map((id) => preset.assumptions.find((item) => item.id === id).reference);
427
+ if (!exactMembers(snapshot.profile.assumptions.map((reference) => canonicalJson(reference)), requestedAssumptions.map((reference) => canonicalJson(reference))))
428
+ throw new AgentsError("REVIEW_EXECUTION_MISMATCH", "Verified snapshot assumptions do not exactly match the approved request");
429
+ return snapshot;
430
+ }
431
+ /** Builds the paired read-only tools over one immutable host catalog. */
432
+ export function createReviewAgentTools(input) {
433
+ if (input === null || typeof input !== "object" || Array.isArray(input))
434
+ throw new AgentsError("BAD_REVIEW_CATALOG", "Review tool options must be an object");
435
+ for (const [name, value] of [
436
+ ["discoveryId", input.discoveryId],
437
+ ["executionId", input.executionId],
438
+ ["tenantContextKey", input.tenantContextKey],
439
+ ])
440
+ if (value !== undefined && !isDiagnosticToken(value))
441
+ throw new AgentsError("BAD_REVIEW_CATALOG", `Review tool ${name} must be a nonempty identifier when supplied`);
442
+ if (input.discoveryId !== undefined &&
443
+ input.executionId !== undefined &&
444
+ input.discoveryId === input.executionId)
445
+ throw new AgentsError("BAD_REVIEW_CATALOG", "Review discovery and execution tool IDs must differ");
446
+ const catalog = catalogOf(input.runPresets);
447
+ const tenantKey = input.tenantContextKey ?? "projectId";
448
+ const discover = defineActuarialTool({
449
+ id: input.discoveryId ?? "discover-approved-review",
450
+ description: "Discover one host-approved analytical review and its contextual eligibility",
451
+ kind: "read",
452
+ tenant: "required",
453
+ tenantKey,
454
+ inputSchema: reviewAgentDiscoveryInputSchema,
455
+ outputSchema: reviewAgentDiscoveryResultSchema,
456
+ execute: async (request, tenantId) => {
457
+ const preset = catalog.get(request.runPresetId);
458
+ if (!preset)
459
+ throw new AgentsError("UNKNOWN_REVIEW_PRESET", `Unknown review preset ${request.runPresetId}`);
460
+ const eligibility = await inspectPreset(preset, tenantId);
461
+ return {
462
+ success: true,
463
+ data: {
464
+ runPresetId: preset.id,
465
+ presetVersion: preset.version,
466
+ label: preset.label,
467
+ planId: preset.plan.id,
468
+ inputId: preset.input.id,
469
+ profile: preset.profile,
470
+ methods: preset.methods.map((item) => ({ ...item })),
471
+ assumptions: preset.assumptions.map(({ id, label }) => ({ id, label })),
472
+ options: preset.options.map((item) => ({ ...item })),
473
+ judgments: preset.judgments.map((item) => ({
474
+ ...item,
475
+ candidateIds: [...item.candidateIds],
476
+ })),
477
+ eligibility: [...eligibility],
478
+ },
479
+ };
480
+ },
481
+ });
482
+ const execute = defineActuarialTool({
483
+ id: input.executionId ?? "run-approved-review",
484
+ description: "Run a host-approved analytical review and return verified readiness evidence",
485
+ kind: "read",
486
+ tenant: "required",
487
+ tenantKey,
488
+ inputSchema: reviewAgentExecutionInputSchema,
489
+ outputSchema: reviewAgentExecutionResultSchema,
490
+ execute: async (raw, tenantId) => {
491
+ const preset = catalog.get(raw.runPresetId);
492
+ if (!preset)
493
+ throw new AgentsError("UNKNOWN_REVIEW_PRESET", `Unknown review preset ${raw.runPresetId}`);
494
+ assertAllowedRequest(preset, raw);
495
+ const eligibility = await inspectPreset(preset, tenantId);
496
+ const unavailable = selectedEligibility(eligibility, raw).filter((item) => item.status === "requires-input" || item.status === "unsupported");
497
+ if (unavailable.length > 0)
498
+ throw new AgentsError("REVIEW_NOT_ELIGIBLE", `Approved review cannot run because these selected items are ineligible: ${unavailable
499
+ .map((item) => `${item.kind}:${item.id}`)
500
+ .join(", ")}`);
501
+ const normalized = {
502
+ ...raw,
503
+ methodIds: sorted(raw.methodIds),
504
+ assumptionIds: sorted(raw.assumptionIds),
505
+ optionIds: sorted(raw.optionIds),
506
+ };
507
+ const executionInput = {
508
+ tenantId,
509
+ runPresetId: preset.id,
510
+ presetVersion: preset.version,
511
+ requestIdentity: requestIdentity(normalized),
512
+ planId: normalized.planId,
513
+ inputId: normalized.inputId,
514
+ methodIds: normalized.methodIds,
515
+ assumptionIds: normalized.assumptionIds,
516
+ optionIds: normalized.optionIds,
517
+ };
518
+ const receipt = await preset.execute(executionInput);
519
+ const snapshot = assertReceipt(preset, executionInput, receipt);
520
+ return {
521
+ success: true,
522
+ data: {
523
+ runPresetId: preset.id,
524
+ presetVersion: preset.version,
525
+ requestIdentity: executionInput.requestIdentity,
526
+ planId: preset.plan.id,
527
+ inputId: preset.input.id,
528
+ methodIds: [...executionInput.methodIds],
529
+ assumptionIds: [...executionInput.assumptionIds],
530
+ optionIds: [...executionInput.optionIds],
531
+ snapshot: {
532
+ id: snapshot.id,
533
+ version: snapshot.version,
534
+ reference: snapshot.reference,
535
+ profile: { id: snapshot.profile.id, version: snapshot.profile.version },
536
+ readiness: snapshot.readiness,
537
+ limitations: snapshot.limitations.map(({ id, disposition }) => ({
538
+ id,
539
+ disposition,
540
+ })),
541
+ findingCodes: [...new Set(snapshot.findings.map((item) => item.code))].sort(),
542
+ assurance: snapshot.assurance,
543
+ },
544
+ },
545
+ };
546
+ },
547
+ });
548
+ return Object.freeze({ discover, execute });
549
+ }
550
+ const judgmentDecisionSchema = z
551
+ .object({
552
+ decision: z.enum(["adopt", "decline"]),
553
+ candidateId: token.nullable(),
554
+ rationale: z.string(),
555
+ actor: z.enum(["actuary", "agent"]).optional(),
556
+ })
557
+ .strict();
558
+ function judgmentContext(gate, context, tenantKey) {
559
+ return {
560
+ tenantId: tenantOf({ requestContext: context.requestContext }, tenantKey),
561
+ presetId: gate.presetId,
562
+ presetVersion: gate.presetVersion,
563
+ gateId: gate.id,
564
+ kind: gate.kind,
565
+ targetId: gate.targetId,
566
+ decisions: context.decisions,
567
+ trail: context.trail,
568
+ };
569
+ }
570
+ /**
571
+ * Creates a resumable review-judgment workflow. The fixed schema admits only
572
+ * an allowlisted candidate ID and a documented adopt/decline decision. The
573
+ * wrapper always records the review judgment in the ledger, even when the
574
+ * host application has no additional assumption entries to append.
575
+ */
576
+ export function createReviewAgentJudgmentChain(input) {
577
+ if (input === null || typeof input !== "object" || Array.isArray(input))
578
+ throw new AgentsError("BAD_REVIEW_JUDGMENT_CATALOG", "Review judgment options must be an object");
579
+ const tenantKey = input.tenantContextKey ?? "projectId";
580
+ if (!isDiagnosticToken(input.id) ||
581
+ !isDiagnosticToken(tenantKey) ||
582
+ typeof input.now !== "function")
583
+ throw new AgentsError("BAD_REVIEW_JUDGMENT_CATALOG", "Review judgment chain requires an ID and host clock");
584
+ if (!Array.isArray(input.gates) || input.gates.length === 0 || input.gates.length > REVIEW_AGENT_LIMITS.maximumJudgments)
585
+ throw new AgentsError("BAD_REVIEW_JUDGMENT_CATALOG", "Review judgment chain requires a nonempty bounded gate list");
586
+ if (new Set(input.gates.map((gate) => gate?.id)).size !== input.gates.length)
587
+ throw new AgentsError("BAD_REVIEW_JUDGMENT_CATALOG", "Review judgment gate IDs must be distinct");
588
+ const gates = input.gates.map((gate) => {
589
+ const parsed = z
590
+ .object({
591
+ id: token,
592
+ stage: text,
593
+ presetId: token,
594
+ presetVersion: token,
595
+ kind: z.enum(REVIEW_AGENT_JUDGMENT_KINDS),
596
+ targetId: token,
597
+ allowedCandidateIds: uniqueTokens(REVIEW_AGENT_LIMITS.maximumCandidatesPerJudgment),
598
+ })
599
+ .strict()
600
+ .safeParse({
601
+ id: gate.id,
602
+ stage: gate.stage,
603
+ presetId: gate.presetId,
604
+ presetVersion: gate.presetVersion,
605
+ kind: gate.kind,
606
+ targetId: gate.targetId,
607
+ allowedCandidateIds: gate.allowedCandidateIds,
608
+ });
609
+ if (!parsed.success ||
610
+ typeof gate.gatherEvidence !== "function" ||
611
+ typeof gate.applyDecision !== "function")
612
+ throw new AgentsError("BAD_REVIEW_JUDGMENT_CATALOG", "Review judgment gates require valid metadata and host callbacks");
613
+ const owned = parsed.data;
614
+ return {
615
+ id: owned.id,
616
+ stage: owned.stage,
617
+ resumeSchema: judgmentDecisionSchema,
618
+ gatherEvidence: async (context) => gate.gatherEvidence(judgmentContext(gate, context, tenantKey)),
619
+ applyDecision: async (context, decision) => {
620
+ const adopting = decision.decision === "adopt";
621
+ if ((adopting &&
622
+ (decision.candidateId === null ||
623
+ !owned.allowedCandidateIds.includes(decision.candidateId))) ||
624
+ (!adopting && decision.candidateId !== null))
625
+ throw new AgentsError("UNAPPROVED_REVIEW_JUDGMENT", "Review judgment must adopt one approved candidate or decline without a candidate");
626
+ const trusted = judgmentContext(gate, context, tenantKey);
627
+ const application = await gate.applyDecision(trusted, decision);
628
+ const auditValue = {
629
+ presetId: owned.presetId,
630
+ presetVersion: owned.presetVersion,
631
+ kind: owned.kind,
632
+ targetId: owned.targetId,
633
+ decision: decision.decision,
634
+ candidateId: decision.candidateId,
635
+ };
636
+ return {
637
+ summary: application.summary ??
638
+ (adopting
639
+ ? `adopted ${decision.candidateId}`
640
+ : `declined ${owned.targetId}`),
641
+ ledgerEntries: [
642
+ {
643
+ field: `review.judgment.${owned.kind}.${owned.targetId}`,
644
+ value: auditValue,
645
+ source: `review-agent-gate:${owned.id}`,
646
+ },
647
+ ...(application.ledgerEntries ?? []),
648
+ ],
649
+ };
650
+ },
651
+ };
652
+ });
653
+ return createJudgmentChain({
654
+ id: input.id,
655
+ gates,
656
+ now: input.now,
657
+ onComplete: input.onComplete,
658
+ requestContextSchema: z.object({ [tenantKey]: z.string().min(1) }),
659
+ });
660
+ }
661
+ /** Ready-to-run offline eval cases for the default review tool IDs. */
662
+ export const REVIEW_AGENT_TOOL_SELECTION_CASES = Object.freeze([
663
+ {
664
+ id: "discover-approved-review",
665
+ prompt: "Show which approved review methods and assumptions are eligible before calculating anything.",
666
+ expectTools: ["discover-approved-review"],
667
+ },
668
+ {
669
+ id: "run-approved-review",
670
+ prompt: "Run the approved review I selected and return its verified readiness evidence.",
671
+ expectTools: ["run-approved-review"],
672
+ },
673
+ ]);
674
+ //# sourceMappingURL=review.js.map