@tangle-network/agent-interface 0.33.0 → 0.34.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.
Files changed (33) hide show
  1. package/dist/agent-candidate-code-schema.d.ts +0 -3
  2. package/dist/agent-candidate-execution-plan-schema.d.ts +11 -17
  3. package/dist/agent-candidate-lineage-schema.d.ts +2 -2
  4. package/dist/agent-candidate-outcome-schema.d.ts +4 -4
  5. package/dist/agent-candidate-profile-schema.d.ts +0 -3
  6. package/dist/agent-candidate-promotion-schema.d.ts +1411 -885
  7. package/dist/agent-candidate-promotion-schema.js +46 -346
  8. package/dist/agent-candidate-receipt-schema.d.ts +8 -11
  9. package/dist/agent-candidate-schema.d.ts +0 -6
  10. package/dist/agent-candidate-schema.js +1 -3
  11. package/dist/agent-candidate.d.ts +14 -7
  12. package/dist/agent-improvement-measurement-schema.d.ts +198 -0
  13. package/dist/agent-improvement-measurement-schema.js +349 -0
  14. package/dist/agent-improvement-source.d.ts +23 -0
  15. package/dist/agent-improvement-source.js +38 -0
  16. package/dist/agent-profile-improvement-schema.d.ts +1085 -0
  17. package/dist/agent-profile-improvement-schema.js +553 -0
  18. package/dist/agent-profile-improvement.d.ts +139 -0
  19. package/dist/agent-profile-improvement.js +1 -0
  20. package/dist/agent-profile.d.ts +2 -2
  21. package/dist/agent-profile.js +2 -2
  22. package/dist/harness-capabilities.d.ts +1 -1
  23. package/dist/harness-capabilities.js +9 -12
  24. package/dist/harness.d.ts +1 -10
  25. package/dist/harness.js +0 -13
  26. package/dist/index.d.ts +5 -1
  27. package/dist/index.js +4 -0
  28. package/dist/interaction.d.ts +0 -17
  29. package/dist/interaction.js +0 -23
  30. package/dist/number-validation.d.ts +1 -0
  31. package/dist/number-validation.js +4 -0
  32. package/dist/profile-schema.d.ts +0 -3
  33. package/package.json +1 -1
