@tangle-network/agent-interface 0.33.0 → 0.35.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 (36) 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 +1418 -885
  7. package/dist/agent-candidate-promotion-schema.js +55 -346
  8. package/dist/agent-candidate-receipt-schema.d.ts +9 -11
  9. package/dist/agent-candidate-receipt-schema.js +1 -0
  10. package/dist/agent-candidate-schema.d.ts +0 -6
  11. package/dist/agent-candidate-schema.js +1 -3
  12. package/dist/agent-candidate.d.ts +15 -7
  13. package/dist/agent-execution-limits.d.ts +28 -0
  14. package/dist/agent-execution-limits.js +77 -0
  15. package/dist/agent-improvement-measurement-schema.d.ts +198 -0
  16. package/dist/agent-improvement-measurement-schema.js +349 -0
  17. package/dist/agent-improvement-source.d.ts +23 -0
  18. package/dist/agent-improvement-source.js +38 -0
  19. package/dist/agent-profile-improvement-schema.d.ts +1088 -0
  20. package/dist/agent-profile-improvement-schema.js +560 -0
  21. package/dist/agent-profile-improvement.d.ts +140 -0
  22. package/dist/agent-profile-improvement.js +1 -0
  23. package/dist/agent-profile.d.ts +2 -2
  24. package/dist/agent-profile.js +2 -2
  25. package/dist/harness-capabilities.d.ts +1 -1
  26. package/dist/harness-capabilities.js +9 -12
  27. package/dist/harness.d.ts +1 -10
  28. package/dist/harness.js +0 -13
  29. package/dist/index.d.ts +8 -1
  30. package/dist/index.js +6 -0
  31. package/dist/interaction.d.ts +0 -17
  32. package/dist/interaction.js +0 -23
  33. package/dist/number-validation.d.ts +1 -0
  34. package/dist/number-validation.js +4 -0
  35. package/dist/profile-schema.d.ts +0 -3
  36. package/package.json +1 -1
