@actuarial-ts/agents 0.6.0 → 0.7.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.
@@ -1,30 +1,530 @@
1
- import { assertCompiledDiagnosticDefinition } from "@actuarial-ts/core";
2
- import { assertVerifiedDiagnosticRunProvenance } from "@actuarial-ts/compliance";
1
+ import { assertCompiledDiagnosticDefinition, isDiagnosticToken, isDiagnosticPlainRecord, } from "@actuarial-ts/core";
2
+ import { assertVerifiedDiagnosticRunProvenance, } from "@actuarial-ts/compliance";
3
3
  import { z } from "zod";
4
4
  import { AgentsError } from "./errors.js";
5
- import { defineActuarialTool } from "./tools.js";
6
- export const diagnosticAgentToolInputSchema = z.object({
7
- runPresetId: z.string().min(1),
8
- instanceIds: z.array(z.string().min(1)).min(1),
5
+ import { defineActuarialTool, } from "./tools.js";
6
+ const tokenSchema = z.string().min(1).refine(isDiagnosticToken);
7
+ const selectedInstanceIdsSchema = z
8
+ .array(tokenSchema)
9
+ .min(1);
10
+ export const diagnosticAgentToolInputSchema = z
11
+ .object({
12
+ runPresetId: tokenSchema,
13
+ instanceIds: selectedInstanceIdsSchema,
9
14
  view: z.enum(["emergence", "triangles", "latest-diagonal"]),
10
- }).strict();
11
- const toolFailureSchema = z.object({ success: z.literal(false), error: z.object({ code: z.string(), message: z.string() }).strict() }).strict();
15
+ })
16
+ .strict();
17
+ const toolFailureSchema = z
18
+ .object({
19
+ success: z.literal(false),
20
+ error: z.object({ code: z.string(), message: z.string() }).strict(),
21
+ })
22
+ .strict();
23
+ const tagSchema = z.string().regex(/^fnv1a64-jcs-v1:[0-9a-f]{16}$/);
24
+ const finiteNullable = z.number().finite().nullable();
25
+ /** Zod 3 drops an own `__proto__` key when assembling records. Encode every
26
+ * key during validation and decode only after its value has been validated. */
27
+ function recordSchema(valueSchema) {
28
+ return z
29
+ .record(z.string().transform((key) => `:${key}`), valueSchema)
30
+ .transform((record) => Object.fromEntries(Object.entries(record).map(([key, value]) => [key.slice(1), value])));
31
+ }
32
+ const jsonSchema = z.lazy(() => z.union([
33
+ z.string(),
34
+ z.number().finite(),
35
+ z.boolean(),
36
+ z.null(),
37
+ z.array(jsonSchema),
38
+ recordSchema(jsonSchema),
39
+ ]));
40
+ const sourceSchema = z
41
+ .object({
42
+ artifactId: tokenSchema,
43
+ sourceFile: tokenSchema.optional(),
44
+ sourceSheet: tokenSchema.optional(),
45
+ sourceRow: z.number().int().nonnegative().optional(),
46
+ sourceCell: tokenSchema.optional(),
47
+ })
48
+ .strict();
49
+ const quantitySchema = z
50
+ .object({
51
+ kind: z.enum(["amount", "count", "exposure"]),
52
+ unit: tokenSchema,
53
+ basisId: tokenSchema.optional(),
54
+ countPopulationId: tokenSchema.optional(),
55
+ exposureBasisId: tokenSchema.optional(),
56
+ value: finiteNullable,
57
+ })
58
+ .strict();
59
+ const statsSchema = z
60
+ .object({
61
+ sum: finiteNullable,
62
+ value: finiteNullable,
63
+ observed: z.number().int().nonnegative(),
64
+ missing: z.number().int().nonnegative(),
65
+ imputedZero: z.number().int().nonnegative(),
66
+ nonFinite: z.number().int().nonnegative(),
67
+ structural: z.number().int().nonnegative(),
68
+ deduplicated: z.number().int().nonnegative(),
69
+ })
70
+ .strict();
71
+ const findingSchema = z
72
+ .object({
73
+ code: tokenSchema,
74
+ message: z.string().min(1),
75
+ severity: z.enum(["info", "warning", "fail"]),
76
+ category: z.enum([
77
+ "structural",
78
+ "aggregation",
79
+ "calculation",
80
+ "rule",
81
+ "presentation",
82
+ ]),
83
+ ruleId: tokenSchema.optional(),
84
+ measureId: tokenSchema.optional(),
85
+ instanceId: tokenSchema.optional(),
86
+ expressionPath: z.string().optional(),
87
+ offendingKey: z.string().optional(),
88
+ sourceGroup: tokenSchema.optional(),
89
+ group: tokenSchema.optional(),
90
+ origin: tokenSchema.optional(),
91
+ valuation: tokenSchema.optional(),
92
+ developmentAge: z.number().int().nonnegative().optional(),
93
+ ageUnit: tokenSchema.optional(),
94
+ recordId: tokenSchema.optional(),
95
+ claimId: tokenSchema.optional(),
96
+ exposureKey: tokenSchema.optional(),
97
+ sources: z.array(sourceSchema),
98
+ })
99
+ .strict();
100
+ const overflowSchema = z
101
+ .object({ expressionPath: z.string(), sources: z.array(sourceSchema) })
102
+ .strict();
103
+ const metricRuleSchema = z
104
+ .object({
105
+ ruleId: tokenSchema,
106
+ status: z.enum(["pass", "triggered", "not-evaluated"]),
107
+ severity: z.enum(["warning", "fail"]),
108
+ left: finiteNullable,
109
+ right: finiteNullable,
110
+ relation: z.enum(["less", "equal", "greater"]).nullable(),
111
+ notEvaluatedReasons: z.array(z.enum([
112
+ "missing",
113
+ "imputed",
114
+ "non-finite",
115
+ "structural-ambiguity",
116
+ "aggregation-overflow",
117
+ "expression-overflow",
118
+ "tolerance-overflow",
119
+ ])),
120
+ expressionOverflows: z.array(overflowSchema),
121
+ code: z.string().nullable(),
122
+ message: z.string().nullable(),
123
+ })
124
+ .strict();
125
+ const presentationSchema = z
126
+ .object({
127
+ displayName: z.string().min(1),
128
+ description: z.string().min(1),
129
+ displayUnit: tokenSchema,
130
+ scale: z.number().finite().positive(),
131
+ numeratorLabel: z.string().min(1),
132
+ denominatorLabel: z.string().min(1),
133
+ value: finiteNullable,
134
+ })
135
+ .strict();
136
+ const evaluationSchema = z
137
+ .object({
138
+ instanceId: tokenSchema,
139
+ instanceVersion: tokenSchema,
140
+ formulaId: tokenSchema,
141
+ formulaVersion: tokenSchema,
142
+ semanticReferences: z
143
+ .object({
144
+ amountBasisIds: z.array(tokenSchema),
145
+ countPopulationIds: z.array(tokenSchema),
146
+ exposureBasisIds: z.array(tokenSchema),
147
+ })
148
+ .strict(),
149
+ formulaFingerprint: tagSchema,
150
+ calculationFingerprint: tagSchema,
151
+ definitionIntegrity: tagSchema,
152
+ calculation: z
153
+ .object({
154
+ numerator: quantitySchema,
155
+ denominator: quantitySchema,
156
+ value: finiteNullable,
157
+ })
158
+ .strict(),
159
+ presentation: presentationSchema,
160
+ components: recordSchema(statsSchema),
161
+ rules: z.array(metricRuleSchema),
162
+ findings: z.array(findingSchema),
163
+ })
164
+ .strict();
165
+ const pointSchema = z
166
+ .object({
167
+ group: tokenSchema,
168
+ sourceGroups: z.array(tokenSchema),
169
+ dimensions: jsonSchema.optional(),
170
+ origin: tokenSchema,
171
+ valuation: tokenSchema,
172
+ developmentAge: z.number().int().nonnegative(),
173
+ ageUnit: tokenSchema,
174
+ components: recordSchema(statsSchema),
175
+ metrics: recordSchema(evaluationSchema),
176
+ findings: z.array(findingSchema),
177
+ })
178
+ .strict();
179
+ const triangleCellSchema = z
180
+ .object({
181
+ origin: tokenSchema,
182
+ valuation: tokenSchema,
183
+ developmentAge: z.number().int().nonnegative(),
184
+ ageUnit: tokenSchema,
185
+ evaluation: evaluationSchema,
186
+ })
187
+ .strict();
188
+ const triangleSchema = z
189
+ .object({
190
+ group: tokenSchema,
191
+ instanceId: tokenSchema,
192
+ origins: z.array(tokenSchema),
193
+ developmentAges: z.array(z.number().int().nonnegative()),
194
+ ageUnit: tokenSchema,
195
+ calculationValues: z.array(z.array(finiteNullable)),
196
+ presentationValues: z.array(z.array(finiteNullable)),
197
+ cells: z.array(z.array(triangleCellSchema.nullable())),
198
+ })
199
+ .strict();
200
+ const reviewCoordinateSchema = z
201
+ .object({
202
+ sourceGroup: tokenSchema,
203
+ origin: tokenSchema,
204
+ valuation: tokenSchema,
205
+ developmentAge: z.number().int().nonnegative().safe(),
206
+ ageUnit: tokenSchema,
207
+ })
208
+ .strict();
209
+ const cellReviewScopeSchema = z
210
+ .object({
211
+ kind: z.literal("cell"),
212
+ cell: reviewCoordinateSchema,
213
+ sources: z.array(sourceSchema),
214
+ })
215
+ .strict();
216
+ const pairReviewScopeSchema = z
217
+ .object({
218
+ kind: z.literal("valuation-pair"),
219
+ previous: reviewCoordinateSchema,
220
+ current: reviewCoordinateSchema,
221
+ sources: z.array(sourceSchema),
222
+ })
223
+ .strict();
224
+ const controlReviewScopeSchema = z
225
+ .object({
226
+ kind: z.literal("control-total"),
227
+ projection: z.discriminatedUnion("kind", [
228
+ z
229
+ .object({ kind: z.literal("valuation"), valuation: tokenSchema })
230
+ .strict(),
231
+ z.object({ kind: z.literal("latest-valuation-per-origin") }).strict(),
232
+ z.object({ kind: z.literal("all-cells") }).strict(),
233
+ ]),
234
+ filter: z
235
+ .object({
236
+ sourceGroups: z.array(tokenSchema).nullable(),
237
+ origins: z.array(tokenSchema).nullable(),
238
+ originFrom: tokenSchema.nullable(),
239
+ originThrough: tokenSchema.nullable(),
240
+ valuations: z.array(tokenSchema).nullable(),
241
+ valuationFrom: tokenSchema.nullable(),
242
+ valuationThrough: tokenSchema.nullable(),
243
+ minDevelopmentAge: z.number().int().nonnegative().safe().nullable(),
244
+ maxDevelopmentAge: z.number().int().nonnegative().safe().nullable(),
245
+ })
246
+ .strict()
247
+ .nullable(),
248
+ selectedCellCount: z.number().int().nonnegative().safe(),
249
+ selectedContributionCount: z.number().int().nonnegative().safe(),
250
+ sources: z.array(sourceSchema),
251
+ })
252
+ .strict();
253
+ const reviewScopeSchema = z.discriminatedUnion("kind", [
254
+ cellReviewScopeSchema,
255
+ pairReviewScopeSchema,
256
+ controlReviewScopeSchema,
257
+ ]);
258
+ const dataFindingContextSchema = z
259
+ .object({
260
+ ruleId: tokenSchema.optional(),
261
+ measureId: tokenSchema.optional(),
262
+ expressionPath: z.string().optional(),
263
+ offendingKey: z.string().optional(),
264
+ groupingKey: tokenSchema.optional(),
265
+ cachedEvidenceId: tokenSchema.optional(),
266
+ sourceGroup: tokenSchema.optional(),
267
+ origin: tokenSchema.optional(),
268
+ valuation: tokenSchema.optional(),
269
+ developmentAge: z.number().int().nonnegative().safe().optional(),
270
+ ageUnit: tokenSchema.optional(),
271
+ recordId: tokenSchema.optional(),
272
+ claimId: tokenSchema.optional(),
273
+ exposureKey: tokenSchema.optional(),
274
+ group: tokenSchema.optional(),
275
+ sourceFile: tokenSchema.optional(),
276
+ sourceRow: z.number().int().nonnegative().safe().optional(),
277
+ sources: z.array(sourceSchema).optional(),
278
+ reviewScope: reviewScopeSchema.optional(),
279
+ })
280
+ .strict();
281
+ const dataFindingSchema = z
282
+ .object({
283
+ code: tokenSchema,
284
+ message: z.string(),
285
+ context: dataFindingContextSchema.optional(),
286
+ })
287
+ .strict();
288
+ const reviewEvaluationBaseSchema = z
289
+ .object({
290
+ ruleId: tokenSchema,
291
+ status: z.enum(["pass", "triggered", "not-evaluated"]),
292
+ severity: z.enum(["warning", "fail"]),
293
+ triggerReason: z
294
+ .enum([
295
+ "predicate",
296
+ "missing-input",
297
+ "aggregation-overflow",
298
+ "expression-overflow",
299
+ "tolerance-overflow",
300
+ ])
301
+ .nullable(),
302
+ left: finiteNullable,
303
+ right: finiteNullable,
304
+ relation: z.enum(["less", "equal", "greater"]).nullable(),
305
+ notEvaluatedReasons: metricRuleSchema.shape.notEvaluatedReasons,
306
+ expressionOverflows: z.array(overflowSchema.extend({ coordinate: reviewCoordinateSchema.nullable() })),
307
+ })
308
+ .strict();
309
+ const comparabilitySchema = z.discriminatedUnion("kind", [
310
+ z.object({ kind: z.literal("compiler-proven") }).strict(),
311
+ z
312
+ .object({
313
+ kind: z.literal("caller-asserted"),
314
+ rationaleArtifactId: tokenSchema,
315
+ })
316
+ .strict(),
317
+ ]);
318
+ const reviewEvaluationSchema = z.discriminatedUnion("ruleKind", [
319
+ reviewEvaluationBaseSchema.extend({
320
+ ruleKind: z.literal("compare"),
321
+ scope: cellReviewScopeSchema,
322
+ }),
323
+ reviewEvaluationBaseSchema.extend({
324
+ ruleKind: z.literal("reconcile"),
325
+ scope: cellReviewScopeSchema,
326
+ }),
327
+ reviewEvaluationBaseSchema.extend({
328
+ ruleKind: z.literal("monotonic"),
329
+ scope: pairReviewScopeSchema,
330
+ }),
331
+ reviewEvaluationBaseSchema.extend({
332
+ ruleKind: z.literal("control-total"),
333
+ scope: controlReviewScopeSchema,
334
+ }),
335
+ reviewEvaluationBaseSchema.extend({
336
+ ruleKind: z.literal("layer-order"),
337
+ scope: cellReviewScopeSchema,
338
+ comparability: comparabilitySchema,
339
+ }),
340
+ ]);
341
+ const reviewSchemaBase = z
342
+ .object({
343
+ definitionIntegrity: tagSchema,
344
+ preparationFingerprint: tagSchema,
345
+ report: z
346
+ .object({
347
+ checks: z.array(z
348
+ .object({
349
+ id: tokenSchema,
350
+ description: z.string(),
351
+ status: z.enum(["pass", "warning", "fail", "not-evaluated"]),
352
+ details: z.array(z.string()),
353
+ findings: z.array(dataFindingSchema),
354
+ })
355
+ .strict()),
356
+ summary: z
357
+ .object({
358
+ pass: z.number().int().nonnegative(),
359
+ warning: z.number().int().nonnegative(),
360
+ fail: z.number().int().nonnegative(),
361
+ notEvaluated: z.number().int().nonnegative(),
362
+ })
363
+ .strict(),
364
+ })
365
+ .strict(),
366
+ evaluations: z.array(reviewEvaluationSchema),
367
+ evidence: z
368
+ .object({
369
+ groupingAssignments: z.array(z
370
+ .object({
371
+ key: tokenSchema,
372
+ group: tokenSchema,
373
+ source: sourceSchema.optional(),
374
+ })
375
+ .strict()),
376
+ cachedFormulas: z.array(z
377
+ .object({
378
+ id: tokenSchema,
379
+ source: sourceSchema.optional(),
380
+ formula: z.string().optional(),
381
+ cachedValue: finiteNullable.optional(),
382
+ declaredFormulaSource: z.boolean(),
383
+ })
384
+ .strict()),
385
+ })
386
+ .strict()
387
+ .nullable(),
388
+ reportFingerprint: tagSchema,
389
+ })
390
+ .strict();
391
+ const normalizedSourceSchema = sourceSchema.extend({
392
+ sourceFile: tokenSchema.nullable(),
393
+ sourceSheet: tokenSchema.nullable(),
394
+ sourceRow: z.number().int().nonnegative().safe().nullable(),
395
+ sourceCell: tokenSchema.nullable(),
396
+ });
397
+ const normalizedSourcesSchema = z.array(normalizedSourceSchema);
398
+ const normalizedCellScopeSchema = cellReviewScopeSchema.extend({
399
+ sources: normalizedSourcesSchema,
400
+ });
401
+ const normalizedPairScopeSchema = pairReviewScopeSchema.extend({
402
+ sources: normalizedSourcesSchema,
403
+ });
404
+ const normalizedControlScopeSchema = controlReviewScopeSchema.extend({
405
+ sources: normalizedSourcesSchema,
406
+ });
407
+ const normalizedScopeSchema = z.discriminatedUnion("kind", [
408
+ normalizedCellScopeSchema,
409
+ normalizedPairScopeSchema,
410
+ normalizedControlScopeSchema,
411
+ ]);
412
+ const normalizedReviewEvaluationBaseSchema = reviewEvaluationBaseSchema.extend({
413
+ expressionOverflows: z.array(overflowSchema.extend({
414
+ sources: normalizedSourcesSchema,
415
+ coordinate: reviewCoordinateSchema.nullable(),
416
+ })),
417
+ });
418
+ const normalizedReviewEvaluationSchema = z.discriminatedUnion("ruleKind", [
419
+ normalizedReviewEvaluationBaseSchema.extend({
420
+ ruleKind: z.literal("compare"),
421
+ scope: normalizedCellScopeSchema,
422
+ }),
423
+ normalizedReviewEvaluationBaseSchema.extend({
424
+ ruleKind: z.literal("reconcile"),
425
+ scope: normalizedCellScopeSchema,
426
+ }),
427
+ normalizedReviewEvaluationBaseSchema.extend({
428
+ ruleKind: z.literal("monotonic"),
429
+ scope: normalizedPairScopeSchema,
430
+ }),
431
+ normalizedReviewEvaluationBaseSchema.extend({
432
+ ruleKind: z.literal("control-total"),
433
+ scope: normalizedControlScopeSchema,
434
+ }),
435
+ normalizedReviewEvaluationBaseSchema.extend({
436
+ ruleKind: z.literal("layer-order"),
437
+ scope: normalizedCellScopeSchema,
438
+ comparability: comparabilitySchema,
439
+ }),
440
+ ]);
441
+ const normalizedFindingSchema = dataFindingSchema.extend({
442
+ context: dataFindingContextSchema
443
+ .extend({
444
+ sources: normalizedSourcesSchema.optional(),
445
+ reviewScope: normalizedScopeSchema.optional(),
446
+ })
447
+ .optional(),
448
+ });
449
+ const evidenceShape = reviewSchemaBase.shape.evidence.unwrap().shape;
450
+ const normalizedEvidenceSchema = z
451
+ .object({
452
+ groupingAssignments: z.array(evidenceShape.groupingAssignments.element.extend({
453
+ source: normalizedSourceSchema.optional(),
454
+ })),
455
+ cachedFormulas: z.array(evidenceShape.cachedFormulas.element.extend({
456
+ source: normalizedSourceSchema.optional(),
457
+ })),
458
+ })
459
+ .strict()
460
+ .nullable();
461
+ const reviewSchema = reviewSchemaBase.extend({
462
+ identityBody: z
463
+ .object({
464
+ definitionIntegrity: tagSchema,
465
+ preparationFingerprint: tagSchema,
466
+ evidence: normalizedEvidenceSchema,
467
+ checks: z.array(reviewSchemaBase.shape.report.shape.checks.element
468
+ .omit({ description: true, details: true })
469
+ .extend({ findings: z.array(normalizedFindingSchema) })),
470
+ summary: reviewSchemaBase.shape.report.shape.summary,
471
+ evaluations: z.array(normalizedReviewEvaluationSchema),
472
+ })
473
+ .strict(),
474
+ });
12
475
  const displaySchema = z.discriminatedUnion("view", [
13
- z.object({ view: z.literal("emergence"), value: z.custom() }).strict(),
14
- z.object({ view: z.literal("triangles"), value: z.custom() }).strict(),
15
- z.object({ view: z.literal("latest-diagonal"), value: z.custom() }).strict(),
476
+ z
477
+ .object({
478
+ view: z.literal("emergence"),
479
+ points: z.array(pointSchema.omit({ components: true })),
480
+ })
481
+ .strict(),
482
+ z
483
+ .object({
484
+ view: z.literal("triangles"),
485
+ triangles: z.array(triangleSchema),
486
+ })
487
+ .strict(),
488
+ z
489
+ .object({
490
+ view: z.literal("latest-diagonal"),
491
+ points: z.array(pointSchema.omit({ components: true })),
492
+ })
493
+ .strict(),
16
494
  ]);
