@tangle-network/agent-interface 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-candidate-execution-plan-schema.d.ts +24 -0
- package/dist/agent-candidate-execution-plan-schema.js +57 -1
- package/dist/agent-candidate-outcome-schema.d.ts +618 -0
- package/dist/agent-candidate-outcome-schema.js +293 -0
- package/dist/agent-candidate-receipt-schema.d.ts +1399 -0
- package/dist/agent-candidate-receipt-schema.js +125 -0
- package/dist/agent-candidate-schema.d.ts +1 -0
- package/dist/agent-candidate-schema.js +1 -0
- package/dist/agent-candidate.d.ts +124 -0
- package/package.json +1 -1
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { agentCandidateArtifactRefSchema, agentCandidateCapturedArtifactSchema, agentCandidateWorkspaceSnapshotEvidenceSchema, } from "./agent-candidate-artifact-schema.js";
|
|
3
|
+
import { agentCandidateResolvedModelSchema } from "./agent-candidate-execution-plan-schema.js";
|
|
4
|
+
import { gitObjectSchema, isCanonicalJsonValue, sameGitObjectFormat, sha256DigestSchema, } from "./agent-candidate-schema-common.js";
|
|
5
|
+
const safeCountSchema = z
|
|
6
|
+
.number()
|
|
7
|
+
.int()
|
|
8
|
+
.nonnegative()
|
|
9
|
+
.refine(Number.isSafeInteger, "value must be a nonnegative safe integer");
|
|
10
|
+
const boundedIdentifierSchema = z.string().min(1).max(256);
|
|
11
|
+
const normalizedDimensionNameSchema = z
|
|
12
|
+
.string()
|
|
13
|
+
.regex(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/, "dimension names must be normalized lowercase identifiers");
|
|
14
|
+
const normalizedScoreSchema = z.number().finite().min(0).max(1);
|
|
15
|
+
export const agentCandidateFixedSpendSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
inputTokens: safeCountSchema,
|
|
18
|
+
outputTokens: safeCountSchema,
|
|
19
|
+
cachedInputTokens: safeCountSchema,
|
|
20
|
+
reasoningTokens: safeCountSchema,
|
|
21
|
+
modelCalls: safeCountSchema,
|
|
22
|
+
costUsdNanos: safeCountSchema,
|
|
23
|
+
})
|
|
24
|
+
.strict();
|
|
25
|
+
export const agentCandidateModelSettlementCallSchema = z
|
|
26
|
+
.object({
|
|
27
|
+
callId: boundedIdentifierSchema,
|
|
28
|
+
traceSpanId: boundedIdentifierSchema,
|
|
29
|
+
model: boundedIdentifierSchema,
|
|
30
|
+
inputTokens: safeCountSchema,
|
|
31
|
+
outputTokens: safeCountSchema,
|
|
32
|
+
cachedInputTokens: safeCountSchema,
|
|
33
|
+
reasoningTokens: safeCountSchema,
|
|
34
|
+
costUsdNanos: safeCountSchema,
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
export const agentCandidateModelSettlementMaterialSchema = z
|
|
38
|
+
.object({
|
|
39
|
+
schemaVersion: z.literal(1),
|
|
40
|
+
kind: z.literal("agent-candidate-model-settlement-material"),
|
|
41
|
+
executionPlanDigest: sha256DigestSchema,
|
|
42
|
+
preparationId: boundedIdentifierSchema,
|
|
43
|
+
grantDigest: sha256DigestSchema,
|
|
44
|
+
closed: z.literal(true),
|
|
45
|
+
resolved: agentCandidateResolvedModelSchema,
|
|
46
|
+
calls: z.array(agentCandidateModelSettlementCallSchema),
|
|
47
|
+
usage: agentCandidateFixedSpendSchema,
|
|
48
|
+
})
|
|
49
|
+
.strict()
|
|
50
|
+
.superRefine((material, ctx) => {
|
|
51
|
+
const callIds = new Set();
|
|
52
|
+
const traceSpanIds = new Set();
|
|
53
|
+
const totals = {
|
|
54
|
+
inputTokens: 0,
|
|
55
|
+
outputTokens: 0,
|
|
56
|
+
cachedInputTokens: 0,
|
|
57
|
+
reasoningTokens: 0,
|
|
58
|
+
modelCalls: material.calls.length,
|
|
59
|
+
costUsdNanos: 0,
|
|
60
|
+
};
|
|
61
|
+
for (const [index, call] of material.calls.entries()) {
|
|
62
|
+
if (callIds.has(call.callId)) {
|
|
63
|
+
ctx.addIssue({
|
|
64
|
+
code: "custom",
|
|
65
|
+
path: ["calls", index, "callId"],
|
|
66
|
+
message: "model settlement call ids must be unique",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
callIds.add(call.callId);
|
|
70
|
+
if (traceSpanIds.has(call.traceSpanId)) {
|
|
71
|
+
ctx.addIssue({
|
|
72
|
+
code: "custom",
|
|
73
|
+
path: ["calls", index, "traceSpanId"],
|
|
74
|
+
message: "model settlement trace span ids must be unique",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
traceSpanIds.add(call.traceSpanId);
|
|
78
|
+
if (call.model !== material.resolved.model) {
|
|
79
|
+
ctx.addIssue({
|
|
80
|
+
code: "custom",
|
|
81
|
+
path: ["calls", index, "model"],
|
|
82
|
+
message: "settled call model must match the resolved single model",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
for (const field of [
|
|
86
|
+
"inputTokens",
|
|
87
|
+
"outputTokens",
|
|
88
|
+
"cachedInputTokens",
|
|
89
|
+
"reasoningTokens",
|
|
90
|
+
"costUsdNanos",
|
|
91
|
+
]) {
|
|
92
|
+
const sum = totals[field] + call[field];
|
|
93
|
+
if (!Number.isSafeInteger(sum)) {
|
|
94
|
+
ctx.addIssue({
|
|
95
|
+
code: "custom",
|
|
96
|
+
path: ["calls", index, field],
|
|
97
|
+
message: `model settlement ${field} total exceeds safe integer range`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
totals[field] = sum;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (!sameFixedSpend(totals, material.usage)) {
|
|
106
|
+
ctx.addIssue({
|
|
107
|
+
code: "custom",
|
|
108
|
+
path: ["usage"],
|
|
109
|
+
message: "model settlement usage must equal the exact per-call aggregate",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (!isCanonicalJsonValue(material)) {
|
|
113
|
+
ctx.addIssue({
|
|
114
|
+
code: "custom",
|
|
115
|
+
message: "model settlement material must contain only RFC 8785 JSON values",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
export const agentCandidateModelSettlementEvidenceSchema = evidenceSchema("agent-candidate-model-settlement", agentCandidateModelSettlementMaterialSchema, "model settlement");
|
|
120
|
+
export const agentCandidateRepositoryStateSchema = z
|
|
121
|
+
.object({
|
|
122
|
+
identity: z.string().min(1),
|
|
123
|
+
rootIdentity: z.string().min(1),
|
|
124
|
+
commit: gitObjectSchema,
|
|
125
|
+
tree: gitObjectSchema,
|
|
126
|
+
})
|
|
127
|
+
.strict()
|
|
128
|
+
.superRefine((state, ctx) => {
|
|
129
|
+
if (!sameGitObjectFormat(state.commit, state.tree)) {
|
|
130
|
+
ctx.addIssue({
|
|
131
|
+
code: "custom",
|
|
132
|
+
path: ["tree"],
|
|
133
|
+
message: "repository commit and tree must use the same Git object format",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
export const agentCandidateTaskOutcomeMaterialSchema = z
|
|
138
|
+
.object({
|
|
139
|
+
schemaVersion: z.literal(1),
|
|
140
|
+
kind: z.literal("agent-candidate-task-outcome-material"),
|
|
141
|
+
executionPlanDigest: sha256DigestSchema,
|
|
142
|
+
baseRepository: agentCandidateRepositoryStateSchema,
|
|
143
|
+
resultRepository: agentCandidateRepositoryStateSchema,
|
|
144
|
+
afterState: agentCandidateWorkspaceSnapshotEvidenceSchema,
|
|
145
|
+
gitDiff: z
|
|
146
|
+
.object({
|
|
147
|
+
format: z.literal("git-diff-binary"),
|
|
148
|
+
artifact: agentCandidateArtifactRefSchema,
|
|
149
|
+
})
|
|
150
|
+
.strict(),
|
|
151
|
+
})
|
|
152
|
+
.strict()
|
|
153
|
+
.superRefine((material, ctx) => {
|
|
154
|
+
if (material.baseRepository.identity !== material.resultRepository.identity) {
|
|
155
|
+
ctx.addIssue({
|
|
156
|
+
code: "custom",
|
|
157
|
+
path: ["resultRepository", "identity"],
|
|
158
|
+
message: "base and result repository identities must match",
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (material.baseRepository.rootIdentity !==
|
|
162
|
+
material.resultRepository.rootIdentity) {
|
|
163
|
+
ctx.addIssue({
|
|
164
|
+
code: "custom",
|
|
165
|
+
path: ["resultRepository", "rootIdentity"],
|
|
166
|
+
message: "base and result repository roots must match",
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (!sameGitObjectFormat(material.baseRepository.commit, material.resultRepository.commit) ||
|
|
170
|
+
!sameGitObjectFormat(material.baseRepository.tree, material.resultRepository.tree)) {
|
|
171
|
+
ctx.addIssue({
|
|
172
|
+
code: "custom",
|
|
173
|
+
path: ["resultRepository"],
|
|
174
|
+
message: "base and result repositories must use one Git object format",
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (!isCanonicalJsonValue(material)) {
|
|
178
|
+
ctx.addIssue({
|
|
179
|
+
code: "custom",
|
|
180
|
+
message: "task outcome material must contain only RFC 8785 JSON values",
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
export const agentCandidateTaskOutcomeEvidenceSchema = evidenceSchema("agent-candidate-task-outcome", agentCandidateTaskOutcomeMaterialSchema, "task outcome");
|
|
185
|
+
export const agentCandidateBenchmarkDimensionSchema = z
|
|
186
|
+
.object({
|
|
187
|
+
name: normalizedDimensionNameSchema,
|
|
188
|
+
score: normalizedScoreSchema,
|
|
189
|
+
})
|
|
190
|
+
.strict();
|
|
191
|
+
export const agentCandidateBenchmarkResultMaterialSchema = z
|
|
192
|
+
.object({
|
|
193
|
+
schemaVersion: z.literal(1),
|
|
194
|
+
kind: z.literal("agent-candidate-benchmark-result-material"),
|
|
195
|
+
executionPlanDigest: sha256DigestSchema,
|
|
196
|
+
taskOutcomeDigest: sha256DigestSchema,
|
|
197
|
+
benchmark: z
|
|
198
|
+
.object({
|
|
199
|
+
name: z.string().min(1),
|
|
200
|
+
version: z.string().min(1),
|
|
201
|
+
taskId: z.string().min(1),
|
|
202
|
+
splitDigest: sha256DigestSchema,
|
|
203
|
+
})
|
|
204
|
+
.strict(),
|
|
205
|
+
grader: z
|
|
206
|
+
.object({
|
|
207
|
+
name: z.string().min(1),
|
|
208
|
+
version: z.string().min(1),
|
|
209
|
+
artifact: agentCandidateArtifactRefSchema,
|
|
210
|
+
})
|
|
211
|
+
.strict(),
|
|
212
|
+
evidence: agentCandidateArtifactRefSchema,
|
|
213
|
+
score: normalizedScoreSchema,
|
|
214
|
+
passed: z.boolean(),
|
|
215
|
+
dimensions: z.array(agentCandidateBenchmarkDimensionSchema),
|
|
216
|
+
})
|
|
217
|
+
.strict()
|
|
218
|
+
.superRefine((material, ctx) => {
|
|
219
|
+
if (material.grader.artifact.byteLength === 0) {
|
|
220
|
+
ctx.addIssue({
|
|
221
|
+
code: "custom",
|
|
222
|
+
path: ["grader", "artifact", "byteLength"],
|
|
223
|
+
message: "pinned grader artifact must contain executable grader bytes",
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
if (material.evidence.byteLength === 0) {
|
|
227
|
+
ctx.addIssue({
|
|
228
|
+
code: "custom",
|
|
229
|
+
path: ["evidence", "byteLength"],
|
|
230
|
+
message: "benchmark result must contain non-empty durable grading evidence",
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
if (material.evidence.sha256 === material.grader.artifact.sha256) {
|
|
234
|
+
ctx.addIssue({
|
|
235
|
+
code: "custom",
|
|
236
|
+
path: ["evidence", "sha256"],
|
|
237
|
+
message: "grading evidence must be distinct from the grader implementation",
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
for (let index = 1; index < material.dimensions.length; index++) {
|
|
241
|
+
const previous = material.dimensions[index - 1]?.name ?? "";
|
|
242
|
+
const current = material.dimensions[index]?.name ?? "";
|
|
243
|
+
if (previous >= current) {
|
|
244
|
+
ctx.addIssue({
|
|
245
|
+
code: "custom",
|
|
246
|
+
path: ["dimensions", index, "name"],
|
|
247
|
+
message: "benchmark dimensions must be unique and lexicographically sorted",
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (!isCanonicalJsonValue(material)) {
|
|
252
|
+
ctx.addIssue({
|
|
253
|
+
code: "custom",
|
|
254
|
+
message: "benchmark result material must contain only RFC 8785 JSON values",
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
export const agentCandidateBenchmarkResultEvidenceSchema = evidenceSchema("agent-candidate-benchmark-result", agentCandidateBenchmarkResultMaterialSchema, "benchmark result");
|
|
259
|
+
export function sameFixedSpend(left, right) {
|
|
260
|
+
return (left.inputTokens === right.inputTokens &&
|
|
261
|
+
left.outputTokens === right.outputTokens &&
|
|
262
|
+
left.cachedInputTokens === right.cachedInputTokens &&
|
|
263
|
+
left.reasoningTokens === right.reasoningTokens &&
|
|
264
|
+
left.modelCalls === right.modelCalls &&
|
|
265
|
+
left.costUsdNanos === right.costUsdNanos);
|
|
266
|
+
}
|
|
267
|
+
function evidenceSchema(kind, material, label) {
|
|
268
|
+
return z
|
|
269
|
+
.object({
|
|
270
|
+
schemaVersion: z.literal(1),
|
|
271
|
+
kind: z.literal(kind),
|
|
272
|
+
digest: sha256DigestSchema,
|
|
273
|
+
material,
|
|
274
|
+
artifact: agentCandidateCapturedArtifactSchema,
|
|
275
|
+
})
|
|
276
|
+
.strict()
|
|
277
|
+
.superRefine((evidence, ctx) => {
|
|
278
|
+
if (evidence.artifact.sha256 !== evidence.digest) {
|
|
279
|
+
ctx.addIssue({
|
|
280
|
+
code: "custom",
|
|
281
|
+
path: ["artifact", "sha256"],
|
|
282
|
+
message: `${label} artifact hash must equal its canonical material digest`,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
if (evidence.artifact.byteLength === 0) {
|
|
286
|
+
ctx.addIssue({
|
|
287
|
+
code: "custom",
|
|
288
|
+
path: ["artifact", "byteLength"],
|
|
289
|
+
message: `${label} artifact must contain canonical material bytes`,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|