@@ -0,0 +1,349 @@
1
+ import { z } from "zod";
2
+ import { isCanonicalJsonValue, sha256DigestSchema } from "./agent-candidate-schema-common.js";
3
+ import { numbersApproximatelyEqual } from "./number-validation.js";
4
+ export const canonicalJsonSchema = z.custom(isCanonicalJsonValue, "value must be finite, acyclic RFC 8785 JSON");
5
+ export const canonicalJsonObjectSchema = z
6
+ .record(z.string(), canonicalJsonSchema)
7
+ .refine(isCanonicalJsonValue, "value must be finite, acyclic RFC 8785 JSON");
8
+ const confidenceIntervalSchema = z
9
+ .object({
10
+ level: z.number().finite().gt(0).lt(1),
11
+ lower: z.number().finite(),
12
+ upper: z.number().finite(),
13
+ method: z.literal("paired-bootstrap"),
14
+ statistic: z.literal("mean"),
15
+ resamples: z.number().int().positive(),
16
+ })
17
+ .strict();
18
+ const measuredEstimateFields = {
19
+ baseline: z.number().finite(),
20
+ candidate: z.number().finite(),
21
+ delta: z.number().finite(),
22
+ confidenceInterval: confidenceIntervalSchema,
23
+ n: z.number().int().positive(),
24
+ };
25
+ const qualityObjectiveFields = {
26
+ kind: z.literal("objective"),
27
+ name: z.string().min(1),
28
+ direction: z.literal("higher-is-better"),
29
+ unit: z.literal("score"),
30
+ };
31
+ const qualityDimensionFields = {
32
+ kind: z.literal("dimension"),
33
+ objective: z.string().min(1),
34
+ name: z.string().min(1),
35
+ direction: z.literal("higher-is-better"),
36
+ unit: z.literal("score"),
37
+ };
38
+ const costObjectiveFields = {
39
+ kind: z.literal("cost"),
40
+ name: z.literal("cost"),
41
+ direction: z.literal("lower-is-better"),
42
+ unit: z.literal("usd"),
43
+ };
44
+ const latencyObjectiveFields = {
45
+ kind: z.literal("latency"),
46
+ name: z.literal("latency"),
47
+ direction: z.literal("lower-is-better"),
48
+ unit: z.literal("milliseconds"),
49
+ };
50
+ function measuredObjectiveVariant(fields) {
51
+ return z
52
+ .object({
53
+ ...fields,
54
+ availability: z.literal("measured"),
55
+ ...measuredEstimateFields,
56
+ })
57
+ .strict();
58
+ }
59
+ function unavailableObjectiveVariant(fields) {
60
+ return z
61
+ .object({
62
+ ...fields,
63
+ availability: z.literal("unavailable"),
64
+ reason: z.string().min(1),
65
+ })
66
+ .strict();
67
+ }
68
+ const measuredObjectiveSchema = z.union([
69
+ measuredObjectiveVariant(qualityObjectiveFields),
70
+ unavailableObjectiveVariant(qualityObjectiveFields),
71
+ measuredObjectiveVariant(qualityDimensionFields),
72
+ unavailableObjectiveVariant(qualityDimensionFields),
73
+ measuredObjectiveVariant(costObjectiveFields),
74
+ measuredObjectiveVariant(latencyObjectiveFields),
75
+ ]);
76
+ export const agentCandidateEvaluationPolicySchema = z
77
+ .object({
78
+ confidenceLevel: z.number().finite().gt(0).lt(1),
79
+ resamples: z.number().int().min(100),
80
+ bootstrapSeed: z.number().int().safe(),
81
+ deltaThreshold: z.number().finite().nonnegative(),
82
+ minProductiveRuns: z.number().int().min(3),
83
+ budgetUsd: z.number().finite().nonnegative().optional(),
84
+ criticalDimensions: z.array(z.string().min(1)),
85
+ regressionTolerance: z.number().finite().nonnegative(),
86
+ })
87
+ .strict()
88
+ .superRefine((policy, ctx) => {
89
+ if (new Set(policy.criticalDimensions).size !== policy.criticalDimensions.length ||
90
+ policy.criticalDimensions.some((name, index) => index > 0 && policy.criticalDimensions[index - 1] >= name)) {
91
+ ctx.addIssue({
92
+ code: "custom",
93
+ path: ["criticalDimensions"],
94
+ message: "critical dimensions must be sorted and unique",
95
+ });
96
+ }
97
+ });
98
+ export const measuredComparisonCommonShape = {
99
+ overall: z
100
+ .object({
101
+ name: z.literal("composite"),
102
+ ...measuredEstimateFields,
103
+ direction: z.literal("higher-is-better"),
104
+ unit: z.literal("score"),
105
+ })
106
+ .strict(),
107
+ objectives: z.array(measuredObjectiveSchema),
108
+ candidate: z
109
+ .object({
110
+ label: z.string().min(1).optional(),
111
+ rationale: z.string().min(1).optional(),
112
+ })
113
+ .strict()
114
+ .refine((candidate) => candidate.label !== undefined || candidate.rationale !== undefined, "candidate metadata requires a label or rationale")
115
+ .optional(),
116
+ decision: z
117
+ .object({
118
+ outcome: z.enum([
119
+ "ship",
120
+ "hold",
121
+ "need_more_work",
122
+ "model_ceiling",
123
+ "arch_ceiling",
124
+ ]),
125
+ reasons: z.array(z.string().min(1)).min(1),
126
+ contributingChecks: z.array(z.object({ name: z.string().min(1), passed: z.boolean() }).strict()),
127
+ })
128
+ .strict(),
129
+ power: z
130
+ .object({
131
+ sufficient: z.boolean(),
132
+ n: z.number().int().positive(),
133
+ minimumDetectableDelta: z.number().finite().nonnegative(),
134
+ confidenceLevel: z.number().finite().gt(0).lt(1),
135
+ scaleAssumed: z.boolean(),
136
+ sharedScorerChannel: z.boolean(),
137
+ reason: z.string().min(1),
138
+ })
139
+ .strict(),
140
+ provenance: z
141
+ .object({
142
+ kind: z.literal("agent-eval-loop"),
143
+ schema: z.string().min(1),
144
+ runId: z.string().min(1),
145
+ recordDigest: sha256DigestSchema,
146
+ baselineContentHash: z.string().regex(/^(?:sha256:)?[a-f0-9]{64}$/),
147
+ candidateContentHash: z.string().regex(/^(?:sha256:)?[a-f0-9]{64}$/),
148
+ })
149
+ .strict(),
150
+ diff: z.string(),
151
+ evaluation: z
152
+ .object({
153
+ generationsExplored: z.number().int().nonnegative(),
154
+ searchDurationMs: z.number().finite().nonnegative(),
155
+ executionDurationMs: z.number().finite().nonnegative(),
156
+ durationMs: z.number().finite().nonnegative(),
157
+ searchCostUsd: z.number().finite().nonnegative(),
158
+ executionCostUsd: z.number().finite().nonnegative(),
159
+ totalCostUsd: z.number().finite().nonnegative(),
160
+ })
161
+ .strict(),
162
+ metadata: canonicalJsonObjectSchema.optional(),
163
+ };
164
+ /** Keep receipt identity reuse rules identical across measured source formats. */
165
+ export function createMeasuredComparisonIdentityRegistry(options) {
166
+ const seen = new Map();
167
+ return (identities, fallbackPath) => {
168
+ for (const identity of identities) {
169
+ const used = seen.get(identity.kind) ?? new Set();
170
+ if (used.has(identity.value)) {
171
+ options.ctx.addIssue({
172
+ code: "custom",
173
+ path: identity.path ?? fallbackPath,
174
+ message: `${options.identityLabel} must not reuse ${identity.kind} identity`,
175
+ });
176
+ }
177
+ used.add(identity.value);
178
+ seen.set(identity.kind, used);
179
+ }
180
+ };
181
+ }
182
+ export function refineMeasuredComparisonSummary(comparison, policy, expectedN, measurements, values, ctx) {
183
+ refineEstimate(comparison.overall, ["overall"], ctx);
184
+ if (!numbersApproximatelyEqual(comparison.evaluation.durationMs, comparison.evaluation.searchDurationMs + comparison.evaluation.executionDurationMs) ||
185
+ !numbersApproximatelyEqual(comparison.evaluation.totalCostUsd, comparison.evaluation.searchCostUsd + comparison.evaluation.executionCostUsd)) {
186
+ ctx.addIssue({
187
+ code: "custom",
188
+ path: ["evaluation"],
189
+ message: "evaluation totals must equal their search and execution components",
190
+ });
191
+ }
192
+ if (comparison.overall.n !== expectedN) {
193
+ ctx.addIssue({
194
+ code: "custom",
195
+ path: ["overall", "n"],
196
+ message: "measured sample count must equal the complete benchmark suite",
197
+ });
198
+ }
199
+ if (measurements.length > 0) {
200
+ refineMeasuredMean(comparison.overall.baseline, measurements.map((measurement) => values.score(measurement.baseline)), ["overall", "baseline"], ctx);
201
+ refineMeasuredMean(comparison.overall.candidate, measurements.map((measurement) => values.score(measurement.candidate)), ["overall", "candidate"], ctx);
202
+ }
203
+ const identities = new Set();
204
+ const qualityObjectives = new Set();
205
+ const dimensionParents = [];
206
+ let costCount = 0;
207
+ let latencyCount = 0;
208
+ for (const [index, objective] of comparison.objectives.entries()) {
209
+ if (objective.availability === "measured") {
210
+ refineEstimate(objective, ["objectives", index], ctx);
211
+ if (objective.n !== expectedN) {
212
+ ctx.addIssue({
213
+ code: "custom",
214
+ path: ["objectives", index, "n"],
215
+ message: "measured objective count must equal the complete benchmark suite",
216
+ });
217
+ }
218
+ if (measurements.length > 0) {
219
+ const extractor = objective.kind === "objective"
220
+ ? values.score
221
+ : objective.kind === "dimension"
222
+ ? (receipt) => values.dimension(receipt, objective.name)
223
+ : objective.kind === "cost"
224
+ ? values.cost
225
+ : values.latency;
226
+ const baseline = measurements.map((measurement) => extractor(measurement.baseline));
227
+ const candidate = measurements.map((measurement) => extractor(measurement.candidate));
228
+ const baselineValues = baseline.filter((value) => value !== undefined);
229
+ const candidateValues = candidate.filter((value) => value !== undefined);
230
+ if (baselineValues.length !== baseline.length ||
231
+ candidateValues.length !== candidate.length) {
232
+ ctx.addIssue({
233
+ code: "custom",
234
+ path: ["objectives", index, "name"],
235
+ message: "every signed receipt must include each measured dimension",
236
+ });
237
+ }
238
+ else {
239
+ refineMeasuredMean(objective.baseline, baselineValues, ["objectives", index, "baseline"], ctx);
240
+ refineMeasuredMean(objective.candidate, candidateValues, ["objectives", index, "candidate"], ctx);
241
+ }
242
+ }
243
+ }
244
+ const identity = objective.kind === "dimension"
245
+ ? `${objective.kind}:${objective.objective}:${objective.name}`
246
+ : `${objective.kind}:${objective.name}`;
247
+ if (identities.has(identity)) {
248
+ ctx.addIssue({
249
+ code: "custom",
250
+ path: ["objectives", index, "name"],
251
+ message: "measured objective identities must be unique",
252
+ });
253
+ }
254
+ identities.add(identity);
255
+ if (objective.kind === "objective") {
256
+ qualityObjectives.add(objective.name);
257
+ }
258
+ else if (objective.kind === "dimension") {
259
+ dimensionParents.push({ index, objective: objective.objective });
260
+ }
261
+ else if (objective.kind === "cost") {
262
+ costCount += 1;
263
+ }
264
+ else if (objective.kind === "latency") {
265
+ latencyCount += 1;
266
+ }
267
+ }
268
+ if (costCount !== 1 || latencyCount !== 1) {
269
+ ctx.addIssue({
270
+ code: "custom",
271
+ path: ["objectives"],
272
+ message: "measured comparison must contain exactly one cost and latency objective",
273
+ });
274
+ }
275
+ if (qualityObjectives.size === 0) {
276
+ ctx.addIssue({
277
+ code: "custom",
278
+ path: ["objectives"],
279
+ message: "measured comparison must contain at least one quality objective",
280
+ });
281
+ }
282
+ for (const parent of dimensionParents) {
283
+ if (!qualityObjectives.has(parent.objective)) {
284
+ ctx.addIssue({
285
+ code: "custom",
286
+ path: ["objectives", parent.index, "objective"],
287
+ message: "measured dimension must name a present quality objective",
288
+ });
289
+ }
290
+ }
291
+ if (comparison.power.n !== expectedN) {
292
+ ctx.addIssue({
293
+ code: "custom",
294
+ path: ["power", "n"],
295
+ message: "power analysis must use the paired held-out sample",
296
+ });
297
+ }
298
+ if (comparison.overall.confidenceInterval.level !== policy.confidenceLevel ||
299
+ comparison.overall.confidenceInterval.resamples !== policy.resamples ||
300
+ comparison.power.confidenceLevel !== policy.confidenceLevel) {
301
+ ctx.addIssue({
302
+ code: "custom",
303
+ path: ["experiment", "policy"],
304
+ message: "reported uncertainty must use the frozen evaluation policy",
305
+ });
306
+ }
307
+ for (const [index, objective] of comparison.objectives.entries()) {
308
+ if (objective.availability === "measured" &&
309
+ (objective.confidenceInterval.level !== policy.confidenceLevel ||
310
+ objective.confidenceInterval.resamples !== policy.resamples)) {
311
+ ctx.addIssue({
312
+ code: "custom",
313
+ path: ["objectives", index, "confidenceInterval"],
314
+ message: "objective uncertainty must use the frozen evaluation policy",
315
+ });
316
+ }
317
+ }
318
+ }
319
+ export function refineEstimate(estimate, path, ctx) {
320
+ const expectedDelta = estimate.candidate - estimate.baseline;
321
+ const tolerance = Number.EPSILON * Math.max(1, Math.abs(expectedDelta)) * 8;
322
+ if (Math.abs(estimate.delta - expectedDelta) > tolerance) {
323
+ ctx.addIssue({
324
+ code: "custom",
325
+ path: [...path, "delta"],
326
+ message: "measured delta must equal candidate minus baseline",
327
+ });
328
+ }
329
+ if (estimate.confidenceInterval.lower > estimate.confidenceInterval.upper ||
330
+ estimate.delta < estimate.confidenceInterval.lower ||
331
+ estimate.delta > estimate.confidenceInterval.upper) {
332
+ ctx.addIssue({
333
+ code: "custom",
334
+ path: [...path, "confidenceInterval"],
335
+ message: "confidence interval must be ordered and contain the measured delta",
336
+ });
337
+ }
338
+ }
339
+ function refineMeasuredMean(reported, values, path, ctx) {
340
+ const measured = values.reduce((sum, value) => sum + value, 0) / values.length;
341
+ const tolerance = Number.EPSILON * Math.max(1, Math.abs(measured)) * values.length * 8;
342
+ if (Math.abs(reported - measured) > tolerance) {
343
+ ctx.addIssue({
344
+ code: "custom",
345
+ path,
346
+ message: "reported mean must equal the signed per-cell results",
347
+ });
348
+ }
349
+ }
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import type { AgentCandidateJsonValue } from "./agent-candidate.js";
3
+ /** Metadata key that binds a measured improvement to its exact external source. */
4
+ export declare const AGENT_IMPROVEMENT_SOURCE_METADATA_KEY = "agentImprovementSource";
5
+ /**
6
+ * Stable reference for the state from which an improvement candidate was made.
7
+ * `sourceIdentity` identifies the provider object; `sourceDigest` is the exact
8
+ * measured source state; `sourceRevision` is an
9
+ * opaque provider version retained to make stale-source errors intelligible to
10
+ * callers. A revision may be numeric or textual because providers use both
11
+ * counters and immutable revision identifiers.
12
+ */
13
+ export declare const agentImprovementSourceSchema: z.ZodObject<{
14
+ kind: z.ZodString;
15
+ sourceIdentity: z.ZodString;
16
+ sourceDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
17
+ sourceRevision: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
18
+ }, z.core.$strict>;
19
+ export type AgentImprovementSource = z.infer<typeof agentImprovementSourceSchema>;
20
+ /** Attach one validated source reference to signed improvement metadata. */
21
+ export declare function agentImprovementSourceMetadata(source: AgentImprovementSource): Record<string, AgentCandidateJsonValue>;
22
+ /** Read the exact source reference from a signed improvement proposal. */
23
+ export declare function readAgentImprovementSource(metadata: unknown): AgentImprovementSource;
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ import { sha256DigestSchema } from "./agent-candidate-schema-common.js";
3
+ /** Metadata key that binds a measured improvement to its exact external source. */
4
+ export const AGENT_IMPROVEMENT_SOURCE_METADATA_KEY = "agentImprovementSource";
5
+ /**
6
+ * Stable reference for the state from which an improvement candidate was made.
7
+ * `sourceIdentity` identifies the provider object; `sourceDigest` is the exact
8
+ * measured source state; `sourceRevision` is an
9
+ * opaque provider version retained to make stale-source errors intelligible to
10
+ * callers. A revision may be numeric or textual because providers use both
11
+ * counters and immutable revision identifiers.
12
+ */
13
+ export const agentImprovementSourceSchema = z
14
+ .object({
15
+ kind: z.string().trim().min(1).max(100).regex(/^[a-z][a-z0-9-]*$/),
16
+ sourceIdentity: z.string().trim().min(1).max(256),
17
+ sourceDigest: sha256DigestSchema,
18
+ sourceRevision: z.union([
19
+ z.string().trim().min(1).max(256),
20
+ z.number().int().nonnegative(),
21
+ ]),
22
+ })
23
+ .strict();
24
+ /** Attach one validated source reference to signed improvement metadata. */
25
+ export function agentImprovementSourceMetadata(source) {
26
+ return {
27
+ [AGENT_IMPROVEMENT_SOURCE_METADATA_KEY]: agentImprovementSourceSchema.parse(source),
28
+ };
29
+ }
30
+ /** Read the exact source reference from a signed improvement proposal. */
31
+ export function readAgentImprovementSource(metadata) {
32
+ const record = z.record(z.string(), z.unknown()).parse(metadata);
33
+ const source = record[AGENT_IMPROVEMENT_SOURCE_METADATA_KEY];
34
+ if (source === undefined) {
35
+ throw new Error("signed improvement proposal is missing its source reference");
36
+ }
37
+ return agentImprovementSourceSchema.parse(source);
38
+ }