ai-experiments 2.3.0 → 2.4.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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +8 -0
- package/dist/cartesian.d.ts +140 -0
- package/dist/cartesian.d.ts.map +1 -0
- package/dist/cartesian.js +216 -0
- package/dist/cartesian.js.map +1 -0
- package/dist/clickhouse-storage.d.ts +227 -0
- package/dist/clickhouse-storage.d.ts.map +1 -0
- package/dist/clickhouse-storage.js +522 -0
- package/dist/clickhouse-storage.js.map +1 -0
- package/dist/decide.d.ts +152 -0
- package/dist/decide.d.ts.map +1 -0
- package/dist/decide.js +333 -0
- package/dist/decide.js.map +1 -0
- package/dist/experiment.d.ts +53 -0
- package/dist/experiment.d.ts.map +1 -0
- package/dist/experiment.js +292 -0
- package/dist/experiment.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/tracking.d.ts +159 -0
- package/dist/tracking.d.ts.map +1 -0
- package/dist/tracking.js +310 -0
- package/dist/tracking.js.map +1 -0
- package/dist/types.d.ts +198 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Experiment execution and management
|
|
3
|
+
*/
|
|
4
|
+
import { randomUUID } from 'crypto';
|
|
5
|
+
import { track } from './tracking.js';
|
|
6
|
+
/**
|
|
7
|
+
* Create and run an A/B experiment with multiple variants
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { Experiment } from 'ai-experiments'
|
|
12
|
+
*
|
|
13
|
+
* const results = await Experiment({
|
|
14
|
+
* id: 'prompt-comparison',
|
|
15
|
+
* name: 'Prompt Engineering Test',
|
|
16
|
+
* variants: [
|
|
17
|
+
* {
|
|
18
|
+
* id: 'baseline',
|
|
19
|
+
* name: 'Baseline Prompt',
|
|
20
|
+
* config: { prompt: 'Summarize this text.' },
|
|
21
|
+
* },
|
|
22
|
+
* {
|
|
23
|
+
* id: 'detailed',
|
|
24
|
+
* name: 'Detailed Prompt',
|
|
25
|
+
* config: { prompt: 'Provide a comprehensive summary...' },
|
|
26
|
+
* },
|
|
27
|
+
* ],
|
|
28
|
+
* execute: async (config) => {
|
|
29
|
+
* return await ai.generate({ prompt: config.prompt })
|
|
30
|
+
* },
|
|
31
|
+
* metric: (result) => result.quality_score,
|
|
32
|
+
* })
|
|
33
|
+
*
|
|
34
|
+
* console.log('Best variant:', results.bestVariant)
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export async function Experiment(config, options = {}) {
|
|
38
|
+
const { parallel = true, maxConcurrency, stopOnError = false, context: contextData, onVariantStart, onVariantComplete, onVariantError, } = options;
|
|
39
|
+
const experimentStartTime = new Date();
|
|
40
|
+
// Track experiment start
|
|
41
|
+
track({
|
|
42
|
+
type: 'experiment.start',
|
|
43
|
+
timestamp: experimentStartTime,
|
|
44
|
+
data: {
|
|
45
|
+
experimentId: config.id,
|
|
46
|
+
experimentName: config.name,
|
|
47
|
+
variantCount: config.variants.length,
|
|
48
|
+
parallel,
|
|
49
|
+
...config.metadata,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const results = [];
|
|
53
|
+
// Execute variants
|
|
54
|
+
if (parallel) {
|
|
55
|
+
// Parallel execution with optional concurrency limit
|
|
56
|
+
const executeVariant = async (variant) => {
|
|
57
|
+
return runVariant(config, variant, contextData, {
|
|
58
|
+
...(onVariantStart !== undefined && { onVariantStart }),
|
|
59
|
+
...(onVariantComplete !== undefined && { onVariantComplete }),
|
|
60
|
+
...(onVariantError !== undefined && { onVariantError }),
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
if (maxConcurrency && maxConcurrency > 0) {
|
|
64
|
+
// Execute with concurrency limit
|
|
65
|
+
const chunks = chunkArray(config.variants, maxConcurrency);
|
|
66
|
+
for (const chunk of chunks) {
|
|
67
|
+
const chunkResults = await Promise.all(chunk.map(executeVariant));
|
|
68
|
+
results.push(...chunkResults);
|
|
69
|
+
// Stop on first error if configured
|
|
70
|
+
if (stopOnError && chunkResults.some((r) => !r.success)) {
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Execute all in parallel
|
|
77
|
+
const allResults = await Promise.all(config.variants.map(executeVariant));
|
|
78
|
+
results.push(...allResults);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Sequential execution
|
|
83
|
+
for (const variant of config.variants) {
|
|
84
|
+
const result = await runVariant(config, variant, contextData, {
|
|
85
|
+
...(onVariantStart !== undefined && { onVariantStart }),
|
|
86
|
+
...(onVariantComplete !== undefined && { onVariantComplete }),
|
|
87
|
+
...(onVariantError !== undefined && { onVariantError }),
|
|
88
|
+
});
|
|
89
|
+
results.push(result);
|
|
90
|
+
// Stop on first error if configured
|
|
91
|
+
if (stopOnError && !result.success) {
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const experimentEndTime = new Date();
|
|
97
|
+
const totalDuration = experimentEndTime.getTime() - experimentStartTime.getTime();
|
|
98
|
+
// Find best variant by metric
|
|
99
|
+
let bestVariant;
|
|
100
|
+
const successfulResults = results.filter((r) => r.success && r.metricValue !== undefined);
|
|
101
|
+
if (successfulResults.length > 0) {
|
|
102
|
+
const best = successfulResults.reduce((prev, current) => (current.metricValue ?? -Infinity) > (prev.metricValue ?? -Infinity) ? current : prev);
|
|
103
|
+
bestVariant = {
|
|
104
|
+
variantId: best.variantId,
|
|
105
|
+
variantName: best.variantName,
|
|
106
|
+
metricValue: best.metricValue,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const summary = {
|
|
110
|
+
experimentId: config.id,
|
|
111
|
+
experimentName: config.name,
|
|
112
|
+
results,
|
|
113
|
+
...(bestVariant !== undefined && { bestVariant }),
|
|
114
|
+
totalDuration,
|
|
115
|
+
successCount: results.filter((r) => r.success).length,
|
|
116
|
+
failureCount: results.filter((r) => !r.success).length,
|
|
117
|
+
startedAt: experimentStartTime,
|
|
118
|
+
completedAt: experimentEndTime,
|
|
119
|
+
};
|
|
120
|
+
// Track experiment completion
|
|
121
|
+
track({
|
|
122
|
+
type: 'experiment.complete',
|
|
123
|
+
timestamp: experimentEndTime,
|
|
124
|
+
data: {
|
|
125
|
+
experimentId: config.id,
|
|
126
|
+
experimentName: config.name,
|
|
127
|
+
successCount: summary.successCount,
|
|
128
|
+
failureCount: summary.failureCount,
|
|
129
|
+
totalDuration,
|
|
130
|
+
bestVariant: bestVariant?.variantId,
|
|
131
|
+
...config.metadata,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
return summary;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Run a single variant
|
|
138
|
+
*/
|
|
139
|
+
async function runVariant(config, variant, contextData, callbacks) {
|
|
140
|
+
const runId = randomUUID();
|
|
141
|
+
const startTime = new Date();
|
|
142
|
+
const context = {
|
|
143
|
+
experimentId: config.id,
|
|
144
|
+
variantId: variant.id,
|
|
145
|
+
runId,
|
|
146
|
+
startedAt: startTime,
|
|
147
|
+
...(contextData !== undefined && { data: contextData }),
|
|
148
|
+
};
|
|
149
|
+
// Track variant start
|
|
150
|
+
track({
|
|
151
|
+
type: 'variant.start',
|
|
152
|
+
timestamp: startTime,
|
|
153
|
+
data: {
|
|
154
|
+
experimentId: config.id,
|
|
155
|
+
variantId: variant.id,
|
|
156
|
+
variantName: variant.name,
|
|
157
|
+
runId,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
callbacks.onVariantStart?.(variant.id, variant.name);
|
|
161
|
+
try {
|
|
162
|
+
// Execute the variant
|
|
163
|
+
const result = await config.execute(variant.config, context);
|
|
164
|
+
const endTime = new Date();
|
|
165
|
+
const duration = endTime.getTime() - startTime.getTime();
|
|
166
|
+
// Compute metric if provided
|
|
167
|
+
let metricValue;
|
|
168
|
+
if (config.metric) {
|
|
169
|
+
metricValue = await config.metric(result);
|
|
170
|
+
track({
|
|
171
|
+
type: 'metric.computed',
|
|
172
|
+
timestamp: new Date(),
|
|
173
|
+
data: {
|
|
174
|
+
experimentId: config.id,
|
|
175
|
+
variantId: variant.id,
|
|
176
|
+
runId,
|
|
177
|
+
metricValue,
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
const experimentResult = {
|
|
182
|
+
experimentId: config.id,
|
|
183
|
+
variantId: variant.id,
|
|
184
|
+
variantName: variant.name,
|
|
185
|
+
runId,
|
|
186
|
+
result,
|
|
187
|
+
...(metricValue !== undefined && { metricValue }),
|
|
188
|
+
duration,
|
|
189
|
+
startedAt: startTime,
|
|
190
|
+
completedAt: endTime,
|
|
191
|
+
success: true,
|
|
192
|
+
};
|
|
193
|
+
// Track variant completion
|
|
194
|
+
track({
|
|
195
|
+
type: 'variant.complete',
|
|
196
|
+
timestamp: endTime,
|
|
197
|
+
data: {
|
|
198
|
+
experimentId: config.id,
|
|
199
|
+
variantId: variant.id,
|
|
200
|
+
variantName: variant.name,
|
|
201
|
+
runId,
|
|
202
|
+
duration,
|
|
203
|
+
metricValue,
|
|
204
|
+
success: true,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
callbacks.onVariantComplete?.(experimentResult);
|
|
208
|
+
return experimentResult;
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
const endTime = new Date();
|
|
212
|
+
const duration = endTime.getTime() - startTime.getTime();
|
|
213
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
214
|
+
// Track variant error
|
|
215
|
+
track({
|
|
216
|
+
type: 'variant.error',
|
|
217
|
+
timestamp: endTime,
|
|
218
|
+
data: {
|
|
219
|
+
experimentId: config.id,
|
|
220
|
+
variantId: variant.id,
|
|
221
|
+
variantName: variant.name,
|
|
222
|
+
runId,
|
|
223
|
+
duration,
|
|
224
|
+
error: err.message,
|
|
225
|
+
stack: err.stack,
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
callbacks.onVariantError?.(variant.id, err);
|
|
229
|
+
return {
|
|
230
|
+
experimentId: config.id,
|
|
231
|
+
variantId: variant.id,
|
|
232
|
+
variantName: variant.name,
|
|
233
|
+
runId,
|
|
234
|
+
result: undefined,
|
|
235
|
+
duration,
|
|
236
|
+
startedAt: startTime,
|
|
237
|
+
completedAt: endTime,
|
|
238
|
+
error: err,
|
|
239
|
+
success: false,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Split array into chunks
|
|
245
|
+
*/
|
|
246
|
+
function chunkArray(array, size) {
|
|
247
|
+
const chunks = [];
|
|
248
|
+
for (let i = 0; i < array.length; i += size) {
|
|
249
|
+
chunks.push(array.slice(i, i + size));
|
|
250
|
+
}
|
|
251
|
+
return chunks;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Helper to create experiment variants from a parameter grid
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```ts
|
|
258
|
+
* const variants = createVariantsFromGrid({
|
|
259
|
+
* temperature: [0.3, 0.7, 1.0],
|
|
260
|
+
* model: ['sonnet', 'opus'],
|
|
261
|
+
* maxTokens: [100, 500],
|
|
262
|
+
* })
|
|
263
|
+
* // Returns 12 variants (3 * 2 * 2 combinations)
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
export function createVariantsFromGrid(grid) {
|
|
267
|
+
const keys = Object.keys(grid);
|
|
268
|
+
const values = keys.map((k) => grid[k]);
|
|
269
|
+
// Generate all combinations
|
|
270
|
+
const combinations = cartesianProduct(values);
|
|
271
|
+
return combinations.map((combo, index) => {
|
|
272
|
+
const config = Object.fromEntries(keys.map((key, i) => [key, combo[i]]));
|
|
273
|
+
return {
|
|
274
|
+
id: `variant-${index}`,
|
|
275
|
+
name: keys.map((k, i) => `${String(k)}=${combo[i]}`).join(', '),
|
|
276
|
+
config,
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Cartesian product helper
|
|
282
|
+
*/
|
|
283
|
+
function cartesianProduct(arrays) {
|
|
284
|
+
if (arrays.length === 0)
|
|
285
|
+
return [[]];
|
|
286
|
+
if (arrays.length === 1)
|
|
287
|
+
return arrays[0].map((x) => [x]);
|
|
288
|
+
const [first, ...rest] = arrays;
|
|
289
|
+
const restProduct = cartesianProduct(rest);
|
|
290
|
+
return first.flatMap((x) => restProduct.map((arr) => [x, ...arr]));
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=experiment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experiment.js","sourceRoot":"","sources":["../src/experiment.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-experiments - AI-powered experimentation primitives for testing and evaluating models
|
|
3
|
+
*
|
|
4
|
+
* This package provides tools for A/B testing, parameter exploration, decision making,
|
|
5
|
+
* and tracking in AI applications.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export * from './types.js';
|
|
10
|
+
export { Experiment, createVariantsFromGrid } from './experiment.js';
|
|
11
|
+
export { cartesian, cartesianFilter, cartesianSample, cartesianCount, cartesianWithLabels, } from './cartesian.js';
|
|
12
|
+
export { decide, decideWeighted, decideEpsilonGreedy, decideThompsonSampling, decideUCB, } from './decide.js';
|
|
13
|
+
export { track, flush, configureTracking, getTrackingConfig, createConsoleBackend, createMemoryBackend, createBatchBackend, createFileBackend, } from './tracking.js';
|
|
14
|
+
export { ClickHouseExperimentStorage, createClickHouseExperimentStorage, bootstrapExperimentsSchema, ChdbStorage, createChdbBackend, } from './clickhouse-storage.js';
|
|
15
|
+
export type { ClickHouseExperimentStorageOptions, ChdbStorageOptions, } from './clickhouse-storage.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,cAAc,YAAY,CAAA;AAG1B,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAGpE,OAAO,EACL,SAAS,EACT,eAAe,EACf,eAAe,EACf,cAAc,EACd,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACL,MAAM,EACN,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,GACV,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,KAAK,EACL,KAAK,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,eAAe,CAAA;AAGtB,OAAO,EACL,2BAA2B,EAC3B,iCAAiC,EACjC,0BAA0B,EAE1B,WAAW,EACX,iBAAiB,GAClB,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,kCAAkC,EAClC,kBAAkB,GACnB,MAAM,yBAAyB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-experiments - AI-powered experimentation primitives for testing and evaluating models
|
|
3
|
+
*
|
|
4
|
+
* This package provides tools for A/B testing, parameter exploration, decision making,
|
|
5
|
+
* and tracking in AI applications.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
// Export core types
|
|
10
|
+
export * from './types.js';
|
|
11
|
+
// Export experiment functionality
|
|
12
|
+
export { Experiment, createVariantsFromGrid } from './experiment.js';
|
|
13
|
+
// Export cartesian product utilities
|
|
14
|
+
export { cartesian, cartesianFilter, cartesianSample, cartesianCount, cartesianWithLabels, } from './cartesian.js';
|
|
15
|
+
// Export decision making utilities
|
|
16
|
+
export { decide, decideWeighted, decideEpsilonGreedy, decideThompsonSampling, decideUCB, } from './decide.js';
|
|
17
|
+
// Export tracking utilities
|
|
18
|
+
export { track, flush, configureTracking, getTrackingConfig, createConsoleBackend, createMemoryBackend, createBatchBackend, createFileBackend, } from './tracking.js';
|
|
19
|
+
// Export ClickHouse storage backend (canonical adapter via ai-database)
|
|
20
|
+
export { ClickHouseExperimentStorage, createClickHouseExperimentStorage, bootstrapExperimentsSchema,
|
|
21
|
+
// Backwards-compat aliases
|
|
22
|
+
ChdbStorage, createChdbBackend, } from './clickhouse-storage.js';
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,oBAAoB;AACpB,cAAc,YAAY,CAAA;AAE1B,kCAAkC;AAClC,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAEpE,qCAAqC;AACrC,OAAO,EACL,SAAS,EACT,eAAe,EACf,eAAe,EACf,cAAc,EACd,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAEvB,mCAAmC;AACnC,OAAO,EACL,MAAM,EACN,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,GACV,MAAM,aAAa,CAAA;AAEpB,4BAA4B;AAC5B,OAAO,EACL,KAAK,EACL,KAAK,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,eAAe,CAAA;AAEtB,wEAAwE;AACxE,OAAO,EACL,2BAA2B,EAC3B,iCAAiC,EACjC,0BAA0B;AAC1B,2BAA2B;AAC3B,WAAW,EACX,iBAAiB,GAClB,MAAM,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event tracking for experiments
|
|
3
|
+
*/
|
|
4
|
+
import type { TrackingEvent, TrackingBackend, TrackingOptions } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Configure tracking
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { configureTracking } from 'ai-experiments'
|
|
11
|
+
*
|
|
12
|
+
* // Use console backend (default)
|
|
13
|
+
* configureTracking({
|
|
14
|
+
* enabled: true,
|
|
15
|
+
* metadata: { projectId: 'my-project' },
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* // Use custom backend
|
|
19
|
+
* configureTracking({
|
|
20
|
+
* backend: {
|
|
21
|
+
* track: async (event) => {
|
|
22
|
+
* await fetch('/api/analytics', {
|
|
23
|
+
* method: 'POST',
|
|
24
|
+
* body: JSON.stringify(event),
|
|
25
|
+
* })
|
|
26
|
+
* },
|
|
27
|
+
* },
|
|
28
|
+
* })
|
|
29
|
+
*
|
|
30
|
+
* // Disable tracking
|
|
31
|
+
* configureTracking({ enabled: false })
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function configureTracking(options: TrackingOptions): void;
|
|
35
|
+
/**
|
|
36
|
+
* Track an event
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { track } from 'ai-experiments'
|
|
41
|
+
*
|
|
42
|
+
* track({
|
|
43
|
+
* type: 'experiment.start',
|
|
44
|
+
* timestamp: new Date(),
|
|
45
|
+
* data: {
|
|
46
|
+
* experimentId: 'my-experiment',
|
|
47
|
+
* variantCount: 3,
|
|
48
|
+
* },
|
|
49
|
+
* })
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function track(event: TrackingEvent): void;
|
|
53
|
+
/**
|
|
54
|
+
* Flush pending events
|
|
55
|
+
*
|
|
56
|
+
* Call this before the process exits to ensure all events are sent.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { flush } from 'ai-experiments'
|
|
61
|
+
*
|
|
62
|
+
* process.on('SIGINT', async () => {
|
|
63
|
+
* await flush()
|
|
64
|
+
* process.exit(0)
|
|
65
|
+
* })
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function flush(): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Create a console-based tracking backend
|
|
71
|
+
*
|
|
72
|
+
* Logs events to console.log in a human-readable format.
|
|
73
|
+
*/
|
|
74
|
+
export declare function createConsoleBackend(options?: {
|
|
75
|
+
/** Whether to include full event data (default: false) */
|
|
76
|
+
verbose?: boolean;
|
|
77
|
+
}): TrackingBackend;
|
|
78
|
+
/**
|
|
79
|
+
* Create an in-memory tracking backend that stores events
|
|
80
|
+
*
|
|
81
|
+
* Useful for testing or collecting events for batch processing.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* import { createMemoryBackend } from 'ai-experiments'
|
|
86
|
+
*
|
|
87
|
+
* const backend = createMemoryBackend()
|
|
88
|
+
* configureTracking({ backend })
|
|
89
|
+
*
|
|
90
|
+
* // Run experiments...
|
|
91
|
+
*
|
|
92
|
+
* // Get all events
|
|
93
|
+
* const events = backend.getEvents()
|
|
94
|
+
* console.log(`Tracked ${events.length} events`)
|
|
95
|
+
*
|
|
96
|
+
* // Clear events
|
|
97
|
+
* backend.clear()
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export declare function createMemoryBackend(): TrackingBackend & {
|
|
101
|
+
getEvents: () => TrackingEvent[];
|
|
102
|
+
clear: () => void;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Create a batching tracking backend
|
|
106
|
+
*
|
|
107
|
+
* Batches events and sends them in groups to reduce network overhead.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* import { createBatchBackend } from 'ai-experiments'
|
|
112
|
+
*
|
|
113
|
+
* const backend = createBatchBackend({
|
|
114
|
+
* batchSize: 10,
|
|
115
|
+
* flushInterval: 5000, // 5 seconds
|
|
116
|
+
* send: async (events) => {
|
|
117
|
+
* await fetch('/api/analytics/batch', {
|
|
118
|
+
* method: 'POST',
|
|
119
|
+
* body: JSON.stringify({ events }),
|
|
120
|
+
* })
|
|
121
|
+
* },
|
|
122
|
+
* })
|
|
123
|
+
*
|
|
124
|
+
* configureTracking({ backend })
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export declare function createBatchBackend(options: {
|
|
128
|
+
/** Maximum batch size before auto-flush */
|
|
129
|
+
batchSize: number;
|
|
130
|
+
/** Interval in ms to auto-flush (default: no auto-flush) */
|
|
131
|
+
flushInterval?: number;
|
|
132
|
+
/** Function to send batched events */
|
|
133
|
+
send: (events: TrackingEvent[]) => Promise<void>;
|
|
134
|
+
}): TrackingBackend;
|
|
135
|
+
/**
|
|
136
|
+
* Create a file-based tracking backend
|
|
137
|
+
*
|
|
138
|
+
* Writes events to a file (JSONL format).
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* import { createFileBackend } from 'ai-experiments'
|
|
143
|
+
*
|
|
144
|
+
* const backend = createFileBackend({
|
|
145
|
+
* path: './experiments.jsonl',
|
|
146
|
+
* })
|
|
147
|
+
*
|
|
148
|
+
* configureTracking({ backend })
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export declare function createFileBackend(options: {
|
|
152
|
+
/** Path to the file */
|
|
153
|
+
path: string;
|
|
154
|
+
}): TrackingBackend;
|
|
155
|
+
/**
|
|
156
|
+
* Get current tracking configuration
|
|
157
|
+
*/
|
|
158
|
+
export declare function getTrackingConfig(): Readonly<Required<TrackingOptions>>;
|
|
159
|
+
//# sourceMappingURL=tracking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../src/tracking.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAWjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAMhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAsBhD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAI3C;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IAC7C,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,GAAG,eAAe,CAgBlB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,IAAI,eAAe,GAAG;IACvD,SAAS,EAAE,MAAM,aAAa,EAAE,CAAA;IAChC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB,CAYA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAA;IACjB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,sCAAsC;IACtC,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACjD,GAAG,eAAe,CAkDlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,eAAe,CAwClB;AAaD;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAEvE"}
|