@@ -0,0 +1,553 @@
1
+ import { z } from "zod";
2
+ import { agentCandidateLineageSchema } from "./agent-candidate-lineage-schema.js";
3
+ import { canonicalCandidateDigest, isCanonicalJsonValue, omitTopLevelDigest, sha256DigestSchema, } from "./agent-candidate-schema-common.js";
4
+ import { agentCandidateBenchmarkGraderIdentitySchema, agentCandidateExecutionLimitsSchema, agentCandidateResolvedModelSchema, } from "./agent-candidate-execution-plan-schema.js";
5
+ import { agentCandidateBenchmarkDimensionSchema, agentCandidateFixedSpendSchema, } from "./agent-candidate-outcome-schema.js";
6
+ import { agentCandidateEvaluationPolicySchema, createMeasuredComparisonIdentityRegistry, measuredComparisonCommonShape, refineMeasuredComparisonSummary, } from "./agent-improvement-measurement-schema.js";
7
+ import { agentImprovementSourceSchema } from "./agent-improvement-source.js";
8
+ import { numbersApproximatelyEqual } from "./number-validation.js";
9
+ import { agentProfileDiffSchema } from "./profile-schema.js";
10
+ const profileImprovementScenarioSchema = z
11
+ .object({
12
+ id: z.string().min(1).max(500),
13
+ kind: z.string().min(1).max(200),
14
+ digest: sha256DigestSchema,
15
+ })
16
+ .strict();
17
+ export const agentProfileImprovementTaskSchema = z
18
+ .object({
19
+ kind: z.literal("agent-profile-improvement-task"),
20
+ digestAlgorithm: z.literal("rfc8785-sha256"),
21
+ scenario: profileImprovementScenarioSchema,
22
+ grader: agentCandidateBenchmarkGraderIdentitySchema,
23
+ model: agentCandidateResolvedModelSchema,
24
+ limits: agentCandidateExecutionLimitsSchema,
25
+ digest: sha256DigestSchema,
26
+ })
27
+ .strict()
28
+ .superRefine((task, ctx) => {
29
+ if (canonicalCandidateDigest(omitTopLevelDigest(task)) !== task.digest) {
30
+ ctx.addIssue({
31
+ code: "custom",
32
+ path: ["digest"],
33
+ message: "profile improvement task digest is invalid",
34
+ });
35
+ }
36
+ });
37
+ export const agentProfileImprovementSuiteSchema = z
38
+ .object({
39
+ kind: z.literal("agent-profile-improvement-suite"),
40
+ digestAlgorithm: z.literal("rfc8785-sha256"),
41
+ splitDigest: sha256DigestSchema,
42
+ taskDigests: z.tuple([sha256DigestSchema]).rest(sha256DigestSchema),
43
+ reps: z.number().int().positive(),
44
+ seeds: z.tuple([z.number().int().safe()]).rest(z.number().int().safe()),
45
+ digest: sha256DigestSchema,
46
+ })
47
+ .strict()
48
+ .superRefine((suite, ctx) => {
49
+ if (canonicalCandidateDigest(omitTopLevelDigest(suite)) !== suite.digest) {
50
+ ctx.addIssue({
51
+ code: "custom",
52
+ path: ["digest"],
53
+ message: "profile improvement suite digest is invalid",
54
+ });
55
+ }
56
+ });
57
+ export const agentProfileImprovementSuiteInputsSchema = z
58
+ .object({
59
+ suite: agentProfileImprovementSuiteSchema,
60
+ tasks: z.tuple([agentProfileImprovementTaskSchema]).rest(agentProfileImprovementTaskSchema),
61
+ })
62
+ .strict()
63
+ .superRefine((input, ctx) => {
64
+ if (input.suite.taskDigests.length !== input.tasks.length) {
65
+ ctx.addIssue({
66
+ code: "custom",
67
+ path: ["tasks"],
68
+ message: "profile improvement suite task count does not match its signed digests",
69
+ });
70
+ }
71
+ if (input.suite.seeds.length !== input.tasks.length * input.suite.reps) {
72
+ ctx.addIssue({
73
+ code: "custom",
74
+ path: ["suite", "seeds"],
75
+ message: "profile improvement suite must have one seed per task and repetition",
76
+ });
77
+ }
78
+ for (const [index, task] of input.tasks.entries()) {
79
+ if (input.suite.taskDigests[index] !== task.digest) {
80
+ ctx.addIssue({
81
+ code: "custom",
82
+ path: ["tasks", index, "digest"],
83
+ message: "profile improvement suite task digest does not match its task",
84
+ });
85
+ }
86
+ }
87
+ });
88
+ const profileImprovementEvidenceSchema = z
89
+ .object({
90
+ kind: z.string().trim().min(1).max(100).regex(/^[a-z][a-z0-9-]*$/),
91
+ identity: z.string().trim().min(1).max(500),
92
+ digest: sha256DigestSchema,
93
+ })
94
+ .strict();
95
+ export const agentProfileImprovementArmSchema = z
96
+ .object({
97
+ stateDigest: sha256DigestSchema,
98
+ })
99
+ .strict();
100
+ /**
101
+ * The first product path changes only prompt and skills, but it uses the
102
+ * shared profile-diff language so execution and activation apply identical
103
+ * ordered patches.
104
+ */
105
+ export const agentProfileImprovementChangeStepSchema = agentProfileDiffSchema.superRefine((change, ctx) => {
106
+ const changed = changedProfileImprovementSurfaces([change]);
107
+ if (changed.length === 0) {
108
+ ctx.addIssue({
109
+ code: "custom",
110
+ message: "profile improvement patch must change prompt or skills",
111
+ });
112
+ }
113
+ const setKeys = Object.keys(change.set ?? {});
114
+ if (setKeys.some((key) => key !== "prompt" && key !== "resources")) {
115
+ ctx.addIssue({
116
+ code: "custom",
117
+ path: ["set"],
118
+ message: "profile improvement patches may set only prompt or skill resources",
119
+ });
120
+ }
121
+ const setResourceKeys = Object.keys(change.set?.resources ?? {});
122
+ if (setResourceKeys.some((key) => key !== "skills")) {
123
+ ctx.addIssue({
124
+ code: "custom",
125
+ path: ["set", "resources"],
126
+ message: "profile improvement patches may set only skill resources",
127
+ });
128
+ }
129
+ if (change.set?.resources?.skills?.some((skill) => skill.kind !== "inline")) {
130
+ ctx.addIssue({
131
+ code: "custom",
132
+ path: ["set", "resources", "skills"],
133
+ message: "measured profile skill patches require inline content with exact bytes",
134
+ });
135
+ }
136
+ const removeKeys = Object.keys(change.remove ?? {});
137
+ if (removeKeys.some((key) => key !== "prompt" && key !== "resources")) {
138
+ ctx.addIssue({
139
+ code: "custom",
140
+ path: ["remove"],
141
+ message: "profile improvement patches may remove only prompt or skill resources",
142
+ });
143
+ }
144
+ if (change.remove?.resources === true) {
145
+ ctx.addIssue({
146
+ code: "custom",
147
+ path: ["remove", "resources"],
148
+ message: "profile improvement patches may not remove unrelated resources",
149
+ });
150
+ }
151
+ const removeResources = change.remove?.resources;
152
+ const removeResourceKeys = Object.keys(typeof removeResources === "object" ? removeResources : {});
153
+ if (removeResourceKeys.some((key) => key !== "skills")) {
154
+ ctx.addIssue({
155
+ code: "custom",
156
+ path: ["remove", "resources"],
157
+ message: "profile improvement patches may remove only skill resources",
158
+ });
159
+ }
160
+ });
161
+ export const agentProfileImprovementChangeSchema = z
162
+ .tuple([agentProfileImprovementChangeStepSchema])
163
+ .rest(agentProfileImprovementChangeStepSchema)
164
+ .superRefine((change, ctx) => {
165
+ const surfaces = changedProfileImprovementSurfaces(change);
166
+ if (surfaces.length === 0) {
167
+ ctx.addIssue({
168
+ code: "custom",
169
+ message: "profile improvement change must alter at least one supported surface",
170
+ });
171
+ }
172
+ });
173
+ export const agentProfileImprovementExperimentSchema = z
174
+ .object({
175
+ kind: z.literal("agent-profile-improvement-experiment"),
176
+ digestAlgorithm: z.literal("rfc8785-sha256"),
177
+ source: agentImprovementSourceSchema,
178
+ baseline: agentProfileImprovementArmSchema,
179
+ candidate: agentProfileImprovementArmSchema,
180
+ change: agentProfileImprovementChangeSchema,
181
+ candidateLineage: agentCandidateLineageSchema,
182
+ benchmark: agentProfileImprovementSuiteInputsSchema,
183
+ policy: agentCandidateEvaluationPolicySchema,
184
+ digest: sha256DigestSchema,
185
+ })
186
+ .strict()
187
+ .superRefine((experiment, ctx) => {
188
+ if (experiment.baseline.stateDigest !== experiment.source.sourceDigest) {
189
+ ctx.addIssue({
190
+ code: "custom",
191
+ path: ["baseline", "stateDigest"],
192
+ message: "profile improvement baseline must bind the exact source state",
193
+ });
194
+ }
195
+ if (experiment.baseline.stateDigest === experiment.candidate.stateDigest) {
196
+ ctx.addIssue({
197
+ code: "custom",
198
+ path: ["candidate", "stateDigest"],
199
+ message: "profile improvement experiment requires a changed candidate state",
200
+ });
201
+ }
202
+ const source = experiment.candidateLineage.source;
203
+ if ((source === "optimizer" || source === "compound") &&
204
+ !experiment.candidateLineage.parentDigests?.includes(experiment.baseline.stateDigest)) {
205
+ ctx.addIssue({
206
+ code: "custom",
207
+ path: ["candidateLineage", "parentDigests"],
208
+ message: "generated profile lineage must include the experiment baseline",
209
+ });
210
+ }
211
+ if (experiment.candidateLineage.parentDigests?.includes(experiment.candidate.stateDigest)) {
212
+ ctx.addIssue({
213
+ code: "custom",
214
+ path: ["candidateLineage", "parentDigests"],
215
+ message: "profile lineage cannot name the candidate itself as a parent",
216
+ });
217
+ }
218
+ if (experiment.candidateLineage.developmentSplitDigest !== undefined &&
219
+ experiment.candidateLineage.developmentSplitDigest === experiment.benchmark.suite.splitDigest) {
220
+ ctx.addIssue({
221
+ code: "custom",
222
+ path: ["candidateLineage", "developmentSplitDigest"],
223
+ message: "profile improvement development and held-out splits must be disjoint",
224
+ });
225
+ }
226
+ if (canonicalCandidateDigest(omitTopLevelDigest(experiment)) !== experiment.digest) {
227
+ ctx.addIssue({
228
+ code: "custom",
229
+ path: ["digest"],
230
+ message: "profile improvement experiment digest is invalid",
231
+ });
232
+ }
233
+ });
234
+ export const agentProfileImprovementRunCellSchema = z
235
+ .object({
236
+ kind: z.literal("agent-profile-improvement-run-cell"),
237
+ experimentDigest: sha256DigestSchema,
238
+ arm: z.enum(["baseline", "candidate"]),
239
+ stateDigest: sha256DigestSchema,
240
+ suiteDigest: sha256DigestSchema,
241
+ taskDigest: sha256DigestSchema,
242
+ taskIndex: z.number().int().nonnegative(),
243
+ repetition: z.number().int().nonnegative(),
244
+ seed: z.number().int().safe(),
245
+ attempt: z.number().int().positive(),
246
+ digest: sha256DigestSchema,
247
+ })
248
+ .strict()
249
+ .superRefine((cell, ctx) => {
250
+ if (canonicalCandidateDigest(omitTopLevelDigest(cell)) !== cell.digest) {
251
+ ctx.addIssue({
252
+ code: "custom",
253
+ path: ["digest"],
254
+ message: "profile improvement run cell digest is invalid",
255
+ });
256
+ }
257
+ });
258
+ const timingSchema = z
259
+ .object({
260
+ startedAtMs: z.number().finite().nonnegative(),
261
+ endedAtMs: z.number().finite().nonnegative(),
262
+ durationMs: z.number().finite().nonnegative(),
263
+ })
264
+ .strict()
265
+ .superRefine((timing, ctx) => {
266
+ if (!numbersApproximatelyEqual(timing.durationMs, timing.endedAtMs - timing.startedAtMs)) {
267
+ ctx.addIssue({
268
+ code: "custom",
269
+ path: ["durationMs"],
270
+ message: "timing duration must equal its start and end timestamps",
271
+ });
272
+ }
273
+ });
274
+ const agentProfileImprovementGradingSchema = z
275
+ .object({
276
+ grader: agentCandidateBenchmarkGraderIdentitySchema,
277
+ evidence: profileImprovementEvidenceSchema,
278
+ timing: timingSchema,
279
+ usage: agentCandidateFixedSpendSchema,
280
+ score: z.number().finite(),
281
+ passed: z.boolean(),
282
+ dimensions: z.array(agentCandidateBenchmarkDimensionSchema),
283
+ })
284
+ .strict()
285
+ .superRefine((grading, ctx) => {
286
+ const names = grading.dimensions.map((dimension) => dimension.name);
287
+ if (new Set(names).size !== names.length) {
288
+ ctx.addIssue({
289
+ code: "custom",
290
+ path: ["dimensions"],
291
+ message: "profile improvement grading dimension names must be unique",
292
+ });
293
+ }
294
+ if (grading.evidence.digest === grading.grader.artifact.sha256) {
295
+ ctx.addIssue({
296
+ code: "custom",
297
+ path: ["evidence"],
298
+ message: "profile improvement grading evidence must be distinct from its grader",
299
+ });
300
+ }
301
+ });
302
+ export const agentProfileImprovementRunReceiptSchema = z
303
+ .object({
304
+ kind: z.literal("agent-profile-improvement-run"),
305
+ digestAlgorithm: z.literal("rfc8785-sha256"),
306
+ executionId: z.string().min(1).max(500),
307
+ runCell: agentProfileImprovementRunCellSchema,
308
+ runRecord: profileImprovementEvidenceSchema,
309
+ billing: z
310
+ .tuple([profileImprovementEvidenceSchema])
311
+ .rest(profileImprovementEvidenceSchema),
312
+ timing: timingSchema,
313
+ resolvedModel: agentCandidateResolvedModelSchema,
314
+ limits: agentCandidateExecutionLimitsSchema,
315
+ usage: agentCandidateFixedSpendSchema,
316
+ trace: z
317
+ .object({
318
+ evidence: profileImprovementEvidenceSchema,
319
+ eventCount: z.number().int().nonnegative(),
320
+ modelCallCount: z.number().int().nonnegative(),
321
+ })
322
+ .strict(),
323
+ output: profileImprovementEvidenceSchema,
324
+ outcome: z.discriminatedUnion("status", [
325
+ z.object({ status: z.literal("succeeded") }).strict(),
326
+ z
327
+ .object({
328
+ status: z.literal("failed"),
329
+ code: z.string().min(1).max(200),
330
+ message: z.string().min(1).max(4_000),
331
+ })
332
+ .strict(),
333
+ ]),
334
+ grading: agentProfileImprovementGradingSchema,
335
+ digest: sha256DigestSchema,
336
+ })
337
+ .strict()
338
+ .superRefine((receipt, ctx) => {
339
+ if (evidenceKey(receipt.output) === evidenceKey(receipt.grading.evidence)) {
340
+ ctx.addIssue({
341
+ code: "custom",
342
+ path: ["grading", "evidence"],
343
+ message: "profile improvement grading evidence must be distinct from the agent output",
344
+ });
345
+ }
346
+ if (receipt.trace.modelCallCount !== receipt.usage.modelCalls) {
347
+ ctx.addIssue({
348
+ code: "custom",
349
+ path: ["trace", "modelCallCount"],
350
+ message: "profile trace model calls must equal settled execution model calls",
351
+ });
352
+ }
353
+ if (receipt.trace.eventCount < receipt.trace.modelCallCount) {
354
+ ctx.addIssue({
355
+ code: "custom",
356
+ path: ["trace", "eventCount"],
357
+ message: "profile trace must retain at least one event for every model call",
358
+ });
359
+ }
360
+ const billing = receipt.billing.map(evidenceKey);
361
+ if (new Set(billing).size !== billing.length) {
362
+ ctx.addIssue({
363
+ code: "custom",
364
+ path: ["billing"],
365
+ message: "profile improvement billing evidence must be unique",
366
+ });
367
+ }
368
+ if (canonicalCandidateDigest(omitTopLevelDigest(receipt)) !== receipt.digest) {
369
+ ctx.addIssue({
370
+ code: "custom",
371
+ path: ["digest"],
372
+ message: "profile improvement run receipt digest is invalid",
373
+ });
374
+ }
375
+ });
376
+ const agentProfileImprovementMeasurementSchema = z
377
+ .object({
378
+ baseline: agentProfileImprovementRunReceiptSchema,
379
+ candidate: agentProfileImprovementRunReceiptSchema,
380
+ })
381
+ .strict();
382
+ export const agentProfileImprovementMeasuredComparisonSchema = z
383
+ .object({
384
+ kind: z.literal("agent-profile-improvement-measured-comparison"),
385
+ experiment: agentProfileImprovementExperimentSchema,
386
+ measurements: z.array(agentProfileImprovementMeasurementSchema),
387
+ ...measuredComparisonCommonShape,
388
+ })
389
+ .strict()
390
+ .superRefine((comparison, ctx) => {
391
+ refineProfileImprovementComparison(comparison, ctx);
392
+ });
393
+ export function changedProfileImprovementSurfaces(change) {
394
+ const surfaces = new Set();
395
+ for (const step of change) {
396
+ if (step.set?.prompt !== undefined || step.remove?.prompt !== undefined) {
397
+ surfaces.add("prompt");
398
+ }
399
+ if (step.set?.resources?.skills !== undefined ||
400
+ (typeof step.remove?.resources === "object" &&
401
+ step.remove.resources.skills !== undefined)) {
402
+ surfaces.add("skills");
403
+ }
404
+ }
405
+ return [...surfaces].sort();
406
+ }
407
+ function refineProfileImprovementComparison(comparison, ctx) {
408
+ const { suite, tasks } = comparison.experiment.benchmark;
409
+ const expectedN = tasks.length * suite.reps;
410
+ if (comparison.provenance.baselineContentHash !== comparison.experiment.baseline.stateDigest ||
411
+ comparison.provenance.candidateContentHash !== comparison.experiment.candidate.stateDigest) {
412
+ ctx.addIssue({
413
+ code: "custom",
414
+ path: ["provenance"],
415
+ message: "profile comparison provenance must bind both complete measured states",
416
+ });
417
+ }
418
+ if (comparison.measurements.length !== expectedN) {
419
+ ctx.addIssue({
420
+ code: "custom",
421
+ path: ["measurements"],
422
+ message: "profile comparison must contain every signed benchmark cell",
423
+ });
424
+ }
425
+ const recordProfileIdentities = createMeasuredComparisonIdentityRegistry({
426
+ ctx,
427
+ identityLabel: "profile measurements",
428
+ });
429
+ const expectedDimensions = measurementDimensionNames(comparison.measurements[0]);
430
+ for (let taskIndex = 0; taskIndex < tasks.length; taskIndex += 1) {
431
+ const task = tasks[taskIndex];
432
+ if (!task)
433
+ continue;
434
+ for (let repetition = 0; repetition < suite.reps; repetition += 1) {
435
+ const index = taskIndex * suite.reps + repetition;
436
+ const measurement = comparison.measurements[index];
437
+ if (!measurement)
438
+ continue;
439
+ const seed = suite.seeds[index];
440
+ for (const arm of ["baseline", "candidate"]) {
441
+ const receipt = measurement[arm];
442
+ const cell = receipt.runCell;
443
+ const profile = comparison.experiment[arm];
444
+ const armPath = ["measurements", index, arm];
445
+ const checks = [
446
+ [
447
+ cell.experimentDigest === comparison.experiment.digest,
448
+ [...armPath, "runCell", "experimentDigest"],
449
+ "profile run receipt must bind the measured experiment",
450
+ ],
451
+ [
452
+ cell.arm === arm,
453
+ [...armPath, "runCell", "arm"],
454
+ "profile run receipt must bind its measured arm",
455
+ ],
456
+ [
457
+ cell.stateDigest === profile.stateDigest,
458
+ [...armPath, "runCell", "stateDigest"],
459
+ "profile run receipt must bind the experiment arm state",
460
+ ],
461
+ [
462
+ cell.suiteDigest === suite.digest &&
463
+ cell.taskDigest === task.digest &&
464
+ cell.taskIndex === taskIndex &&
465
+ cell.repetition === repetition &&
466
+ cell.seed === seed &&
467
+ cell.attempt === 1,
468
+ [...armPath, "runCell"],
469
+ "publishable profile evidence must use the first signed task attempt",
470
+ ],
471
+ [
472
+ JSON.stringify(receipt.grading.grader) === JSON.stringify(task.grader),
473
+ [...armPath, "grading", "grader"],
474
+ "profile run receipt must bind the signed evaluator",
475
+ ],
476
+ [
477
+ JSON.stringify(receipt.resolvedModel) === JSON.stringify(task.model),
478
+ [...armPath, "resolvedModel"],
479
+ "profile run receipt must bind the signed model snapshot",
480
+ ],
481
+ [
482
+ JSON.stringify(receipt.limits) === JSON.stringify(task.limits),
483
+ [...armPath, "limits"],
484
+ "profile run receipt must bind the signed execution limits",
485
+ ],
486
+ [
487
+ JSON.stringify(receipt.grading.dimensions.map((dimension) => dimension.name)) ===
488
+ JSON.stringify(expectedDimensions),
489
+ [...armPath, "grading", "dimensions"],
490
+ "profile run receipt dimensions must match the complete measured comparison",
491
+ ],
492
+ ];
493
+ for (const [valid, path, message] of checks) {
494
+ if (!valid)
495
+ ctx.addIssue({ code: "custom", path, message });
496
+ }
497
+ recordProfileIdentities([
498
+ { kind: "execution", value: receipt.executionId },
499
+ { kind: "runCell", value: cell.digest },
500
+ { kind: "receipt", value: receipt.digest },
501
+ { kind: "runRecord", value: evidenceKey(receipt.runRecord) },
502
+ ...receipt.billing.map((billing) => ({
503
+ kind: "billing",
504
+ value: evidenceKey(billing),
505
+ path: [...armPath, "billing"],
506
+ })),
507
+ ], armPath);
508
+ }
509
+ if (measurement.baseline.executionId === measurement.candidate.executionId ||
510
+ measurement.baseline.runCell.digest === measurement.candidate.runCell.digest ||
511
+ measurement.baseline.digest === measurement.candidate.digest) {
512
+ ctx.addIssue({
513
+ code: "custom",
514
+ path: ["measurements", index],
515
+ message: "profile measurement must use independent baseline and candidate executions",
516
+ });
517
+ }
518
+ }
519
+ }
520
+ if (comparison.decision.outcome === "ship" &&
521
+ comparison.measurements.some((measurement) => measurement.baseline.outcome.status !== "succeeded" ||
522
+ measurement.candidate.outcome.status !== "succeeded")) {
523
+ ctx.addIssue({
524
+ code: "custom",
525
+ path: ["measurements"],
526
+ message: "a shippable profile comparison cannot include failed executions",
527
+ });
528
+ }
529
+ refineMeasuredComparisonSummary(comparison, comparison.experiment.policy, expectedN, comparison.measurements, {
530
+ score: (receipt) => receipt.grading.score,
531
+ dimension: (receipt, name) => receipt.grading.dimensions.find((dimension) => dimension.name === name)?.score,
532
+ cost: profileImprovementExecutionCostUsd,
533
+ latency: profileImprovementExecutionLatencyMs,
534
+ }, ctx);
535
+ if (!isCanonicalJsonValue(comparison)) {
536
+ ctx.addIssue({
537
+ code: "custom",
538
+ message: "profile measured comparison must contain only RFC 8785 JSON values",
539
+ });
540
+ }
541
+ }
542
+ function measurementDimensionNames(measurement) {
543
+ return measurement?.baseline.grading.dimensions.map((dimension) => dimension.name) ?? [];
544
+ }
545
+ function evidenceKey(evidence) {
546
+ return `${evidence.kind}\u0000${evidence.identity}\u0000${evidence.digest}`;
547
+ }
548
+ function profileImprovementExecutionCostUsd(receipt) {
549
+ return (receipt.usage.costUsdNanos + receipt.grading.usage.costUsdNanos) / 1_000_000_000;
550
+ }
551
+ function profileImprovementExecutionLatencyMs(receipt) {
552
+ return receipt.timing.durationMs + receipt.grading.timing.durationMs;
553
+ }
@@ -0,0 +1,139 @@
1
+ import type { AgentCandidateBenchmarkDimension, AgentCandidateBenchmarkGraderIdentity, AgentCandidateDigestAlgorithm, AgentCandidateEvaluationPolicy, AgentCandidateExecutionLimits, AgentCandidateFixedSpend, AgentCandidateLineage, AgentCandidateResolvedModel, AgentImprovementMeasuredComparisonBase, Sha256Digest } from "./agent-candidate.js";
2
+ import type { AgentImprovementSource } from "./agent-improvement-source.js";
3
+ import type { AgentProfileDiff } from "./profile-diff.js";
4
+ /** An access-controlled evidence record emitted by a host-owned profile run. */
5
+ export interface AgentProfileImprovementEvidence {
6
+ kind: string;
7
+ identity: string;
8
+ digest: Sha256Digest;
9
+ }
10
+ /** One profile task whose content and evaluator are frozen before either arm runs. */
11
+ export interface AgentProfileImprovementTaskMaterial {
12
+ kind: "agent-profile-improvement-task";
13
+ digestAlgorithm: AgentCandidateDigestAlgorithm;
14
+ scenario: {
15
+ id: string;
16
+ kind: string;
17
+ digest: Sha256Digest;
18
+ };
19
+ grader: AgentCandidateBenchmarkGraderIdentity;
20
+ model: AgentCandidateResolvedModel;
21
+ limits: AgentCandidateExecutionLimits;
22
+ }
23
+ export interface AgentProfileImprovementTask extends AgentProfileImprovementTaskMaterial {
24
+ digest: Sha256Digest;
25
+ }
26
+ /** The full paired denominator for host-owned profile executions. */
27
+ export interface AgentProfileImprovementSuiteMaterial {
28
+ kind: "agent-profile-improvement-suite";
29
+ digestAlgorithm: AgentCandidateDigestAlgorithm;
30
+ splitDigest: Sha256Digest;
31
+ taskDigests: [Sha256Digest, ...Sha256Digest[]];
32
+ reps: number;
33
+ /** Task-major, then repetition-major. */
34
+ seeds: [number, ...number[]];
35
+ }
36
+ export interface AgentProfileImprovementSuite extends AgentProfileImprovementSuiteMaterial {
37
+ digest: Sha256Digest;
38
+ }
39
+ export interface AgentProfileImprovementSuiteInputs {
40
+ suite: AgentProfileImprovementSuite;
41
+ tasks: [AgentProfileImprovementTask, ...AgentProfileImprovementTask[]];
42
+ }
43
+ /** The complete profile state that actually runs. */
44
+ export interface AgentProfileImprovementArm {
45
+ stateDigest: Sha256Digest;
46
+ }
47
+ /**
48
+ * Ordered portable profile patches retained for review and activation.
49
+ *
50
+ * Applying the steps in order matters: a full resource replacement is a reset
51
+ * followed by a replacement step. Prompt and inline skill content can be
52
+ * sensitive, so the product that persists this value owns access control and
53
+ * redaction.
54
+ */
55
+ export type AgentProfileImprovementChange = [AgentProfileDiff, ...AgentProfileDiff[]];
56
+ /** A measured comparison of two states of one host-owned agent profile. */
57
+ export interface AgentProfileImprovementExperimentMaterial {
58
+ kind: "agent-profile-improvement-experiment";
59
+ digestAlgorithm: AgentCandidateDigestAlgorithm;
60
+ source: AgentImprovementSource;
61
+ baseline: AgentProfileImprovementArm;
62
+ candidate: AgentProfileImprovementArm;
63
+ change: AgentProfileImprovementChange;
64
+ candidateLineage: AgentCandidateLineage;
65
+ benchmark: AgentProfileImprovementSuiteInputs;
66
+ policy: AgentCandidateEvaluationPolicy;
67
+ }
68
+ export interface AgentProfileImprovementExperiment extends AgentProfileImprovementExperimentMaterial {
69
+ digest: Sha256Digest;
70
+ }
71
+ /** Exact identity for one profile attempt in a frozen experiment. */
72
+ export interface AgentProfileImprovementRunCellMaterial {
73
+ kind: "agent-profile-improvement-run-cell";
74
+ experimentDigest: Sha256Digest;
75
+ arm: "baseline" | "candidate";
76
+ stateDigest: Sha256Digest;
77
+ suiteDigest: Sha256Digest;
78
+ taskDigest: Sha256Digest;
79
+ taskIndex: number;
80
+ repetition: number;
81
+ seed: number;
82
+ attempt: number;
83
+ }
84
+ export interface AgentProfileImprovementRunCell extends AgentProfileImprovementRunCellMaterial {
85
+ digest: Sha256Digest;
86
+ }
87
+ /** Verifiable output from one profile execution and its frozen evaluator. */
88
+ export interface AgentProfileImprovementRunReceipt {
89
+ kind: "agent-profile-improvement-run";
90
+ digestAlgorithm: AgentCandidateDigestAlgorithm;
91
+ executionId: string;
92
+ runCell: AgentProfileImprovementRunCell;
93
+ runRecord: AgentProfileImprovementEvidence;
94
+ billing: [AgentProfileImprovementEvidence, ...AgentProfileImprovementEvidence[]];
95
+ timing: {
96
+ startedAtMs: number;
97
+ endedAtMs: number;
98
+ durationMs: number;
99
+ };
100
+ resolvedModel: AgentCandidateResolvedModel;
101
+ limits: AgentCandidateExecutionLimits;
102
+ usage: AgentCandidateFixedSpend;
103
+ trace: {
104
+ evidence: AgentProfileImprovementEvidence;
105
+ eventCount: number;
106
+ modelCallCount: number;
107
+ };
108
+ output: AgentProfileImprovementEvidence;
109
+ outcome: {
110
+ status: "succeeded";
111
+ } | {
112
+ status: "failed";
113
+ code: string;
114
+ message: string;
115
+ };
116
+ grading: {
117
+ grader: AgentCandidateBenchmarkGraderIdentity;
118
+ evidence: AgentProfileImprovementEvidence;
119
+ timing: {
120
+ startedAtMs: number;
121
+ endedAtMs: number;
122
+ durationMs: number;
123
+ };
124
+ usage: AgentCandidateFixedSpend;
125
+ score: number;
126
+ passed: boolean;
127
+ dimensions: AgentCandidateBenchmarkDimension[];
128
+ };
129
+ digest: Sha256Digest;
130
+ }
131
+ /** One paired result from the exact same task, seed, and evaluator. */
132
+ export interface AgentProfileImprovementMeasurement {
133
+ baseline: AgentProfileImprovementRunReceipt;
134
+ candidate: AgentProfileImprovementRunReceipt;
135
+ }
136
+ /** Portable paired comparison from ordinary profile executions. */
137
+ export interface AgentProfileImprovementMeasuredComparison extends AgentImprovementMeasuredComparisonBase<AgentProfileImprovementExperiment, AgentProfileImprovementMeasurement, "agent-profile-improvement-measured-comparison"> {
138
+ kind: "agent-profile-improvement-measured-comparison";
139
+ }
@@ -0,0 +1 @@
1
+ export {};