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,152 @@
1
+ /**
2
+ * Decision making utilities
3
+ */
4
+ import type { DecideOptions, DecisionResult } from './types.js';
5
+ /**
6
+ * Make a decision by evaluating and scoring multiple options
7
+ *
8
+ * Scores each option and returns the best one (highest score).
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { decide } from 'ai-experiments'
13
+ *
14
+ * // Simple decision with sync scoring
15
+ * const result = await decide({
16
+ * options: ['apple', 'banana', 'orange'],
17
+ * score: (fruit) => {
18
+ * const prices = { apple: 1.5, banana: 0.5, orange: 2.0 }
19
+ * return 1 / prices[fruit] // Lower price = higher score
20
+ * },
21
+ * })
22
+ * console.log(result.selected) // 'banana'
23
+ *
24
+ * // Decision with async scoring (AI-based)
25
+ * const result = await decide({
26
+ * options: [
27
+ * { prompt: 'Summarize in one sentence' },
28
+ * { prompt: 'Provide a detailed summary' },
29
+ * { prompt: 'Extract key points only' },
30
+ * ],
31
+ * score: async (option) => {
32
+ * const result = await ai.generate(option)
33
+ * return evaluateQuality(result)
34
+ * },
35
+ * context: 'Choosing best summarization approach',
36
+ * })
37
+ *
38
+ * // Get all options sorted by score
39
+ * const result = await decide({
40
+ * options: ['fast', 'accurate', 'balanced'],
41
+ * score: (approach) => evaluateApproach(approach),
42
+ * returnAll: true,
43
+ * })
44
+ * console.log(result.allOptions)
45
+ * // [
46
+ * // { option: 'balanced', score: 0.9 },
47
+ * // { option: 'accurate', score: 0.85 },
48
+ * // { option: 'fast', score: 0.7 },
49
+ * // ]
50
+ * ```
51
+ */
52
+ export declare function decide<T>(options: DecideOptions<T>): Promise<DecisionResult<T>>;
53
+ /**
54
+ * Weighted random selection from options
55
+ *
56
+ * Each option has a weight, and selection probability is proportional to weight.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * import { decideWeighted } from 'ai-experiments'
61
+ *
62
+ * const result = decideWeighted([
63
+ * { value: 'A', weight: 0.7 }, // 70% chance
64
+ * { value: 'B', weight: 0.2 }, // 20% chance
65
+ * { value: 'C', weight: 0.1 }, // 10% chance
66
+ * ])
67
+ *
68
+ * console.log(result) // Most likely 'A', but could be B or C
69
+ * ```
70
+ */
71
+ export declare function decideWeighted<T>(options: Array<{
72
+ value: T;
73
+ weight: number;
74
+ }>): T;
75
+ /**
76
+ * Epsilon-greedy decision strategy
77
+ *
78
+ * With probability epsilon, select a random option (exploration).
79
+ * Otherwise, select the best option by score (exploitation).
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * import { decideEpsilonGreedy } from 'ai-experiments'
84
+ *
85
+ * const result = await decideEpsilonGreedy({
86
+ * options: ['model-a', 'model-b', 'model-c'],
87
+ * score: async (model) => await evaluateModel(model),
88
+ * epsilon: 0.1, // 10% exploration, 90% exploitation
89
+ * })
90
+ * ```
91
+ */
92
+ export declare function decideEpsilonGreedy<T>(options: DecideOptions<T> & {
93
+ epsilon: number;
94
+ }): Promise<DecisionResult<T>>;
95
+ /**
96
+ * Thompson sampling decision strategy
97
+ *
98
+ * Bayesian approach to balancing exploration and exploitation.
99
+ * Each option has a Beta distribution representing our belief about its true score.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import { decideThompsonSampling } from 'ai-experiments'
104
+ *
105
+ * // Track successes and failures for each option
106
+ * const priors = {
107
+ * 'variant-a': { alpha: 10, beta: 5 }, // 10 successes, 5 failures
108
+ * 'variant-b': { alpha: 8, beta: 3 }, // 8 successes, 3 failures
109
+ * 'variant-c': { alpha: 2, beta: 2 }, // 2 successes, 2 failures (uncertain)
110
+ * }
111
+ *
112
+ * const result = decideThompsonSampling(['variant-a', 'variant-b', 'variant-c'], priors)
113
+ * // More likely to select 'variant-b' (higher rate) but will sometimes explore 'variant-c'
114
+ * ```
115
+ */
116
+ export declare function decideThompsonSampling<T extends string>(options: T[], priors: Record<T, {
117
+ alpha: number;
118
+ beta: number;
119
+ }>): T;
120
+ /**
121
+ * Upper Confidence Bound (UCB) decision strategy
122
+ *
123
+ * Select the option with the highest upper confidence bound.
124
+ * Balances exploration and exploitation using confidence intervals.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * import { decideUCB } from 'ai-experiments'
129
+ *
130
+ * const stats = {
131
+ * 'variant-a': { mean: 0.85, count: 100 },
132
+ * 'variant-b': { mean: 0.82, count: 50 }, // Less data, higher uncertainty
133
+ * 'variant-c': { mean: 0.78, count: 10 }, // Very uncertain
134
+ * }
135
+ *
136
+ * const result = decideUCB(['variant-a', 'variant-b', 'variant-c'], stats, {
137
+ * explorationFactor: 2.0,
138
+ * totalCount: 160,
139
+ * })
140
+ * // Might select variant-c to explore more, despite lower mean
141
+ * ```
142
+ */
143
+ export declare function decideUCB<T extends string>(options: T[], stats: Record<T, {
144
+ mean: number;
145
+ count: number;
146
+ }>, config: {
147
+ /** Exploration factor (typically 1-2) */
148
+ explorationFactor: number;
149
+ /** Total number of trials across all options */
150
+ totalCount: number;
151
+ }): T;
152
+ //# sourceMappingURL=decide.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decide.d.ts","sourceRoot":"","sources":["../src/decide.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAG/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAsB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CA2CrF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,CAAC,CA0BjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAiD5B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,EACrD,OAAO,EAAE,CAAC,EAAE,EACZ,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GACjD,CAAC,CA6BH;AAuDD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EACxC,OAAO,EAAE,CAAC,EAAE,EACZ,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EACjD,MAAM,EAAE;IACN,yCAAyC;IACzC,iBAAiB,EAAE,MAAM,CAAA;IACzB,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAA;CACnB,GACA,CAAC,CAwCH"}
package/dist/decide.js ADDED
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Decision making utilities
3
+ */
4
+ import { track } from './tracking.js';
5
+ /**
6
+ * Make a decision by evaluating and scoring multiple options
7
+ *
8
+ * Scores each option and returns the best one (highest score).
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { decide } from 'ai-experiments'
13
+ *
14
+ * // Simple decision with sync scoring
15
+ * const result = await decide({
16
+ * options: ['apple', 'banana', 'orange'],
17
+ * score: (fruit) => {
18
+ * const prices = { apple: 1.5, banana: 0.5, orange: 2.0 }
19
+ * return 1 / prices[fruit] // Lower price = higher score
20
+ * },
21
+ * })
22
+ * console.log(result.selected) // 'banana'
23
+ *
24
+ * // Decision with async scoring (AI-based)
25
+ * const result = await decide({
26
+ * options: [
27
+ * { prompt: 'Summarize in one sentence' },
28
+ * { prompt: 'Provide a detailed summary' },
29
+ * { prompt: 'Extract key points only' },
30
+ * ],
31
+ * score: async (option) => {
32
+ * const result = await ai.generate(option)
33
+ * return evaluateQuality(result)
34
+ * },
35
+ * context: 'Choosing best summarization approach',
36
+ * })
37
+ *
38
+ * // Get all options sorted by score
39
+ * const result = await decide({
40
+ * options: ['fast', 'accurate', 'balanced'],
41
+ * score: (approach) => evaluateApproach(approach),
42
+ * returnAll: true,
43
+ * })
44
+ * console.log(result.allOptions)
45
+ * // [
46
+ * // { option: 'balanced', score: 0.9 },
47
+ * // { option: 'accurate', score: 0.85 },
48
+ * // { option: 'fast', score: 0.7 },
49
+ * // ]
50
+ * ```
51
+ */
52
+ export async function decide(options) {
53
+ const { options: choices, score, context, returnAll = false } = options;
54
+ if (choices.length === 0) {
55
+ throw new Error('Cannot decide with empty options');
56
+ }
57
+ // Score all options
58
+ const scoredOptions = await Promise.all(choices.map(async (option) => {
59
+ const optionScore = await score(option);
60
+ return { option, score: optionScore };
61
+ }));
62
+ // Sort by score (highest first)
63
+ const sorted = scoredOptions.sort((a, b) => b.score - a.score);
64
+ // Select best option
65
+ const best = sorted[0];
66
+ // Track decision
67
+ track({
68
+ type: 'decision.made',
69
+ timestamp: new Date(),
70
+ data: {
71
+ context,
72
+ optionCount: choices.length,
73
+ selectedScore: best.score,
74
+ allScores: sorted.map((s) => s.score),
75
+ },
76
+ });
77
+ const result = {
78
+ selected: best.option,
79
+ score: best.score,
80
+ };
81
+ if (returnAll) {
82
+ result.allOptions = sorted;
83
+ }
84
+ return result;
85
+ }
86
+ /**
87
+ * Weighted random selection from options
88
+ *
89
+ * Each option has a weight, and selection probability is proportional to weight.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * import { decideWeighted } from 'ai-experiments'
94
+ *
95
+ * const result = decideWeighted([
96
+ * { value: 'A', weight: 0.7 }, // 70% chance
97
+ * { value: 'B', weight: 0.2 }, // 20% chance
98
+ * { value: 'C', weight: 0.1 }, // 10% chance
99
+ * ])
100
+ *
101
+ * console.log(result) // Most likely 'A', but could be B or C
102
+ * ```
103
+ */
104
+ export function decideWeighted(options) {
105
+ if (options.length === 0) {
106
+ throw new Error('Cannot decide with empty options');
107
+ }
108
+ // Calculate total weight
109
+ const totalWeight = options.reduce((sum, opt) => sum + opt.weight, 0);
110
+ if (totalWeight <= 0) {
111
+ throw new Error('Total weight must be positive');
112
+ }
113
+ // Generate random value between 0 and totalWeight
114
+ const random = Math.random() * totalWeight;
115
+ // Find the option that corresponds to this random value
116
+ let cumulative = 0;
117
+ for (const option of options) {
118
+ cumulative += option.weight;
119
+ if (random <= cumulative) {
120
+ return option.value;
121
+ }
122
+ }
123
+ // Fallback (should not reach here due to floating point precision)
124
+ return options[options.length - 1].value;
125
+ }
126
+ /**
127
+ * Epsilon-greedy decision strategy
128
+ *
129
+ * With probability epsilon, select a random option (exploration).
130
+ * Otherwise, select the best option by score (exploitation).
131
+ *
132
+ * @example
133
+ * ```ts
134
+ * import { decideEpsilonGreedy } from 'ai-experiments'
135
+ *
136
+ * const result = await decideEpsilonGreedy({
137
+ * options: ['model-a', 'model-b', 'model-c'],
138
+ * score: async (model) => await evaluateModel(model),
139
+ * epsilon: 0.1, // 10% exploration, 90% exploitation
140
+ * })
141
+ * ```
142
+ */
143
+ export async function decideEpsilonGreedy(options) {
144
+ const { epsilon, options: choices, score, context } = options;
145
+ if (epsilon < 0 || epsilon > 1) {
146
+ throw new Error('Epsilon must be between 0 and 1');
147
+ }
148
+ // Exploration: random selection
149
+ if (Math.random() < epsilon) {
150
+ const randomIndex = Math.floor(Math.random() * choices.length);
151
+ const selected = choices[randomIndex];
152
+ const selectedScore = await score(selected);
153
+ track({
154
+ type: 'decision.made',
155
+ timestamp: new Date(),
156
+ data: {
157
+ context,
158
+ strategy: 'epsilon-greedy-explore',
159
+ epsilon,
160
+ selectedScore,
161
+ },
162
+ });
163
+ return {
164
+ selected,
165
+ score: selectedScore,
166
+ };
167
+ }
168
+ // Exploitation: best option
169
+ const result = await decide({
170
+ options: choices,
171
+ score,
172
+ ...(context !== undefined && { context }),
173
+ });
174
+ track({
175
+ type: 'decision.made',
176
+ timestamp: new Date(),
177
+ data: {
178
+ context,
179
+ strategy: 'epsilon-greedy-exploit',
180
+ epsilon,
181
+ selectedScore: result.score,
182
+ },
183
+ });
184
+ return result;
185
+ }
186
+ /**
187
+ * Thompson sampling decision strategy
188
+ *
189
+ * Bayesian approach to balancing exploration and exploitation.
190
+ * Each option has a Beta distribution representing our belief about its true score.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * import { decideThompsonSampling } from 'ai-experiments'
195
+ *
196
+ * // Track successes and failures for each option
197
+ * const priors = {
198
+ * 'variant-a': { alpha: 10, beta: 5 }, // 10 successes, 5 failures
199
+ * 'variant-b': { alpha: 8, beta: 3 }, // 8 successes, 3 failures
200
+ * 'variant-c': { alpha: 2, beta: 2 }, // 2 successes, 2 failures (uncertain)
201
+ * }
202
+ *
203
+ * const result = decideThompsonSampling(['variant-a', 'variant-b', 'variant-c'], priors)
204
+ * // More likely to select 'variant-b' (higher rate) but will sometimes explore 'variant-c'
205
+ * ```
206
+ */
207
+ export function decideThompsonSampling(options, priors) {
208
+ if (options.length === 0) {
209
+ throw new Error('Cannot decide with empty options');
210
+ }
211
+ // Sample from Beta distribution for each option
212
+ const samples = options.map((option) => {
213
+ const { alpha, beta } = priors[option];
214
+ return {
215
+ option,
216
+ sample: sampleBeta(alpha, beta),
217
+ };
218
+ });
219
+ // Select option with highest sample
220
+ const best = samples.reduce((prev, current) => (current.sample > prev.sample ? current : prev));
221
+ track({
222
+ type: 'decision.made',
223
+ timestamp: new Date(),
224
+ data: {
225
+ strategy: 'thompson-sampling',
226
+ selected: best.option,
227
+ sample: best.sample,
228
+ priors: priors[best.option],
229
+ },
230
+ });
231
+ return best.option;
232
+ }
233
+ /**
234
+ * Sample from Beta distribution using the ratio of two Gamma distributions
235
+ */
236
+ function sampleBeta(alpha, beta) {
237
+ const x = sampleGamma(alpha, 1);
238
+ const y = sampleGamma(beta, 1);
239
+ return x / (x + y);
240
+ }
241
+ /**
242
+ * Sample from Gamma distribution using Marsaglia and Tsang method
243
+ */
244
+ function sampleGamma(shape, scale) {
245
+ // Simple implementation for shape >= 1
246
+ if (shape < 1) {
247
+ // Use the property: Gamma(a) = Gamma(a+1) * U^(1/a)
248
+ return sampleGamma(shape + 1, scale) * Math.pow(Math.random(), 1 / shape);
249
+ }
250
+ const d = shape - 1 / 3;
251
+ const c = 1 / Math.sqrt(9 * d);
252
+ while (true) {
253
+ let x;
254
+ let v;
255
+ do {
256
+ x = randomNormal();
257
+ v = 1 + c * x;
258
+ } while (v <= 0);
259
+ v = v * v * v;
260
+ const u = Math.random();
261
+ if (u < 1 - 0.0331 * x * x * x * x) {
262
+ return d * v * scale;
263
+ }
264
+ if (Math.log(u) < 0.5 * x * x + d * (1 - v + Math.log(v))) {
265
+ return d * v * scale;
266
+ }
267
+ }
268
+ }
269
+ /**
270
+ * Sample from standard normal distribution using Box-Muller transform
271
+ */
272
+ function randomNormal() {
273
+ const u1 = Math.random();
274
+ const u2 = Math.random();
275
+ return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
276
+ }
277
+ /**
278
+ * Upper Confidence Bound (UCB) decision strategy
279
+ *
280
+ * Select the option with the highest upper confidence bound.
281
+ * Balances exploration and exploitation using confidence intervals.
282
+ *
283
+ * @example
284
+ * ```ts
285
+ * import { decideUCB } from 'ai-experiments'
286
+ *
287
+ * const stats = {
288
+ * 'variant-a': { mean: 0.85, count: 100 },
289
+ * 'variant-b': { mean: 0.82, count: 50 }, // Less data, higher uncertainty
290
+ * 'variant-c': { mean: 0.78, count: 10 }, // Very uncertain
291
+ * }
292
+ *
293
+ * const result = decideUCB(['variant-a', 'variant-b', 'variant-c'], stats, {
294
+ * explorationFactor: 2.0,
295
+ * totalCount: 160,
296
+ * })
297
+ * // Might select variant-c to explore more, despite lower mean
298
+ * ```
299
+ */
300
+ export function decideUCB(options, stats, config) {
301
+ const { explorationFactor, totalCount } = config;
302
+ if (options.length === 0) {
303
+ throw new Error('Cannot decide with empty options');
304
+ }
305
+ // Calculate UCB for each option
306
+ const ucbScores = options.map((option) => {
307
+ const { mean, count } = stats[option];
308
+ // UCB = mean + c * sqrt(ln(N) / n)
309
+ const explorationBonus = explorationFactor * Math.sqrt(Math.log(totalCount) / Math.max(count, 1));
310
+ return {
311
+ option,
312
+ ucb: mean + explorationBonus,
313
+ mean,
314
+ count,
315
+ };
316
+ });
317
+ // Select option with highest UCB
318
+ const best = ucbScores.reduce((prev, current) => (current.ucb > prev.ucb ? current : prev));
319
+ track({
320
+ type: 'decision.made',
321
+ timestamp: new Date(),
322
+ data: {
323
+ strategy: 'ucb',
324
+ selected: best.option,
325
+ ucb: best.ucb,
326
+ mean: best.mean,
327
+ count: best.count,
328
+ explorationFactor,
329
+ },
330
+ });
331
+ return best.option;
332
+ }
333
+ //# sourceMappingURL=decide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decide.js","sourceRoot":"","sources":["../src/decide.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAI,OAAyB;IACvD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IAEvE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,CAAC;IAED,oBAAoB;IACpB,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CACrC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAC3B,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAA;QACvC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,CAAA;IACvC,CAAC,CAAC,CACH,CAAA;IAED,gCAAgC;IAChC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;IAE9D,qBAAqB;IACrB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAE,CAAA;IAEvB,iBAAiB;IACjB,KAAK,CAAC;QACJ,IAAI,EAAE,eAAe;QACrB,SAAS,EAAE,IAAI,IAAI,EAAE;QACrB,IAAI,EAAE;YACJ,OAAO;YACP,WAAW,EAAE,OAAO,CAAC,MAAM;YAC3B,aAAa,EAAE,IAAI,CAAC,KAAK;YACzB,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;SACtC;KACF,CAAC,CAAA;IAEF,MAAM,MAAM,GAAsB;QAChC,QAAQ,EAAE,IAAI,CAAC,MAAM;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAA;IAED,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,UAAU,GAAG,MAAM,CAAA;IAC5B,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAAI,OAA4C;IAC5E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,CAAC;IAED,yBAAyB;IACzB,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IAErE,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;IAClD,CAAC;IAED,kDAAkD;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,CAAA;IAE1C,wDAAwD;IACxD,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,UAAU,IAAI,MAAM,CAAC,MAAM,CAAA;QAC3B,IAAI,MAAM,IAAI,UAAU,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC,KAAK,CAAA;QACrB,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,KAAK,CAAA;AAC3C,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA+C;IAE/C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAE7D,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;IAED,gCAAgC;IAChC,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;QAC5B,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAE,CAAA;QACtC,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAA;QAE3C,KAAK,CAAC;YACJ,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,IAAI,EAAE;gBACJ,OAAO;gBACP,QAAQ,EAAE,wBAAwB;gBAClC,OAAO;gBACP,aAAa;aACd;SACF,CAAC,CAAA;QAEF,OAAO;YACL,QAAQ;YACR,KAAK,EAAE,aAAa;SACrB,CAAA;IACH,CAAC;IAED,4BAA4B;IAC5B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;QAC1B,OAAO,EAAE,OAAO;QAChB,KAAK;QACL,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,CAAC;KAC1C,CAAC,CAAA;IAEF,KAAK,CAAC;QACJ,IAAI,EAAE,eAAe;QACrB,SAAS,EAAE,IAAI,IAAI,EAAE;QACrB,IAAI,EAAE;YACJ,OAAO;YACP,QAAQ,EAAE,wBAAwB;YAClC,OAAO;YACP,aAAa,EAAE,MAAM,CAAC,KAAK;SAC5B;KACF,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAY,EACZ,MAAkD;IAElD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,CAAC;IAED,gDAAgD;IAChD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACrC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;QACtC,OAAO;YACL,MAAM;YACN,MAAM,EAAE,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC;SAChC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,oCAAoC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAE/F,KAAK,CAAC;QACJ,IAAI,EAAE,eAAe;QACrB,SAAS,EAAE,IAAI,IAAI,EAAE;QACrB,IAAI,EAAE;YACJ,QAAQ,EAAE,mBAAmB;YAC7B,QAAQ,EAAE,IAAI,CAAC,MAAM;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;SAC5B;KACF,CAAC,CAAA;IAEF,OAAO,IAAI,CAAC,MAAM,CAAA;AACpB,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,KAAa,EAAE,IAAY;IAC7C,MAAM,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC/B,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;AACpB,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,KAAa,EAAE,KAAa;IAC/C,uCAAuC;IACvC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,oDAAoD;QACpD,OAAO,WAAW,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAA;IAC3E,CAAC;IAED,MAAM,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAA;IACvB,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAE9B,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAS,CAAA;QACb,IAAI,CAAS,CAAA;QAEb,GAAG,CAAC;YACF,CAAC,GAAG,YAAY,EAAE,CAAA;YAClB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACf,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAC;QAEhB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAEvB,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACtB,CAAC;QAED,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACtB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,YAAY;IACnB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;IACxB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;IACxB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAA;AAClE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,SAAS,CACvB,OAAY,EACZ,KAAiD,EACjD,MAKC;IAED,MAAM,EAAE,iBAAiB,EAAE,UAAU,EAAE,GAAG,MAAM,CAAA;IAEhD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,CAAC;IAED,gCAAgC;IAChC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACvC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAA;QAErC,mCAAmC;QACnC,MAAM,gBAAgB,GACpB,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;QAE1E,OAAO;YACL,MAAM;YACN,GAAG,EAAE,IAAI,GAAG,gBAAgB;YAC5B,IAAI;YACJ,KAAK;SACN,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,iCAAiC;IACjC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAE3F,KAAK,CAAC;QACJ,IAAI,EAAE,eAAe;QACrB,SAAS,EAAE,IAAI,IAAI,EAAE;QACrB,IAAI,EAAE;YACJ,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,IAAI,CAAC,MAAM;YACrB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,iBAAiB;SAClB;KACF,CAAC,CAAA;IAEF,OAAO,IAAI,CAAC,MAAM,CAAA;AACpB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Experiment execution and management
3
+ */
4
+ import type { ExperimentConfig, ExperimentSummary, RunExperimentOptions, ExperimentVariant } from './types.js';
5
+ /**
6
+ * Create and run an A/B experiment with multiple variants
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { Experiment } from 'ai-experiments'
11
+ *
12
+ * const results = await Experiment({
13
+ * id: 'prompt-comparison',
14
+ * name: 'Prompt Engineering Test',
15
+ * variants: [
16
+ * {
17
+ * id: 'baseline',
18
+ * name: 'Baseline Prompt',
19
+ * config: { prompt: 'Summarize this text.' },
20
+ * },
21
+ * {
22
+ * id: 'detailed',
23
+ * name: 'Detailed Prompt',
24
+ * config: { prompt: 'Provide a comprehensive summary...' },
25
+ * },
26
+ * ],
27
+ * execute: async (config) => {
28
+ * return await ai.generate({ prompt: config.prompt })
29
+ * },
30
+ * metric: (result) => result.quality_score,
31
+ * })
32
+ *
33
+ * console.log('Best variant:', results.bestVariant)
34
+ * ```
35
+ */
36
+ export declare function Experiment<TConfig = unknown, TResult = unknown>(config: ExperimentConfig<TConfig, TResult>, options?: RunExperimentOptions): Promise<ExperimentSummary<TResult>>;
37
+ /**
38
+ * Helper to create experiment variants from a parameter grid
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const variants = createVariantsFromGrid({
43
+ * temperature: [0.3, 0.7, 1.0],
44
+ * model: ['sonnet', 'opus'],
45
+ * maxTokens: [100, 500],
46
+ * })
47
+ * // Returns 12 variants (3 * 2 * 2 combinations)
48
+ * ```
49
+ */
50
+ export declare function createVariantsFromGrid<T extends Record<string, unknown[]>>(grid: T): ExperimentVariant<{
51
+ [K in keyof T]: T[K][number];
52
+ }>[];
53
+ //# sourceMappingURL=experiment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"experiment.d.ts","sourceRoot":"","sources":["../src/experiment.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,gBAAgB,EAGhB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,YAAY,CAAA;AAGnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACnE,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,EAC1C,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAwHrC;AA8ID;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EACxE,IAAI,EAAE,CAAC,GACN,iBAAiB,CAAC;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;CAAE,CAAC,EAAE,CAkBvD"}