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.
@@ -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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"}
@@ -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"}