@plaited/agent-eval-harness 0.5.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/LICENSE +15 -0
- package/README.md +273 -0
- package/bin/cli.ts +162 -0
- package/bin/tests/cli.spec.ts +529 -0
- package/package.json +67 -0
- package/src/commands/balance.ts +257 -0
- package/src/commands/calibrate.ts +313 -0
- package/src/commands/capture.ts +393 -0
- package/src/commands/summarize.ts +228 -0
- package/src/commands/tests/balance-helpers.spec.ts +279 -0
- package/src/commands/tests/calibrate-helpers.spec.ts +226 -0
- package/src/commands/tests/capture-cli.spec.ts +190 -0
- package/src/commands/tests/capture-helpers.spec.ts +524 -0
- package/src/commands/tests/summarize-helpers.spec.ts +339 -0
- package/src/commands/tests/trials-calculations.spec.ts +209 -0
- package/src/commands/tests/trials-cli.spec.ts +147 -0
- package/src/commands/trials.ts +388 -0
- package/src/commands/validate-refs.ts +188 -0
- package/src/commands.ts +33 -0
- package/src/core/core.ts +25 -0
- package/src/core/loading.ts +96 -0
- package/src/core/output.ts +121 -0
- package/src/core/tests/core.spec.ts +309 -0
- package/src/core/trajectory.ts +166 -0
- package/src/core.ts +28 -0
- package/src/harness.ts +46 -0
- package/src/headless/headless-cli.ts +430 -0
- package/src/headless/headless-history-builder.ts +141 -0
- package/src/headless/headless-output-parser.ts +366 -0
- package/src/headless/headless-session-manager.ts +587 -0
- package/src/headless/headless.schemas.ts +310 -0
- package/src/headless/headless.types.ts +19 -0
- package/src/headless/tests/headless.spec.ts +678 -0
- package/src/headless.ts +72 -0
- package/src/integration_tests/claude.spec.ts +157 -0
- package/src/integration_tests/gemini.spec.ts +139 -0
- package/src/pipeline/compare.ts +325 -0
- package/src/pipeline/extract.ts +241 -0
- package/src/pipeline/format.ts +292 -0
- package/src/pipeline/grade.ts +169 -0
- package/src/pipeline/pipeline.ts +41 -0
- package/src/pipeline/pipeline.types.ts +241 -0
- package/src/pipeline/run.ts +412 -0
- package/src/pipeline/tests/pipeline.spec.ts +356 -0
- package/src/pipeline.ts +34 -0
- package/src/schemas/constants.ts +94 -0
- package/src/schemas/grader-loader.ts +174 -0
- package/src/schemas/schemas-cli.ts +239 -0
- package/src/schemas/schemas.ts +558 -0
- package/src/schemas/tests/constants.spec.ts +121 -0
- package/src/schemas/tests/fixtures/grader-bad-module.ts +5 -0
- package/src/schemas/tests/fixtures/grader-exec-fail.py +9 -0
- package/src/schemas/tests/fixtures/grader-exec-invalid.py +6 -0
- package/src/schemas/tests/fixtures/grader-exec.py +29 -0
- package/src/schemas/tests/fixtures/grader-module.ts +14 -0
- package/src/schemas/tests/grader-loader.spec.ts +153 -0
- package/src/schemas/tests/schemas-cli.spec.ts +142 -0
- package/src/schemas/tests/schemas.spec.ts +606 -0
- package/src/schemas.ts +90 -0
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
CaptureResultSchema,
|
|
4
|
+
EnvVariableSchema,
|
|
5
|
+
GraderResultSchema,
|
|
6
|
+
HttpHeaderSchema,
|
|
7
|
+
JsonRpcErrorResponseSchema,
|
|
8
|
+
JsonRpcErrorSchema,
|
|
9
|
+
JsonRpcMessageSchema,
|
|
10
|
+
JsonRpcNotificationSchema,
|
|
11
|
+
JsonRpcRequestSchema,
|
|
12
|
+
JsonRpcResponseSchema,
|
|
13
|
+
JsonRpcSuccessResponseSchema,
|
|
14
|
+
McpServerHttpSchema,
|
|
15
|
+
McpServerSchema,
|
|
16
|
+
McpServerStdioSchema,
|
|
17
|
+
MessageStepSchema,
|
|
18
|
+
PlanStepSchema,
|
|
19
|
+
PromptCaseSchema,
|
|
20
|
+
SessionSchema,
|
|
21
|
+
ThoughtStepSchema,
|
|
22
|
+
TimingSchema,
|
|
23
|
+
ToolCallStepSchema,
|
|
24
|
+
ToolInputSchema,
|
|
25
|
+
TrajectoryRichnessSchema,
|
|
26
|
+
TrajectoryStepSchema,
|
|
27
|
+
} from '../schemas.ts'
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Session Schema
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
describe('SessionSchema', () => {
|
|
34
|
+
test('parses valid session', () => {
|
|
35
|
+
const result = SessionSchema.safeParse({ id: 'sess_123' })
|
|
36
|
+
expect(result.success).toBe(true)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('parses session with _meta', () => {
|
|
40
|
+
const result = SessionSchema.safeParse({ id: 'sess_123', _meta: { key: 'value' } })
|
|
41
|
+
expect(result.success).toBe(true)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('rejects session without id', () => {
|
|
45
|
+
const result = SessionSchema.safeParse({})
|
|
46
|
+
expect(result.success).toBe(false)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// JSON-RPC Schemas
|
|
52
|
+
// ============================================================================
|
|
53
|
+
|
|
54
|
+
describe('JsonRpcRequestSchema', () => {
|
|
55
|
+
test('parses valid request', () => {
|
|
56
|
+
const result = JsonRpcRequestSchema.safeParse({
|
|
57
|
+
jsonrpc: '2.0',
|
|
58
|
+
id: 1,
|
|
59
|
+
method: 'test',
|
|
60
|
+
})
|
|
61
|
+
expect(result.success).toBe(true)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('parses request with params', () => {
|
|
65
|
+
const result = JsonRpcRequestSchema.safeParse({
|
|
66
|
+
jsonrpc: '2.0',
|
|
67
|
+
id: 'abc',
|
|
68
|
+
method: 'test',
|
|
69
|
+
params: { foo: 'bar' },
|
|
70
|
+
})
|
|
71
|
+
expect(result.success).toBe(true)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('rejects invalid jsonrpc version', () => {
|
|
75
|
+
const result = JsonRpcRequestSchema.safeParse({
|
|
76
|
+
jsonrpc: '1.0',
|
|
77
|
+
id: 1,
|
|
78
|
+
method: 'test',
|
|
79
|
+
})
|
|
80
|
+
expect(result.success).toBe(false)
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe('JsonRpcNotificationSchema', () => {
|
|
85
|
+
test('parses notification without id', () => {
|
|
86
|
+
const result = JsonRpcNotificationSchema.safeParse({
|
|
87
|
+
jsonrpc: '2.0',
|
|
88
|
+
method: 'notify',
|
|
89
|
+
})
|
|
90
|
+
expect(result.success).toBe(true)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('JsonRpcErrorSchema', () => {
|
|
95
|
+
test('parses error with code and message', () => {
|
|
96
|
+
const result = JsonRpcErrorSchema.safeParse({
|
|
97
|
+
code: -32600,
|
|
98
|
+
message: 'Invalid request',
|
|
99
|
+
})
|
|
100
|
+
expect(result.success).toBe(true)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('parses error with data', () => {
|
|
104
|
+
const result = JsonRpcErrorSchema.safeParse({
|
|
105
|
+
code: -32603,
|
|
106
|
+
message: 'Internal error',
|
|
107
|
+
data: { details: 'something went wrong' },
|
|
108
|
+
})
|
|
109
|
+
expect(result.success).toBe(true)
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe('JsonRpcSuccessResponseSchema', () => {
|
|
114
|
+
test('parses success response', () => {
|
|
115
|
+
const result = JsonRpcSuccessResponseSchema.safeParse({
|
|
116
|
+
jsonrpc: '2.0',
|
|
117
|
+
id: 1,
|
|
118
|
+
result: { data: 'test' },
|
|
119
|
+
})
|
|
120
|
+
expect(result.success).toBe(true)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('JsonRpcErrorResponseSchema', () => {
|
|
125
|
+
test('parses error response with id', () => {
|
|
126
|
+
const result = JsonRpcErrorResponseSchema.safeParse({
|
|
127
|
+
jsonrpc: '2.0',
|
|
128
|
+
id: 1,
|
|
129
|
+
error: { code: -32600, message: 'Invalid' },
|
|
130
|
+
})
|
|
131
|
+
expect(result.success).toBe(true)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test('parses error response with null id', () => {
|
|
135
|
+
const result = JsonRpcErrorResponseSchema.safeParse({
|
|
136
|
+
jsonrpc: '2.0',
|
|
137
|
+
id: null,
|
|
138
|
+
error: { code: -32700, message: 'Parse error' },
|
|
139
|
+
})
|
|
140
|
+
expect(result.success).toBe(true)
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
describe('JsonRpcResponseSchema', () => {
|
|
145
|
+
test('parses success response', () => {
|
|
146
|
+
const result = JsonRpcResponseSchema.safeParse({
|
|
147
|
+
jsonrpc: '2.0',
|
|
148
|
+
id: 1,
|
|
149
|
+
result: 'ok',
|
|
150
|
+
})
|
|
151
|
+
expect(result.success).toBe(true)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('parses error response', () => {
|
|
155
|
+
const result = JsonRpcResponseSchema.safeParse({
|
|
156
|
+
jsonrpc: '2.0',
|
|
157
|
+
id: 1,
|
|
158
|
+
error: { code: -32600, message: 'Invalid' },
|
|
159
|
+
})
|
|
160
|
+
expect(result.success).toBe(true)
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
describe('JsonRpcMessageSchema', () => {
|
|
165
|
+
test('parses request', () => {
|
|
166
|
+
const result = JsonRpcMessageSchema.safeParse({
|
|
167
|
+
jsonrpc: '2.0',
|
|
168
|
+
id: 1,
|
|
169
|
+
method: 'test',
|
|
170
|
+
})
|
|
171
|
+
expect(result.success).toBe(true)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
test('parses notification', () => {
|
|
175
|
+
const result = JsonRpcMessageSchema.safeParse({
|
|
176
|
+
jsonrpc: '2.0',
|
|
177
|
+
method: 'notify',
|
|
178
|
+
})
|
|
179
|
+
expect(result.success).toBe(true)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('parses response', () => {
|
|
183
|
+
const result = JsonRpcMessageSchema.safeParse({
|
|
184
|
+
jsonrpc: '2.0',
|
|
185
|
+
id: 1,
|
|
186
|
+
result: 'ok',
|
|
187
|
+
})
|
|
188
|
+
expect(result.success).toBe(true)
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// ============================================================================
|
|
193
|
+
// MCP Server Schemas
|
|
194
|
+
// ============================================================================
|
|
195
|
+
|
|
196
|
+
describe('EnvVariableSchema', () => {
|
|
197
|
+
test('parses valid env variable', () => {
|
|
198
|
+
const result = EnvVariableSchema.safeParse({ name: 'API_KEY', value: 'secret' })
|
|
199
|
+
expect(result.success).toBe(true)
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
describe('HttpHeaderSchema', () => {
|
|
204
|
+
test('parses valid header', () => {
|
|
205
|
+
const result = HttpHeaderSchema.safeParse({ name: 'Authorization', value: 'Bearer token' })
|
|
206
|
+
expect(result.success).toBe(true)
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
describe('McpServerStdioSchema', () => {
|
|
211
|
+
test('parses stdio config with optional type', () => {
|
|
212
|
+
const result = McpServerStdioSchema.safeParse({
|
|
213
|
+
name: 'test-server',
|
|
214
|
+
command: 'node',
|
|
215
|
+
args: ['server.js'],
|
|
216
|
+
env: [],
|
|
217
|
+
})
|
|
218
|
+
expect(result.success).toBe(true)
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
test('parses stdio config with explicit type', () => {
|
|
222
|
+
const result = McpServerStdioSchema.safeParse({
|
|
223
|
+
type: 'stdio',
|
|
224
|
+
name: 'test-server',
|
|
225
|
+
command: 'bun',
|
|
226
|
+
args: ['run', 'server.ts'],
|
|
227
|
+
env: [{ name: 'DEBUG', value: 'true' }],
|
|
228
|
+
})
|
|
229
|
+
expect(result.success).toBe(true)
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
describe('McpServerHttpSchema', () => {
|
|
234
|
+
test('parses http config', () => {
|
|
235
|
+
const result = McpServerHttpSchema.safeParse({
|
|
236
|
+
type: 'http',
|
|
237
|
+
name: 'api-server',
|
|
238
|
+
url: 'https://api.example.com',
|
|
239
|
+
headers: [{ name: 'Authorization', value: 'Bearer token' }],
|
|
240
|
+
})
|
|
241
|
+
expect(result.success).toBe(true)
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
describe('McpServerSchema', () => {
|
|
246
|
+
test('parses stdio server', () => {
|
|
247
|
+
const result = McpServerSchema.safeParse({
|
|
248
|
+
name: 'test',
|
|
249
|
+
command: 'node',
|
|
250
|
+
args: [],
|
|
251
|
+
env: [],
|
|
252
|
+
})
|
|
253
|
+
expect(result.success).toBe(true)
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
test('parses http server', () => {
|
|
257
|
+
const result = McpServerSchema.safeParse({
|
|
258
|
+
type: 'http',
|
|
259
|
+
name: 'test',
|
|
260
|
+
url: 'https://example.com',
|
|
261
|
+
headers: [],
|
|
262
|
+
})
|
|
263
|
+
expect(result.success).toBe(true)
|
|
264
|
+
})
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
// ============================================================================
|
|
268
|
+
// Prompt Case Schema
|
|
269
|
+
// ============================================================================
|
|
270
|
+
|
|
271
|
+
describe('PromptCaseSchema', () => {
|
|
272
|
+
test('parses minimal prompt case', () => {
|
|
273
|
+
const result = PromptCaseSchema.safeParse({
|
|
274
|
+
id: 'test-1',
|
|
275
|
+
input: 'Hello',
|
|
276
|
+
})
|
|
277
|
+
expect(result.success).toBe(true)
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
test('parses single-turn with hint', () => {
|
|
281
|
+
const result = PromptCaseSchema.safeParse({
|
|
282
|
+
id: 'test-1',
|
|
283
|
+
input: 'What is 2+2?',
|
|
284
|
+
hint: '4',
|
|
285
|
+
})
|
|
286
|
+
expect(result.success).toBe(true)
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
test('parses multi-turn input array', () => {
|
|
290
|
+
const result = PromptCaseSchema.safeParse({
|
|
291
|
+
id: 'test-1',
|
|
292
|
+
input: ['Hello', 'How are you?', 'Goodbye'],
|
|
293
|
+
})
|
|
294
|
+
expect(result.success).toBe(true)
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
test('parses full prompt case with all fields', () => {
|
|
298
|
+
const result = PromptCaseSchema.safeParse({
|
|
299
|
+
id: 'test-1',
|
|
300
|
+
input: ['Hello'],
|
|
301
|
+
hint: 'greeting',
|
|
302
|
+
reference: 'Hi there!',
|
|
303
|
+
metadata: { category: 'test', difficulty: 'easy' },
|
|
304
|
+
timeout: 30000,
|
|
305
|
+
})
|
|
306
|
+
expect(result.success).toBe(true)
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
test('rejects missing id', () => {
|
|
310
|
+
const result = PromptCaseSchema.safeParse({ input: 'Hello' })
|
|
311
|
+
expect(result.success).toBe(false)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
test('rejects missing input', () => {
|
|
315
|
+
const result = PromptCaseSchema.safeParse({ id: 'test-1' })
|
|
316
|
+
expect(result.success).toBe(false)
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
// ============================================================================
|
|
321
|
+
// Grader Result Schema
|
|
322
|
+
// ============================================================================
|
|
323
|
+
|
|
324
|
+
describe('GraderResultSchema', () => {
|
|
325
|
+
test('parses valid grader result', () => {
|
|
326
|
+
const result = GraderResultSchema.safeParse({
|
|
327
|
+
pass: true,
|
|
328
|
+
score: 1.0,
|
|
329
|
+
})
|
|
330
|
+
expect(result.success).toBe(true)
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
test('parses result with reasoning', () => {
|
|
334
|
+
const result = GraderResultSchema.safeParse({
|
|
335
|
+
pass: false,
|
|
336
|
+
score: 0.5,
|
|
337
|
+
reasoning: 'Partial match',
|
|
338
|
+
})
|
|
339
|
+
expect(result.success).toBe(true)
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
test('rejects score below 0', () => {
|
|
343
|
+
const result = GraderResultSchema.safeParse({
|
|
344
|
+
pass: false,
|
|
345
|
+
score: -0.1,
|
|
346
|
+
})
|
|
347
|
+
expect(result.success).toBe(false)
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
test('rejects score above 1', () => {
|
|
351
|
+
const result = GraderResultSchema.safeParse({
|
|
352
|
+
pass: true,
|
|
353
|
+
score: 1.5,
|
|
354
|
+
})
|
|
355
|
+
expect(result.success).toBe(false)
|
|
356
|
+
})
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
// ============================================================================
|
|
360
|
+
// Trajectory Step Schemas
|
|
361
|
+
// ============================================================================
|
|
362
|
+
|
|
363
|
+
describe('ToolInputSchema', () => {
|
|
364
|
+
test('parses file path input', () => {
|
|
365
|
+
const result = ToolInputSchema.safeParse({ file_path: '/src/index.ts' })
|
|
366
|
+
expect(result.success).toBe(true)
|
|
367
|
+
if (result.success) {
|
|
368
|
+
expect(result.data.file_path).toBe('/src/index.ts')
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
test('allows additional properties via passthrough', () => {
|
|
373
|
+
const result = ToolInputSchema.safeParse({
|
|
374
|
+
file_path: '/test.ts',
|
|
375
|
+
custom_field: 'value',
|
|
376
|
+
})
|
|
377
|
+
expect(result.success).toBe(true)
|
|
378
|
+
if (result.success) {
|
|
379
|
+
expect(result.data.custom_field).toBe('value')
|
|
380
|
+
}
|
|
381
|
+
})
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
describe('ThoughtStepSchema', () => {
|
|
385
|
+
test('parses thought step', () => {
|
|
386
|
+
const result = ThoughtStepSchema.safeParse({
|
|
387
|
+
type: 'thought',
|
|
388
|
+
content: 'Thinking about the problem...',
|
|
389
|
+
timestamp: 1234567890,
|
|
390
|
+
})
|
|
391
|
+
expect(result.success).toBe(true)
|
|
392
|
+
})
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
describe('MessageStepSchema', () => {
|
|
396
|
+
test('parses message step', () => {
|
|
397
|
+
const result = MessageStepSchema.safeParse({
|
|
398
|
+
type: 'message',
|
|
399
|
+
content: 'Hello, world!',
|
|
400
|
+
timestamp: 1234567890,
|
|
401
|
+
})
|
|
402
|
+
expect(result.success).toBe(true)
|
|
403
|
+
})
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
describe('ToolCallStepSchema', () => {
|
|
407
|
+
test('parses tool call step', () => {
|
|
408
|
+
const result = ToolCallStepSchema.safeParse({
|
|
409
|
+
type: 'tool_call',
|
|
410
|
+
name: 'Read',
|
|
411
|
+
status: 'completed',
|
|
412
|
+
timestamp: 1234567890,
|
|
413
|
+
})
|
|
414
|
+
expect(result.success).toBe(true)
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
test('parses tool call with input/output', () => {
|
|
418
|
+
const result = ToolCallStepSchema.safeParse({
|
|
419
|
+
type: 'tool_call',
|
|
420
|
+
name: 'Write',
|
|
421
|
+
status: 'completed',
|
|
422
|
+
input: { file_path: '/test.ts', content: 'code' },
|
|
423
|
+
output: 'File written',
|
|
424
|
+
duration: 150,
|
|
425
|
+
timestamp: 1234567890,
|
|
426
|
+
})
|
|
427
|
+
expect(result.success).toBe(true)
|
|
428
|
+
})
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
describe('PlanStepSchema', () => {
|
|
432
|
+
test('parses plan step', () => {
|
|
433
|
+
const result = PlanStepSchema.safeParse({
|
|
434
|
+
type: 'plan',
|
|
435
|
+
entries: [{ task: 'Step 1' }, { task: 'Step 2' }],
|
|
436
|
+
timestamp: 1234567890,
|
|
437
|
+
})
|
|
438
|
+
expect(result.success).toBe(true)
|
|
439
|
+
})
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
describe('TrajectoryStepSchema', () => {
|
|
443
|
+
test('discriminates thought type', () => {
|
|
444
|
+
const result = TrajectoryStepSchema.safeParse({
|
|
445
|
+
type: 'thought',
|
|
446
|
+
content: 'test',
|
|
447
|
+
timestamp: 123,
|
|
448
|
+
})
|
|
449
|
+
expect(result.success).toBe(true)
|
|
450
|
+
if (result.success) {
|
|
451
|
+
expect(result.data.type).toBe('thought')
|
|
452
|
+
}
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
test('discriminates message type', () => {
|
|
456
|
+
const result = TrajectoryStepSchema.safeParse({
|
|
457
|
+
type: 'message',
|
|
458
|
+
content: 'test',
|
|
459
|
+
timestamp: 123,
|
|
460
|
+
})
|
|
461
|
+
expect(result.success).toBe(true)
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
test('discriminates tool_call type', () => {
|
|
465
|
+
const result = TrajectoryStepSchema.safeParse({
|
|
466
|
+
type: 'tool_call',
|
|
467
|
+
name: 'Test',
|
|
468
|
+
status: 'completed',
|
|
469
|
+
timestamp: 123,
|
|
470
|
+
})
|
|
471
|
+
expect(result.success).toBe(true)
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
test('discriminates plan type', () => {
|
|
475
|
+
const result = TrajectoryStepSchema.safeParse({
|
|
476
|
+
type: 'plan',
|
|
477
|
+
entries: [],
|
|
478
|
+
timestamp: 123,
|
|
479
|
+
})
|
|
480
|
+
expect(result.success).toBe(true)
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
test('rejects unknown type', () => {
|
|
484
|
+
const result = TrajectoryStepSchema.safeParse({
|
|
485
|
+
type: 'unknown',
|
|
486
|
+
timestamp: 123,
|
|
487
|
+
})
|
|
488
|
+
expect(result.success).toBe(false)
|
|
489
|
+
})
|
|
490
|
+
})
|
|
491
|
+
|
|
492
|
+
// ============================================================================
|
|
493
|
+
// Trajectory Richness Schema
|
|
494
|
+
// ============================================================================
|
|
495
|
+
|
|
496
|
+
describe('TrajectoryRichnessSchema', () => {
|
|
497
|
+
test('parses full', () => {
|
|
498
|
+
expect(TrajectoryRichnessSchema.safeParse('full').success).toBe(true)
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
test('parses minimal', () => {
|
|
502
|
+
expect(TrajectoryRichnessSchema.safeParse('minimal').success).toBe(true)
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
test('parses messages-only', () => {
|
|
506
|
+
expect(TrajectoryRichnessSchema.safeParse('messages-only').success).toBe(true)
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
test('rejects invalid value', () => {
|
|
510
|
+
expect(TrajectoryRichnessSchema.safeParse('invalid').success).toBe(false)
|
|
511
|
+
})
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
// ============================================================================
|
|
515
|
+
// Timing Schema
|
|
516
|
+
// ============================================================================
|
|
517
|
+
|
|
518
|
+
describe('TimingSchema', () => {
|
|
519
|
+
test('parses timing with required fields', () => {
|
|
520
|
+
const result = TimingSchema.safeParse({
|
|
521
|
+
start: 1000,
|
|
522
|
+
end: 2000,
|
|
523
|
+
sessionCreation: 100,
|
|
524
|
+
total: 1000,
|
|
525
|
+
})
|
|
526
|
+
expect(result.success).toBe(true)
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
test('parses timing with optional fields', () => {
|
|
530
|
+
const result = TimingSchema.safeParse({
|
|
531
|
+
start: 1000,
|
|
532
|
+
end: 2000,
|
|
533
|
+
firstResponse: 500,
|
|
534
|
+
sessionCreation: 100,
|
|
535
|
+
total: 1000,
|
|
536
|
+
inputTokens: 50,
|
|
537
|
+
outputTokens: 100,
|
|
538
|
+
})
|
|
539
|
+
expect(result.success).toBe(true)
|
|
540
|
+
})
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
// ============================================================================
|
|
544
|
+
// Capture Result Schema
|
|
545
|
+
// ============================================================================
|
|
546
|
+
|
|
547
|
+
describe('CaptureResultSchema', () => {
|
|
548
|
+
test('parses minimal capture result', () => {
|
|
549
|
+
const result = CaptureResultSchema.safeParse({
|
|
550
|
+
id: 'test-1',
|
|
551
|
+
input: 'Hello',
|
|
552
|
+
output: 'Hi there!',
|
|
553
|
+
trajectory: [],
|
|
554
|
+
metadata: {},
|
|
555
|
+
timing: {
|
|
556
|
+
start: 1000,
|
|
557
|
+
end: 2000,
|
|
558
|
+
sessionCreation: 100,
|
|
559
|
+
total: 1000,
|
|
560
|
+
},
|
|
561
|
+
toolErrors: false,
|
|
562
|
+
})
|
|
563
|
+
expect(result.success).toBe(true)
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
test('parses capture result with multi-turn input', () => {
|
|
567
|
+
const result = CaptureResultSchema.safeParse({
|
|
568
|
+
id: 'test-1',
|
|
569
|
+
input: ['Hello', 'Goodbye'],
|
|
570
|
+
output: 'Bye!',
|
|
571
|
+
trajectory: [
|
|
572
|
+
{ type: 'message', content: 'Hi', timestamp: 100 },
|
|
573
|
+
{ type: 'message', content: 'Bye!', timestamp: 200 },
|
|
574
|
+
],
|
|
575
|
+
metadata: { agent: 'test-agent', turnCount: 2 },
|
|
576
|
+
timing: {
|
|
577
|
+
start: 1000,
|
|
578
|
+
end: 2000,
|
|
579
|
+
sessionCreation: 100,
|
|
580
|
+
total: 1000,
|
|
581
|
+
},
|
|
582
|
+
toolErrors: false,
|
|
583
|
+
})
|
|
584
|
+
expect(result.success).toBe(true)
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
test('parses capture result with hint and score', () => {
|
|
588
|
+
const result = CaptureResultSchema.safeParse({
|
|
589
|
+
id: 'test-1',
|
|
590
|
+
input: 'What is 2+2?',
|
|
591
|
+
output: '4',
|
|
592
|
+
hint: '4',
|
|
593
|
+
trajectory: [],
|
|
594
|
+
metadata: {},
|
|
595
|
+
timing: {
|
|
596
|
+
start: 1000,
|
|
597
|
+
end: 2000,
|
|
598
|
+
sessionCreation: 100,
|
|
599
|
+
total: 1000,
|
|
600
|
+
},
|
|
601
|
+
toolErrors: false,
|
|
602
|
+
score: { pass: true, score: 1.0 },
|
|
603
|
+
})
|
|
604
|
+
expect(result.success).toBe(true)
|
|
605
|
+
})
|
|
606
|
+
})
|
package/src/schemas.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schemas and types for agent evaluation harness.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Re-exports all Zod schemas and inferred types for capture results,
|
|
6
|
+
* trajectories, grader results, and CLI data structures.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Constants
|
|
12
|
+
export {
|
|
13
|
+
DEFAULT_CALIBRATION_SAMPLE_SIZE,
|
|
14
|
+
DEFAULT_HARNESS_TIMEOUT,
|
|
15
|
+
DEFAULT_TRIAL_COUNT,
|
|
16
|
+
HEAD_LINES,
|
|
17
|
+
MAX_CONTENT_LENGTH,
|
|
18
|
+
TAIL_LINES,
|
|
19
|
+
} from './schemas/constants.ts'
|
|
20
|
+
// Grader loader
|
|
21
|
+
export { loadGrader } from './schemas/grader-loader.ts'
|
|
22
|
+
// Core session types
|
|
23
|
+
// JSON-RPC types (MCP compatibility)
|
|
24
|
+
// MCP server configuration
|
|
25
|
+
// Prompt and grading
|
|
26
|
+
// Trajectory types
|
|
27
|
+
// Timing and richness
|
|
28
|
+
// Result types
|
|
29
|
+
export {
|
|
30
|
+
type BalanceAnalysis,
|
|
31
|
+
BalanceAnalysisSchema,
|
|
32
|
+
type CalibrationSample,
|
|
33
|
+
CalibrationSampleSchema,
|
|
34
|
+
type CaptureResult,
|
|
35
|
+
CaptureResultSchema,
|
|
36
|
+
type CategoryDistribution,
|
|
37
|
+
CategoryDistributionSchema,
|
|
38
|
+
EnvVariableSchema,
|
|
39
|
+
type Grader,
|
|
40
|
+
type GraderResult,
|
|
41
|
+
GraderResultSchema,
|
|
42
|
+
HttpHeaderSchema,
|
|
43
|
+
type IndexedStep,
|
|
44
|
+
type JsonRpcError,
|
|
45
|
+
type JsonRpcErrorResponse,
|
|
46
|
+
JsonRpcErrorResponseSchema,
|
|
47
|
+
JsonRpcErrorSchema,
|
|
48
|
+
type JsonRpcMessage,
|
|
49
|
+
JsonRpcMessageSchema,
|
|
50
|
+
type JsonRpcNotification,
|
|
51
|
+
JsonRpcNotificationSchema,
|
|
52
|
+
type JsonRpcRequest,
|
|
53
|
+
JsonRpcRequestSchema,
|
|
54
|
+
type JsonRpcResponse,
|
|
55
|
+
JsonRpcResponseSchema,
|
|
56
|
+
type JsonRpcSuccessResponse,
|
|
57
|
+
JsonRpcSuccessResponseSchema,
|
|
58
|
+
type McpServerConfig,
|
|
59
|
+
McpServerHttpSchema,
|
|
60
|
+
McpServerSchema,
|
|
61
|
+
McpServerStdioSchema,
|
|
62
|
+
MessageStepSchema,
|
|
63
|
+
PlanStepSchema,
|
|
64
|
+
type PromptCase,
|
|
65
|
+
PromptCaseSchema,
|
|
66
|
+
type Session,
|
|
67
|
+
SessionSchema,
|
|
68
|
+
type SummaryResult,
|
|
69
|
+
SummaryResultSchema,
|
|
70
|
+
ThoughtStepSchema,
|
|
71
|
+
type Timing,
|
|
72
|
+
TimingSchema,
|
|
73
|
+
ToolCallStepSchema,
|
|
74
|
+
type ToolInput,
|
|
75
|
+
ToolInputSchema,
|
|
76
|
+
type TrajectoryRichness,
|
|
77
|
+
TrajectoryRichnessSchema,
|
|
78
|
+
type TrajectoryStep,
|
|
79
|
+
TrajectoryStepSchema,
|
|
80
|
+
type TrialEntry,
|
|
81
|
+
TrialEntrySchema,
|
|
82
|
+
type TrialResult,
|
|
83
|
+
TrialResultSchema,
|
|
84
|
+
type ValidationResult,
|
|
85
|
+
ValidationResultSchema,
|
|
86
|
+
} from './schemas/schemas.ts'
|
|
87
|
+
|
|
88
|
+
// Schemas CLI
|
|
89
|
+
export type { SchemasConfig } from './schemas/schemas-cli.ts'
|
|
90
|
+
export { runSchemas, schemasCli } from './schemas/schemas-cli.ts'
|