ai.matey.testing 0.2.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 +21 -0
- package/dist/cjs/fixture-capture.js +169 -0
- package/dist/cjs/fixture-capture.js.map +1 -0
- package/dist/cjs/fixture-helpers.js +240 -0
- package/dist/cjs/fixture-helpers.js.map +1 -0
- package/dist/cjs/fixture-loader.js +196 -0
- package/dist/cjs/fixture-loader.js.map +1 -0
- package/dist/cjs/fixture-types.js +20 -0
- package/dist/cjs/fixture-types.js.map +1 -0
- package/dist/cjs/index.js +66 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/property-testing.js +288 -0
- package/dist/cjs/property-testing.js.map +1 -0
- package/dist/cjs/test-helpers.js +289 -0
- package/dist/cjs/test-helpers.js.map +1 -0
- package/dist/esm/fixture-capture.js +163 -0
- package/dist/esm/fixture-capture.js.map +1 -0
- package/dist/esm/fixture-helpers.js +228 -0
- package/dist/esm/fixture-helpers.js.map +1 -0
- package/dist/esm/fixture-loader.js +154 -0
- package/dist/esm/fixture-loader.js.map +1 -0
- package/dist/esm/fixture-types.js +16 -0
- package/dist/esm/fixture-types.js.map +1 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/property-testing.js +274 -0
- package/dist/esm/property-testing.js.map +1 -0
- package/dist/esm/test-helpers.js +272 -0
- package/dist/esm/test-helpers.js.map +1 -0
- package/dist/types/fixture-capture.d.ts +55 -0
- package/dist/types/fixture-capture.d.ts.map +1 -0
- package/dist/types/fixture-helpers.d.ts +69 -0
- package/dist/types/fixture-helpers.d.ts.map +1 -0
- package/dist/types/fixture-loader.d.ts +40 -0
- package/dist/types/fixture-loader.d.ts.map +1 -0
- package/dist/types/fixture-types.d.ts +76 -0
- package/dist/types/fixture-types.d.ts.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/property-testing.d.ts +79 -0
- package/dist/types/property-testing.d.ts.map +1 -0
- package/dist/types/test-helpers.d.ts +81 -0
- package/dist/types/test-helpers.d.ts.map +1 -0
- package/package.json +68 -0
- package/readme.md +31 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property-based testing utilities - generate random valid inputs
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Random seed generator for deterministic randomness
|
|
6
|
+
*/
|
|
7
|
+
export class SeededRandom {
|
|
8
|
+
seed;
|
|
9
|
+
constructor(seed = Date.now()) {
|
|
10
|
+
this.seed = seed;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generate next random number between 0 and 1
|
|
14
|
+
*/
|
|
15
|
+
next() {
|
|
16
|
+
this.seed = (this.seed * 9301 + 49297) % 233280;
|
|
17
|
+
return this.seed / 233280;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate random integer between min and max (inclusive)
|
|
21
|
+
*/
|
|
22
|
+
nextInt(min, max) {
|
|
23
|
+
return Math.floor(this.next() * (max - min + 1)) + min;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Pick random element from array
|
|
27
|
+
*/
|
|
28
|
+
pick(array) {
|
|
29
|
+
if (array.length === 0) {
|
|
30
|
+
throw new Error('Cannot pick from empty array');
|
|
31
|
+
}
|
|
32
|
+
return array[this.nextInt(0, array.length - 1)];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generate random boolean
|
|
36
|
+
*/
|
|
37
|
+
nextBool(probability = 0.5) {
|
|
38
|
+
return this.next() < probability;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generate random text content
|
|
43
|
+
*/
|
|
44
|
+
export function generateTextContent(random) {
|
|
45
|
+
const texts = [
|
|
46
|
+
'Hello, how are you?',
|
|
47
|
+
'What is the weather today?',
|
|
48
|
+
'Explain quantum computing',
|
|
49
|
+
'Write a haiku about programming',
|
|
50
|
+
'What is 2 + 2?',
|
|
51
|
+
'Tell me a joke',
|
|
52
|
+
'Summarize the main points',
|
|
53
|
+
'Translate this to French',
|
|
54
|
+
'Help me debug this code',
|
|
55
|
+
'What are the benefits?',
|
|
56
|
+
];
|
|
57
|
+
return {
|
|
58
|
+
type: 'text',
|
|
59
|
+
text: random.pick(texts),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generate random user message
|
|
64
|
+
*/
|
|
65
|
+
export function generateUserMessage(random) {
|
|
66
|
+
const contentCount = random.nextInt(1, 3);
|
|
67
|
+
const content = [];
|
|
68
|
+
for (let i = 0; i < contentCount; i++) {
|
|
69
|
+
content.push(generateTextContent(random));
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
role: 'user',
|
|
73
|
+
content,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Generate random assistant message
|
|
78
|
+
*/
|
|
79
|
+
export function generateAssistantMessage(random) {
|
|
80
|
+
return {
|
|
81
|
+
role: 'assistant',
|
|
82
|
+
content: [generateTextContent(random)],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generate random system message
|
|
87
|
+
*/
|
|
88
|
+
export function generateSystemMessage(random) {
|
|
89
|
+
const systemPrompts = [
|
|
90
|
+
'You are a helpful assistant',
|
|
91
|
+
'You are an expert programmer',
|
|
92
|
+
'You speak like a pirate',
|
|
93
|
+
'You are a teacher',
|
|
94
|
+
'You provide concise answers',
|
|
95
|
+
];
|
|
96
|
+
return {
|
|
97
|
+
role: 'system',
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: random.pick(systemPrompts),
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Generate random parameters
|
|
108
|
+
*/
|
|
109
|
+
export function generateParameters(random) {
|
|
110
|
+
const models = [
|
|
111
|
+
'gpt-4',
|
|
112
|
+
'gpt-3.5-turbo',
|
|
113
|
+
'claude-3-5-sonnet-20241022',
|
|
114
|
+
'claude-3-haiku-20240307',
|
|
115
|
+
'gemini-1.5-pro',
|
|
116
|
+
'llama3.2:1b',
|
|
117
|
+
];
|
|
118
|
+
return {
|
|
119
|
+
model: random.pick(models),
|
|
120
|
+
temperature: Math.round(random.next() * 20) / 20, // 0.0 to 1.0 in 0.05 increments
|
|
121
|
+
maxTokens: random.nextInt(50, 500),
|
|
122
|
+
topP: random.nextBool() ? Math.round(random.next() * 20) / 20 : undefined,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Generate random chat request
|
|
127
|
+
*/
|
|
128
|
+
export function generateChatRequest(random, options) {
|
|
129
|
+
const messages = [];
|
|
130
|
+
// Add system message if requested
|
|
131
|
+
if (options?.includeSystem && random.nextBool(0.5)) {
|
|
132
|
+
messages.push(generateSystemMessage(random));
|
|
133
|
+
}
|
|
134
|
+
// Add conversation turns
|
|
135
|
+
const minMessages = options?.minMessages ?? 1;
|
|
136
|
+
const maxMessages = options?.maxMessages ?? 5;
|
|
137
|
+
const messageCount = random.nextInt(minMessages, maxMessages);
|
|
138
|
+
if (options?.multiTurn) {
|
|
139
|
+
// Multi-turn conversation
|
|
140
|
+
const turns = Math.floor(messageCount / 2);
|
|
141
|
+
for (let i = 0; i < turns; i++) {
|
|
142
|
+
messages.push(generateUserMessage(random));
|
|
143
|
+
messages.push(generateAssistantMessage(random));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Always end with user message
|
|
147
|
+
messages.push(generateUserMessage(random));
|
|
148
|
+
return {
|
|
149
|
+
messages,
|
|
150
|
+
parameters: generateParameters(random),
|
|
151
|
+
metadata: {
|
|
152
|
+
requestId: `gen-${random.nextInt(1000, 9999)}`,
|
|
153
|
+
timestamp: Date.now(),
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Property test: run test with multiple generated inputs
|
|
159
|
+
*/
|
|
160
|
+
export async function forAll(generator, test, options) {
|
|
161
|
+
const runs = options?.runs ?? 100;
|
|
162
|
+
const seed = options?.seed ?? Date.now();
|
|
163
|
+
const random = new SeededRandom(seed);
|
|
164
|
+
const failures = [];
|
|
165
|
+
for (let i = 0; i < runs; i++) {
|
|
166
|
+
const value = generator(random);
|
|
167
|
+
try {
|
|
168
|
+
await test(value);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
failures.push({
|
|
172
|
+
run: i,
|
|
173
|
+
value,
|
|
174
|
+
error: error,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (failures.length > 0) {
|
|
179
|
+
const firstFailure = failures[0];
|
|
180
|
+
throw new Error(`Property test failed on run ${firstFailure.run + 1}/${runs}\n` +
|
|
181
|
+
`Seed: ${seed}\n` +
|
|
182
|
+
`Value: ${JSON.stringify(firstFailure.value, null, 2)}\n` +
|
|
183
|
+
`Error: ${firstFailure.error.message}\n` +
|
|
184
|
+
`Total failures: ${failures.length}/${runs}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Shrink a failing value to find minimal failing case
|
|
189
|
+
*/
|
|
190
|
+
export function shrinkChatRequest(request) {
|
|
191
|
+
const shrunk = [];
|
|
192
|
+
// Try removing messages
|
|
193
|
+
if (request.messages.length > 1) {
|
|
194
|
+
shrunk.push({
|
|
195
|
+
...request,
|
|
196
|
+
messages: request.messages.slice(0, -1),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// Try simplifying parameters
|
|
200
|
+
shrunk.push({
|
|
201
|
+
...request,
|
|
202
|
+
parameters: {
|
|
203
|
+
...request.parameters,
|
|
204
|
+
temperature: 0.7,
|
|
205
|
+
maxTokens: 100,
|
|
206
|
+
topP: undefined,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
// Try removing content from messages
|
|
210
|
+
for (let i = 0; i < request.messages.length; i++) {
|
|
211
|
+
const message = request.messages[i];
|
|
212
|
+
if (Array.isArray(message.content) && message.content.length > 1) {
|
|
213
|
+
const newMessages = [...request.messages];
|
|
214
|
+
newMessages[i] = {
|
|
215
|
+
...message,
|
|
216
|
+
content: [message.content[0]],
|
|
217
|
+
};
|
|
218
|
+
shrunk.push({
|
|
219
|
+
...request,
|
|
220
|
+
messages: newMessages,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return shrunk;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Example property tests
|
|
228
|
+
*/
|
|
229
|
+
/**
|
|
230
|
+
* Property: All generated requests should be valid
|
|
231
|
+
*/
|
|
232
|
+
export async function propertyValidRequest() {
|
|
233
|
+
await forAll((random) => generateChatRequest(random), (request) => {
|
|
234
|
+
// Request should have messages
|
|
235
|
+
if (request.messages.length === 0) {
|
|
236
|
+
throw new Error('Request must have at least one message');
|
|
237
|
+
}
|
|
238
|
+
// Last message should be from user
|
|
239
|
+
const lastMessage = request.messages[request.messages.length - 1];
|
|
240
|
+
if (lastMessage?.role !== 'user') {
|
|
241
|
+
throw new Error('Last message must be from user');
|
|
242
|
+
}
|
|
243
|
+
// Parameters should be in valid ranges
|
|
244
|
+
if (request.parameters?.temperature !== undefined) {
|
|
245
|
+
if (request.parameters.temperature < 0 || request.parameters.temperature > 2) {
|
|
246
|
+
throw new Error('Temperature must be between 0 and 2');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (request.parameters?.maxTokens !== undefined) {
|
|
250
|
+
if (request.parameters.maxTokens < 1) {
|
|
251
|
+
throw new Error('maxTokens must be positive');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}, { runs: 100 });
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Property: Multi-turn conversations should alternate user/assistant
|
|
258
|
+
*/
|
|
259
|
+
export async function propertyMultiTurnAlternates() {
|
|
260
|
+
await forAll((random) => generateChatRequest(random, { multiTurn: true }), (request) => {
|
|
261
|
+
const nonSystemMessages = request.messages.filter((m) => m.role !== 'system');
|
|
262
|
+
for (let i = 0; i < nonSystemMessages.length - 1; i++) {
|
|
263
|
+
const current = nonSystemMessages[i];
|
|
264
|
+
const next = nonSystemMessages[i + 1];
|
|
265
|
+
if (current.role === 'user' && next.role !== 'assistant') {
|
|
266
|
+
throw new Error('User message must be followed by assistant message');
|
|
267
|
+
}
|
|
268
|
+
if (current.role === 'assistant' && next.role !== 'user') {
|
|
269
|
+
throw new Error('Assistant message must be followed by user message');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}, { runs: 100 });
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=property-testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-testing.js","sourceRoot":"","sources":["../../src/property-testing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helper utilities - assertions and test builders
|
|
3
|
+
*/
|
|
4
|
+
import { expect } from 'vitest';
|
|
5
|
+
/**
|
|
6
|
+
* Assert that a response has the correct structure
|
|
7
|
+
*/
|
|
8
|
+
export function assertValidChatResponse(response) {
|
|
9
|
+
expect(response).toBeDefined();
|
|
10
|
+
expect(response.message).toBeDefined();
|
|
11
|
+
expect(response.message.role).toBe('assistant');
|
|
12
|
+
expect(response.message.content).toBeDefined();
|
|
13
|
+
expect(Array.isArray(response.message.content)).toBe(true);
|
|
14
|
+
expect(response.message.content.length).toBeGreaterThan(0);
|
|
15
|
+
expect(response.usage).toBeDefined();
|
|
16
|
+
if (response.usage) {
|
|
17
|
+
expect(response.usage.promptTokens).toBeGreaterThanOrEqual(0);
|
|
18
|
+
expect(response.usage.completionTokens).toBeGreaterThanOrEqual(0);
|
|
19
|
+
expect(response.usage.totalTokens).toBeGreaterThanOrEqual(0);
|
|
20
|
+
}
|
|
21
|
+
expect(response.finishReason).toBeDefined();
|
|
22
|
+
expect(['stop', 'length', 'tool_use', 'content_filter']).toContain(response.finishReason);
|
|
23
|
+
expect(response.metadata).toBeDefined();
|
|
24
|
+
expect(response.metadata.requestId).toBeDefined();
|
|
25
|
+
expect(response.metadata.timestamp).toBeDefined();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Assert that a stream chunk has the correct structure
|
|
29
|
+
*/
|
|
30
|
+
export function assertValidStreamChunk(chunk) {
|
|
31
|
+
expect(chunk).toBeDefined();
|
|
32
|
+
expect(chunk.type).toBeDefined();
|
|
33
|
+
expect(['start', 'content', 'tool_use', 'error', 'metadata', 'done']).toContain(chunk.type);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Assert that a request has the correct structure
|
|
37
|
+
*/
|
|
38
|
+
export function assertValidChatRequest(request) {
|
|
39
|
+
expect(request).toBeDefined();
|
|
40
|
+
expect(request.messages).toBeDefined();
|
|
41
|
+
expect(Array.isArray(request.messages)).toBe(true);
|
|
42
|
+
expect(request.messages.length).toBeGreaterThan(0);
|
|
43
|
+
// Validate each message
|
|
44
|
+
for (const message of request.messages) {
|
|
45
|
+
assertValidMessage(message);
|
|
46
|
+
}
|
|
47
|
+
expect(request.parameters).toBeDefined();
|
|
48
|
+
expect(request.metadata).toBeDefined();
|
|
49
|
+
expect(request.metadata.requestId).toBeDefined();
|
|
50
|
+
expect(request.metadata.timestamp).toBeDefined();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Assert that a message has the correct structure
|
|
54
|
+
*/
|
|
55
|
+
export function assertValidMessage(message) {
|
|
56
|
+
expect(message).toBeDefined();
|
|
57
|
+
expect(message.role).toBeDefined();
|
|
58
|
+
expect(['user', 'assistant', 'system', 'tool']).toContain(message.role);
|
|
59
|
+
expect(message.content).toBeDefined();
|
|
60
|
+
if (Array.isArray(message.content)) {
|
|
61
|
+
expect(message.content.length).toBeGreaterThan(0);
|
|
62
|
+
for (const content of message.content) {
|
|
63
|
+
assertValidMessageContent(content);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Assert that message content has the correct structure
|
|
69
|
+
*/
|
|
70
|
+
export function assertValidMessageContent(content) {
|
|
71
|
+
expect(content).toBeDefined();
|
|
72
|
+
expect(content.type).toBeDefined();
|
|
73
|
+
switch (content.type) {
|
|
74
|
+
case 'text':
|
|
75
|
+
expect(content.text).toBeDefined();
|
|
76
|
+
expect(typeof content.text).toBe('string');
|
|
77
|
+
break;
|
|
78
|
+
case 'image':
|
|
79
|
+
expect(content.source).toBeDefined();
|
|
80
|
+
expect(content.source.type).toBeDefined();
|
|
81
|
+
break;
|
|
82
|
+
case 'tool_use':
|
|
83
|
+
expect(content.id).toBeDefined();
|
|
84
|
+
expect(content.name).toBeDefined();
|
|
85
|
+
expect(content.input).toBeDefined();
|
|
86
|
+
break;
|
|
87
|
+
case 'tool_result':
|
|
88
|
+
expect(content.toolUseId).toBeDefined();
|
|
89
|
+
expect(content.content).toBeDefined();
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Assert that response contains text
|
|
95
|
+
*/
|
|
96
|
+
export function assertResponseHasText(response) {
|
|
97
|
+
if (!Array.isArray(response.message.content)) {
|
|
98
|
+
throw new Error('Response content must be an array');
|
|
99
|
+
}
|
|
100
|
+
const textContent = response.message.content.find((c) => c.type === 'text');
|
|
101
|
+
expect(textContent).toBeDefined();
|
|
102
|
+
if (textContent?.type === 'text') {
|
|
103
|
+
expect(textContent.text).toBeDefined();
|
|
104
|
+
expect(textContent.text.length).toBeGreaterThan(0);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Assert that response contains tool use
|
|
109
|
+
*/
|
|
110
|
+
export function assertResponseHasToolUse(response) {
|
|
111
|
+
if (!Array.isArray(response.message.content)) {
|
|
112
|
+
throw new Error('Response content must be an array');
|
|
113
|
+
}
|
|
114
|
+
const toolUse = response.message.content.find((c) => c.type === 'tool_use');
|
|
115
|
+
expect(toolUse).toBeDefined();
|
|
116
|
+
if (toolUse?.type === 'tool_use') {
|
|
117
|
+
expect(toolUse.id).toBeDefined();
|
|
118
|
+
expect(toolUse.name).toBeDefined();
|
|
119
|
+
expect(toolUse.input).toBeDefined();
|
|
120
|
+
}
|
|
121
|
+
expect(response.finishReason).toBe('tool_use');
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Assert that streaming produces expected sequence
|
|
125
|
+
*/
|
|
126
|
+
export async function assertValidStreamSequence(stream) {
|
|
127
|
+
const chunks = [];
|
|
128
|
+
for await (const chunk of stream) {
|
|
129
|
+
assertValidStreamChunk(chunk);
|
|
130
|
+
chunks.push(chunk);
|
|
131
|
+
}
|
|
132
|
+
expect(chunks.length).toBeGreaterThan(0);
|
|
133
|
+
// First chunk should be 'start'
|
|
134
|
+
const firstChunk = chunks[0];
|
|
135
|
+
if (firstChunk) {
|
|
136
|
+
expect(firstChunk.type).toBe('start');
|
|
137
|
+
}
|
|
138
|
+
// Last chunk should be 'done'
|
|
139
|
+
const lastChunk = chunks[chunks.length - 1];
|
|
140
|
+
if (lastChunk) {
|
|
141
|
+
expect(lastChunk.type).toBe('done');
|
|
142
|
+
}
|
|
143
|
+
return chunks;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Build a simple chat request for testing
|
|
147
|
+
*/
|
|
148
|
+
export function buildChatRequest(userMessage, options) {
|
|
149
|
+
const messages = [];
|
|
150
|
+
if (options?.systemMessage) {
|
|
151
|
+
messages.push({
|
|
152
|
+
role: 'system',
|
|
153
|
+
content: [{ type: 'text', text: options.systemMessage }],
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
messages.push({
|
|
157
|
+
role: 'user',
|
|
158
|
+
content: [{ type: 'text', text: userMessage }],
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
messages,
|
|
162
|
+
parameters: {
|
|
163
|
+
model: options?.model || 'test-model',
|
|
164
|
+
temperature: options?.temperature ?? 0.7,
|
|
165
|
+
maxTokens: options?.maxTokens ?? 100,
|
|
166
|
+
},
|
|
167
|
+
metadata: {
|
|
168
|
+
requestId: `test-${Date.now()}`,
|
|
169
|
+
timestamp: Date.now(),
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Build a multi-turn chat request for testing
|
|
175
|
+
*/
|
|
176
|
+
export function buildMultiTurnRequest(exchanges, finalUserMessage, options) {
|
|
177
|
+
const messages = [];
|
|
178
|
+
for (const exchange of exchanges) {
|
|
179
|
+
messages.push({
|
|
180
|
+
role: 'user',
|
|
181
|
+
content: [{ type: 'text', text: exchange.user }],
|
|
182
|
+
});
|
|
183
|
+
messages.push({
|
|
184
|
+
role: 'assistant',
|
|
185
|
+
content: [{ type: 'text', text: exchange.assistant }],
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
messages.push({
|
|
189
|
+
role: 'user',
|
|
190
|
+
content: [{ type: 'text', text: finalUserMessage }],
|
|
191
|
+
});
|
|
192
|
+
return {
|
|
193
|
+
messages,
|
|
194
|
+
parameters: {
|
|
195
|
+
model: options?.model || 'test-model',
|
|
196
|
+
temperature: options?.temperature ?? 0.7,
|
|
197
|
+
maxTokens: options?.maxTokens ?? 100,
|
|
198
|
+
},
|
|
199
|
+
metadata: {
|
|
200
|
+
requestId: `test-${Date.now()}`,
|
|
201
|
+
timestamp: Date.now(),
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Extract text from response
|
|
207
|
+
*/
|
|
208
|
+
export function extractTextFromResponse(response) {
|
|
209
|
+
if (!Array.isArray(response.message.content)) {
|
|
210
|
+
return '';
|
|
211
|
+
}
|
|
212
|
+
const textContent = response.message.content.filter((c) => c.type === 'text');
|
|
213
|
+
return textContent.map((c) => (c.type === 'text' ? c.text : '')).join('');
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Extract tool uses from response
|
|
217
|
+
*/
|
|
218
|
+
export function extractToolUsesFromResponse(response) {
|
|
219
|
+
if (!Array.isArray(response.message.content)) {
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
return response.message.content
|
|
223
|
+
.filter((c) => c.type === 'tool_use')
|
|
224
|
+
.map((c) => {
|
|
225
|
+
if (c.type === 'tool_use') {
|
|
226
|
+
return {
|
|
227
|
+
id: c.id,
|
|
228
|
+
name: c.name,
|
|
229
|
+
input: c.input,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
return null;
|
|
233
|
+
})
|
|
234
|
+
.filter(Boolean);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Accumulate text from stream chunks
|
|
238
|
+
*/
|
|
239
|
+
export async function accumulateStreamText(stream) {
|
|
240
|
+
let text = '';
|
|
241
|
+
for await (const chunk of stream) {
|
|
242
|
+
if (chunk.type === 'content' && chunk.delta) {
|
|
243
|
+
text += chunk.delta;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return text;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Count tokens in text (rough estimate)
|
|
250
|
+
*/
|
|
251
|
+
export function estimateTokens(text) {
|
|
252
|
+
// Rough estimate: ~4 characters per token
|
|
253
|
+
return Math.ceil(text.length / 4);
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Assert that usage statistics are reasonable
|
|
257
|
+
*/
|
|
258
|
+
export function assertReasonableUsage(response) {
|
|
259
|
+
const { usage } = response;
|
|
260
|
+
if (!usage) {
|
|
261
|
+
throw new Error('Response must have usage statistics');
|
|
262
|
+
}
|
|
263
|
+
// Tokens should be positive
|
|
264
|
+
expect(usage.promptTokens).toBeGreaterThan(0);
|
|
265
|
+
expect(usage.completionTokens).toBeGreaterThan(0);
|
|
266
|
+
expect(usage.totalTokens).toBeGreaterThan(0);
|
|
267
|
+
// Total should equal sum
|
|
268
|
+
expect(usage.totalTokens).toBe(usage.promptTokens + usage.completionTokens);
|
|
269
|
+
// Token counts should be reasonable (not absurdly high)
|
|
270
|
+
expect(usage.totalTokens).toBeLessThan(1000000);
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=test-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../../src/test-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture capture tool - captures real API calls and saves them as fixtures
|
|
3
|
+
*/
|
|
4
|
+
import type { IRChatRequest, IRChatResponse, IRStreamChunk } from 'ai.matey.types';
|
|
5
|
+
import type { ChatFixture, StreamingFixture } from './fixture-types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Capture configuration
|
|
8
|
+
*/
|
|
9
|
+
export interface CaptureConfig {
|
|
10
|
+
/** Provider name */
|
|
11
|
+
readonly provider: string;
|
|
12
|
+
/** Scenario name */
|
|
13
|
+
readonly scenario: string;
|
|
14
|
+
/** Description of this fixture */
|
|
15
|
+
readonly description?: string;
|
|
16
|
+
/** Tags for categorization */
|
|
17
|
+
readonly tags?: readonly string[];
|
|
18
|
+
/** API version */
|
|
19
|
+
readonly apiVersion?: string;
|
|
20
|
+
/** Whether to sanitize sensitive data */
|
|
21
|
+
readonly sanitize?: boolean;
|
|
22
|
+
/** Custom output directory */
|
|
23
|
+
readonly outputDir?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Capture a non-streaming chat interaction
|
|
27
|
+
*/
|
|
28
|
+
export declare function captureChat(config: CaptureConfig, request: IRChatRequest, response: IRChatResponse, providerData?: {
|
|
29
|
+
providerRequest?: unknown;
|
|
30
|
+
providerResponse?: unknown;
|
|
31
|
+
}): Promise<ChatFixture>;
|
|
32
|
+
/**
|
|
33
|
+
* Capture a streaming chat interaction
|
|
34
|
+
*/
|
|
35
|
+
export declare function captureStream(config: CaptureConfig, request: IRChatRequest, chunks: readonly IRStreamChunk[], finalResponse?: IRChatResponse, providerData?: {
|
|
36
|
+
providerRequest?: unknown;
|
|
37
|
+
providerStreamEvents?: readonly unknown[];
|
|
38
|
+
}): Promise<StreamingFixture>;
|
|
39
|
+
/**
|
|
40
|
+
* Capture middleware - wraps a backend adapter to automatically capture fixtures
|
|
41
|
+
*/
|
|
42
|
+
export declare function createCaptureMiddleware(config: Omit<CaptureConfig, 'scenario'>): {
|
|
43
|
+
name: string;
|
|
44
|
+
processRequest(request: IRChatRequest): IRChatRequest;
|
|
45
|
+
processResponse(response: IRChatResponse, request: IRChatRequest): Promise<IRChatResponse>;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Bulk capture utility - capture multiple fixtures at once
|
|
49
|
+
*/
|
|
50
|
+
export declare function bulkCapture(config: Omit<CaptureConfig, 'scenario'>, captures: Array<{
|
|
51
|
+
scenario: string;
|
|
52
|
+
request: IRChatRequest;
|
|
53
|
+
response: IRChatResponse;
|
|
54
|
+
}>): Promise<void>;
|
|
55
|
+
//# sourceMappingURL=fixture-capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture-capture.d.ts","sourceRoot":"","sources":["../../src/fixture-capture.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAmB,MAAM,oBAAoB,CAAC;AAGzF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,kCAAkC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAElC,kBAAkB;IAClB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAE5B,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AA8BD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,cAAc,EACxB,YAAY,CAAC,EAAE;IACb,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GACA,OAAO,CAAC,WAAW,CAAC,CA2BtB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,aAAa,CAAC,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE;IACb,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,oBAAoB,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC3C,GACA,OAAO,CAAC,gBAAgB,CAAC,CA4B3B;AAuBD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC;;4BAInD,aAAa,GAAG,aAAa;8BAOzC,cAAc,WACf,aAAa,GACrB,OAAO,CAAC,cAAc,CAAC;EAiB7B;AAiCD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,EACvC,QAAQ,EAAE,KAAK,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,cAAc,CAAC;CAC1B,CAAC,GACD,OAAO,CAAC,IAAI,CAAC,CAaf"}
|