17
- const toolSuccessSchema = z.object({
18
- success: z.literal(true), runPresetId: z.string(), instanceIds: z.array(z.string()), definitionIntegrity: z.string(),
19
- formulaFingerprints: z.record(z.string()), calculationFingerprints: z.record(z.string()), runFingerprint: z.string(),
20
- resultFingerprint: z.string(), runResultFingerprint: z.string(), review: z.custom(),
21
- display: displaySchema,
22
- }).strict();
495
+ const toolSuccessSchema = z
496
+ .object({
497
+ success: z.literal(true),
498
+ data: z
499
+ .object({
500
+ runPresetId: tokenSchema,
501
+ instanceIds: z.array(tokenSchema).min(1),
502
+ definitionIntegrity: tagSchema,
503
+ formulaFingerprints: recordSchema(tagSchema),
504
+ calculationFingerprints: recordSchema(tagSchema),
505
+ runFingerprint: tagSchema,
506
+ resultFingerprint: tagSchema,
507
+ runResultFingerprint: tagSchema,
508
+ review: reviewSchema,
509
+ display: displaySchema,
510
+ })
511
+ .strict(),
512
+ })
513
+ .strict();
23
514
  /** Strict model-visible output schema, including the wrapper's failure branch. */
24
- export const diagnosticAgentToolResultSchema = z.union([toolSuccessSchema, toolFailureSchema]);
25
- function token(value, label) { if (value.length === 0 || /^[\t-\r ]|[\t-\r ]$/.test(value) || value.includes("\0"))
26
- throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", `${label} must be a nonempty token`); }
27
- function sortUniqueRequested(values) { const result = [...new Set(values)]; result.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); return result; }
515
+ export const diagnosticAgentToolResultSchema = z.union([
516
+ toolSuccessSchema,
517
+ toolFailureSchema,
518
+ ]);
519
+ function token(value, label) {
520
+ if (!isDiagnosticToken(value))
521
+ throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", `${label} must be a nonempty token`);
522
+ }
523
+ function sortUniqueRequested(values) {
524
+ const result = [...new Set(values)];
525
+ result.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
526
+ return result;
527
+ }
28
528
  export function createDiagnosticSelectionTool(input) {
29
529
  try {
30
530
  assertCompiledDiagnosticDefinition(input.definition);
@@ -32,26 +532,33 @@ export function createDiagnosticSelectionTool(input) {
32
532
  catch {
33
533
  throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", "definition must be an authentic compiled diagnostic definition");
34
534
  }
35
- const id = input.id ?? "run_diagnostic_selection";
36
- const description = input.description ?? "Run a host-approved diagnostic preset for selected registered metric instances.";
37
- const tenantKey = input.tenantContextKey ?? "projectId";
535
+ const definition = input.definition;
536
+ const id = input.id === undefined ? "run_diagnostic_selection" : input.id;
537
+ const description = input.description === undefined
538
+ ? "Run a host-approved diagnostic preset for selected registered metric instances."
539
+ : input.description;
540
+ const tenantKey = input.tenantContextKey === undefined ? "projectId" : input.tenantContextKey;
38
541
  token(id, "tool id");
39
542
  token(tenantKey, "tenant context key");
40
- if (description.trim().length === 0)
543
+ if (typeof description !== "string" || description.trim().length === 0)
41
544
  throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", "description must be nonblank");
42
- if (input.presets.length === 0)
545
+ if (!Array.isArray(input.runPresets) || input.runPresets.length === 0)
43
546
  throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", "at least one approved diagnostic preset is required");
44
- const known = new Set(input.definition.definition.instances.map((item) => item.id));
547
+ const known = new Set(definition.definition.instances.map((item) => item.id));
45
548
  const catalog = new Map();
46
- for (const preset of input.presets) {
549
+ for (const preset of input.runPresets) {
550
+ if (!isDiagnosticPlainRecord(preset))
551
+ throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", "Each diagnostic preset must be a plain record");
47
552
  token(preset.id, "preset id");
48
553
  if (catalog.has(preset.id))
49
554
  throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", `duplicate preset ${preset.id}`);
50
- if (preset.definitionIntegrity !== input.definition.definitionIntegrity)
555
+ if (preset.definitionIntegrity !== definition.definitionIntegrity)
51
556
  throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", `preset ${preset.id} targets another definition`);
52
557
  if (typeof preset.execute !== "function")
53
558
  throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", `preset ${preset.id} has no executor`);
54
559
  const seen = new Set();
560
+ if (!Array.isArray(preset.allowedInstanceIds))
561
+ throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", `preset ${preset.id} must declare allowed instance IDs`);
55
562
  for (const instanceId of preset.allowedInstanceIds) {
56
563
  token(instanceId, "allowed instance id");
57
564
  if (seen.has(instanceId))
@@ -62,31 +569,87 @@ export function createDiagnosticSelectionTool(input) {
62
569
  }
63
570
  if (seen.size === 0)
64
571
  throw new AgentsError("BAD_DIAGNOSTIC_CATALOG", `preset ${preset.id} has no allowed instances`);
65
- catalog.set(preset.id, Object.freeze({ definitionIntegrity: preset.definitionIntegrity, allowedInstanceIds: Object.freeze([...seen].sort()), execute: preset.execute }));
572
+ catalog.set(preset.id, Object.freeze({
573
+ definitionIntegrity: preset.definitionIntegrity,
574
+ allowedInstanceIds: Object.freeze([...seen].sort()),
575
+ execute: preset.execute,
576
+ }));
66
577
  }
67
- return defineActuarialTool({ id, description, kind: "read", tenant: "required", tenantKey, inputSchema: diagnosticAgentToolInputSchema, outputSchema: diagnosticAgentToolResultSchema, execute: async (raw, tenant) => {
578
+ return defineActuarialTool({
579
+ id,
580
+ description,
581
+ kind: "read",
582
+ tenant: "required",
583
+ tenantKey,
584
+ inputSchema: diagnosticAgentToolInputSchema,
585
+ outputSchema: diagnosticAgentToolResultSchema,
586
+ execute: async (raw, tenant) => {
68
587
  const preset = catalog.get(raw.runPresetId);
69
588
  if (!preset)
70
589
  throw new AgentsError("UNKNOWN_DIAGNOSTIC_PRESET", `Unknown diagnostic preset ${raw.runPresetId}`);
71
590
  const selected = sortUniqueRequested(raw.instanceIds);
72
591
  if (selected.some((item) => !preset.allowedInstanceIds.includes(item)))
73
592
  throw new AgentsError("UNAPPROVED_DIAGNOSTIC_INSTANCE", "One or more diagnostic instances are not approved by the selected preset");
74
- const provenance = await preset.execute({ tenant, instanceIds: selected });
593
+ const provenance = await preset.execute({
594
+ tenantId: tenant,
595
+ instanceIds: selected,
596
+ });
75
597
  try {
76
598
  assertVerifiedDiagnosticRunProvenance(provenance);
77
599
  }
78
600
  catch {
79
601
  throw new AgentsError("DIAGNOSTIC_RUN_MISMATCH", "Preset executor returned unauthenticated diagnostic provenance");
80
602
  }
81
- const filter = provenance.manifest.preparation.filter;
82
- if (provenance.definitionIdentities.definition !== input.definition.definitionIntegrity || provenance.manifest.runPresetId !== raw.runPresetId || !filter || JSON.stringify(filter.instanceIds ?? []) !== JSON.stringify(selected))
603
+ const filter = provenance.manifest.filter;
604
+ if (provenance.definition.identities.definition !==
605
+ definition.definitionIntegrity ||
606
+ provenance.manifest.runPresetId !== raw.runPresetId ||
607
+ !filter ||
608
+ JSON.stringify(filter.instanceIds ?? []) !== JSON.stringify(selected))
83
609
  throw new AgentsError("DIAGNOSTIC_RUN_MISMATCH", "Verified run does not match the selected definition, preset, and exact instance set");
84
- const instances = input.definition.definition.instances.filter((item) => selected.includes(item.id));
85
- const formulaIds = [...new Set(instances.map((item) => item.formulaId))].sort();
86
- const formulaFingerprints = Object.fromEntries(formulaIds.map((formulaId) => [formulaId, provenance.definitionIdentities.formulaById[formulaId]]));
87
- const calculationFingerprints = Object.fromEntries(selected.map((instanceId) => [instanceId, provenance.definitionIdentities.calculationByInstanceId[instanceId]]));
88
- const display = raw.view === "emergence" ? { view: "emergence", value: provenance.result.emergence } : raw.view === "triangles" ? { view: "triangles", value: provenance.result.triangles } : { view: "latest-diagonal", value: provenance.result.latestDiagonal };
89
- return { success: true, runPresetId: raw.runPresetId, instanceIds: selected, definitionIntegrity: provenance.definitionIdentities.definition, formulaFingerprints, calculationFingerprints, runFingerprint: provenance.runFingerprint, resultFingerprint: provenance.resultFingerprint, runResultFingerprint: provenance.runResultFingerprint, review: provenance.review, display };
90
- } });
610
+ const instances = definition.definition.instances.filter((item) => selected.includes(item.id));
611
+ const formulaIds = [
612
+ ...new Set(instances.map((item) => item.formulaId)),
613
+ ].sort();
614
+ const formulaFingerprints = Object.fromEntries(formulaIds.map((formulaId) => [
615
+ formulaId,
616
+ provenance.definition.identities.formulaById[formulaId],
617
+ ]));
618
+ const calculationFingerprints = Object.fromEntries(selected.map((instanceId) => [
619
+ instanceId,
620
+ provenance.definition.identities.calculationByInstanceId[instanceId],
621
+ ]));
622
+ const displayPoints = (points) => points.map(({ components: _components, ...point }) => point);
623
+ const display = raw.view === "emergence"
624
+ ? {
625
+ view: "emergence",
626
+ points: displayPoints(provenance.result.emergence),
627
+ }
628
+ : raw.view === "triangles"
629
+ ? {
630
+ view: "triangles",
631
+ triangles: provenance.result.triangles,
632
+ }
633
+ : {
634
+ view: "latest-diagonal",
635
+ points: displayPoints(provenance.result.latestDiagonal),
636
+ };
637
+ return {
638
+ success: true,
639
+ data: {
640
+ runPresetId: raw.runPresetId,
641
+ instanceIds: selected,
642
+ definitionIntegrity: provenance.definition.identities.definition,
643
+ formulaFingerprints,
644
+ calculationFingerprints,
645
+ runFingerprint: provenance.runFingerprint,
646
+ resultFingerprint: provenance.resultFingerprint,
647
+ runResultFingerprint: provenance.runResultFingerprint,
648
+ review: provenance.review,
649
+ display,
650
+ },
651
+ };
652
+ },
653
+ });
91
654
  }
92
655
  //# sourceMappingURL=diagnostics.js.map