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
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cartesian product utilities for parameter exploration
|
|
3
|
+
*/
|
|
4
|
+
import type { CartesianParams, CartesianResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Generate cartesian product of parameter sets
|
|
7
|
+
*
|
|
8
|
+
* Takes an object where each key maps to an array of possible values,
|
|
9
|
+
* and returns all possible combinations as an array of objects.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { cartesian } from 'ai-experiments'
|
|
14
|
+
*
|
|
15
|
+
* const combinations = cartesian({
|
|
16
|
+
* model: ['sonnet', 'opus', 'gpt-4o'],
|
|
17
|
+
* temperature: [0.3, 0.7, 1.0],
|
|
18
|
+
* maxTokens: [100, 500, 1000],
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* // Returns 27 combinations (3 * 3 * 3):
|
|
22
|
+
* // [
|
|
23
|
+
* // { model: 'sonnet', temperature: 0.3, maxTokens: 100 },
|
|
24
|
+
* // { model: 'sonnet', temperature: 0.3, maxTokens: 500 },
|
|
25
|
+
* // { model: 'sonnet', temperature: 0.3, maxTokens: 1000 },
|
|
26
|
+
* // { model: 'sonnet', temperature: 0.7, maxTokens: 100 },
|
|
27
|
+
* // ...
|
|
28
|
+
* // ]
|
|
29
|
+
*
|
|
30
|
+
* // Use with experiments:
|
|
31
|
+
* const variants = combinations.map((config, i) => ({
|
|
32
|
+
* id: `variant-${i}`,
|
|
33
|
+
* name: `${config.model} T=${config.temperature} max=${config.maxTokens}`,
|
|
34
|
+
* config,
|
|
35
|
+
* }))
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function cartesian<T extends CartesianParams>(params: T): CartesianResult<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Generate a grid of parameter combinations with filtering
|
|
41
|
+
*
|
|
42
|
+
* Similar to cartesian(), but allows filtering out invalid combinations.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* import { cartesianFilter } from 'ai-experiments'
|
|
47
|
+
*
|
|
48
|
+
* const combinations = cartesianFilter(
|
|
49
|
+
* {
|
|
50
|
+
* model: ['sonnet', 'opus'],
|
|
51
|
+
* temperature: [0.3, 0.7, 1.0],
|
|
52
|
+
* maxTokens: [100, 500],
|
|
53
|
+
* },
|
|
54
|
+
* // Filter out combinations where opus uses high temperature
|
|
55
|
+
* (combo) => !(combo.model === 'opus' && combo.temperature > 0.7)
|
|
56
|
+
* )
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function cartesianFilter<T extends CartesianParams>(params: T, filter: (combo: {
|
|
60
|
+
[K in keyof T]: T[K][number];
|
|
61
|
+
}) => boolean): CartesianResult<T>;
|
|
62
|
+
/**
|
|
63
|
+
* Generate a random sample from the cartesian product
|
|
64
|
+
*
|
|
65
|
+
* Useful when the full cartesian product is too large to test all combinations.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* import { cartesianSample } from 'ai-experiments'
|
|
70
|
+
*
|
|
71
|
+
* // Full product would be 1000 combinations (10 * 10 * 10)
|
|
72
|
+
* // Sample just 20 random combinations
|
|
73
|
+
* const sample = cartesianSample(
|
|
74
|
+
* {
|
|
75
|
+
* param1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
76
|
+
* param2: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
77
|
+
* param3: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
78
|
+
* },
|
|
79
|
+
* 20
|
|
80
|
+
* )
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function cartesianSample<T extends CartesianParams>(params: T, sampleSize: number, options?: {
|
|
84
|
+
/** Random seed for reproducibility */
|
|
85
|
+
seed?: number;
|
|
86
|
+
/** Whether to sample without replacement (default: true) */
|
|
87
|
+
unique?: boolean;
|
|
88
|
+
}): CartesianResult<T>;
|
|
89
|
+
/**
|
|
90
|
+
* Count the total number of combinations without generating them
|
|
91
|
+
*
|
|
92
|
+
* Useful for checking if cartesian product is feasible before generating.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { cartesianCount } from 'ai-experiments'
|
|
97
|
+
*
|
|
98
|
+
* const count = cartesianCount({
|
|
99
|
+
* model: ['sonnet', 'opus', 'gpt-4o'],
|
|
100
|
+
* temperature: [0.3, 0.5, 0.7, 0.9],
|
|
101
|
+
* maxTokens: [100, 500, 1000, 2000],
|
|
102
|
+
* })
|
|
103
|
+
* // Returns 48 (3 * 4 * 4)
|
|
104
|
+
*
|
|
105
|
+
* if (count > 100) {
|
|
106
|
+
* console.log('Too many combinations, use cartesianSample instead')
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare function cartesianCount<T extends CartesianParams>(params: T): number;
|
|
111
|
+
/**
|
|
112
|
+
* Generate cartesian product with labels for each dimension
|
|
113
|
+
*
|
|
114
|
+
* Returns combinations with additional metadata about which dimension each value came from.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* import { cartesianWithLabels } from 'ai-experiments'
|
|
119
|
+
*
|
|
120
|
+
* const labeled = cartesianWithLabels({
|
|
121
|
+
* model: ['sonnet', 'opus'],
|
|
122
|
+
* temperature: [0.3, 0.7],
|
|
123
|
+
* })
|
|
124
|
+
* // [
|
|
125
|
+
* // { values: { model: 'sonnet', temperature: 0.3 }, labels: { model: 0, temperature: 0 } },
|
|
126
|
+
* // { values: { model: 'sonnet', temperature: 0.7 }, labels: { model: 0, temperature: 1 } },
|
|
127
|
+
* // { values: { model: 'opus', temperature: 0.3 }, labels: { model: 1, temperature: 0 } },
|
|
128
|
+
* // { values: { model: 'opus', temperature: 0.7 }, labels: { model: 1, temperature: 1 } },
|
|
129
|
+
* // ]
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function cartesianWithLabels<T extends CartesianParams>(params: T): Array<{
|
|
133
|
+
values: {
|
|
134
|
+
[K in keyof T]: T[K][number];
|
|
135
|
+
};
|
|
136
|
+
labels: {
|
|
137
|
+
[K in keyof T]: number;
|
|
138
|
+
};
|
|
139
|
+
}>;
|
|
140
|
+
//# sourceMappingURL=cartesian.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cartesian.d.ts","sourceRoot":"","sources":["../src/cartesian.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,eAAe,EAAE,MAAM,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CA0BlF;AA4BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,eAAe,EACvD,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,CAAC,KAAK,EAAE;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;CAAE,KAAK,OAAO,GAC3D,eAAe,CAAC,CAAC,CAAC,CAGpB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,eAAe,EACvD,MAAM,EAAE,CAAC,EACT,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;IACP,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAA;CACZ,GACL,eAAe,CAAC,CAAC,CAAC,CAqBpB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,eAAe,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAS3E;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,eAAe,EAC3D,MAAM,EAAE,CAAC,GACR,KAAK,CAAC;IACP,MAAM,EAAE;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;KAAE,CAAA;IACxC,MAAM,EAAE;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM;KAAE,CAAA;CACnC,CAAC,CA0BD"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cartesian product utilities for parameter exploration
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Generate cartesian product of parameter sets
|
|
6
|
+
*
|
|
7
|
+
* Takes an object where each key maps to an array of possible values,
|
|
8
|
+
* and returns all possible combinations as an array of objects.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { cartesian } from 'ai-experiments'
|
|
13
|
+
*
|
|
14
|
+
* const combinations = cartesian({
|
|
15
|
+
* model: ['sonnet', 'opus', 'gpt-4o'],
|
|
16
|
+
* temperature: [0.3, 0.7, 1.0],
|
|
17
|
+
* maxTokens: [100, 500, 1000],
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* // Returns 27 combinations (3 * 3 * 3):
|
|
21
|
+
* // [
|
|
22
|
+
* // { model: 'sonnet', temperature: 0.3, maxTokens: 100 },
|
|
23
|
+
* // { model: 'sonnet', temperature: 0.3, maxTokens: 500 },
|
|
24
|
+
* // { model: 'sonnet', temperature: 0.3, maxTokens: 1000 },
|
|
25
|
+
* // { model: 'sonnet', temperature: 0.7, maxTokens: 100 },
|
|
26
|
+
* // ...
|
|
27
|
+
* // ]
|
|
28
|
+
*
|
|
29
|
+
* // Use with experiments:
|
|
30
|
+
* const variants = combinations.map((config, i) => ({
|
|
31
|
+
* id: `variant-${i}`,
|
|
32
|
+
* name: `${config.model} T=${config.temperature} max=${config.maxTokens}`,
|
|
33
|
+
* config,
|
|
34
|
+
* }))
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function cartesian(params) {
|
|
38
|
+
const keys = Object.keys(params);
|
|
39
|
+
const values = keys.map((k) => params[k]);
|
|
40
|
+
// Handle empty input
|
|
41
|
+
if (keys.length === 0) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
// Handle single parameter
|
|
45
|
+
if (keys.length === 1) {
|
|
46
|
+
const key = keys[0];
|
|
47
|
+
return values[0].map((val) => ({ [key]: val }));
|
|
48
|
+
}
|
|
49
|
+
// Generate all combinations using recursive helper
|
|
50
|
+
const combinations = cartesianProduct(values);
|
|
51
|
+
// Map back to objects
|
|
52
|
+
return combinations.map((combo) => {
|
|
53
|
+
const obj = {};
|
|
54
|
+
keys.forEach((key, i) => {
|
|
55
|
+
obj[key] = combo[i];
|
|
56
|
+
});
|
|
57
|
+
return obj;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Recursive cartesian product implementation
|
|
62
|
+
*/
|
|
63
|
+
function cartesianProduct(arrays) {
|
|
64
|
+
if (arrays.length === 0)
|
|
65
|
+
return [[]];
|
|
66
|
+
const [first, ...rest] = arrays;
|
|
67
|
+
// Base case: single array
|
|
68
|
+
if (rest.length === 0) {
|
|
69
|
+
return first.map((x) => [x]);
|
|
70
|
+
}
|
|
71
|
+
// Recursive case
|
|
72
|
+
const restProduct = cartesianProduct(rest);
|
|
73
|
+
const result = [];
|
|
74
|
+
for (const x of first) {
|
|
75
|
+
for (const restCombo of restProduct) {
|
|
76
|
+
result.push([x, ...restCombo]);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Generate a grid of parameter combinations with filtering
|
|
83
|
+
*
|
|
84
|
+
* Similar to cartesian(), but allows filtering out invalid combinations.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* import { cartesianFilter } from 'ai-experiments'
|
|
89
|
+
*
|
|
90
|
+
* const combinations = cartesianFilter(
|
|
91
|
+
* {
|
|
92
|
+
* model: ['sonnet', 'opus'],
|
|
93
|
+
* temperature: [0.3, 0.7, 1.0],
|
|
94
|
+
* maxTokens: [100, 500],
|
|
95
|
+
* },
|
|
96
|
+
* // Filter out combinations where opus uses high temperature
|
|
97
|
+
* (combo) => !(combo.model === 'opus' && combo.temperature > 0.7)
|
|
98
|
+
* )
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export function cartesianFilter(params, filter) {
|
|
102
|
+
const allCombinations = cartesian(params);
|
|
103
|
+
return allCombinations.filter(filter);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Generate a random sample from the cartesian product
|
|
107
|
+
*
|
|
108
|
+
* Useful when the full cartesian product is too large to test all combinations.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* import { cartesianSample } from 'ai-experiments'
|
|
113
|
+
*
|
|
114
|
+
* // Full product would be 1000 combinations (10 * 10 * 10)
|
|
115
|
+
* // Sample just 20 random combinations
|
|
116
|
+
* const sample = cartesianSample(
|
|
117
|
+
* {
|
|
118
|
+
* param1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
119
|
+
* param2: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
120
|
+
* param3: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
121
|
+
* },
|
|
122
|
+
* 20
|
|
123
|
+
* )
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export function cartesianSample(params, sampleSize, options = {}) {
|
|
127
|
+
const { unique = true } = options;
|
|
128
|
+
// Generate all combinations first
|
|
129
|
+
const allCombinations = cartesian(params);
|
|
130
|
+
// If sample size is larger than available combinations, return all
|
|
131
|
+
if (sampleSize >= allCombinations.length) {
|
|
132
|
+
return allCombinations;
|
|
133
|
+
}
|
|
134
|
+
// Shuffle and take first n items
|
|
135
|
+
const shuffled = [...allCombinations];
|
|
136
|
+
// Simple Fisher-Yates shuffle
|
|
137
|
+
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
138
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
139
|
+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
|
140
|
+
}
|
|
141
|
+
return shuffled.slice(0, sampleSize);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Count the total number of combinations without generating them
|
|
145
|
+
*
|
|
146
|
+
* Useful for checking if cartesian product is feasible before generating.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* import { cartesianCount } from 'ai-experiments'
|
|
151
|
+
*
|
|
152
|
+
* const count = cartesianCount({
|
|
153
|
+
* model: ['sonnet', 'opus', 'gpt-4o'],
|
|
154
|
+
* temperature: [0.3, 0.5, 0.7, 0.9],
|
|
155
|
+
* maxTokens: [100, 500, 1000, 2000],
|
|
156
|
+
* })
|
|
157
|
+
* // Returns 48 (3 * 4 * 4)
|
|
158
|
+
*
|
|
159
|
+
* if (count > 100) {
|
|
160
|
+
* console.log('Too many combinations, use cartesianSample instead')
|
|
161
|
+
* }
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
export function cartesianCount(params) {
|
|
165
|
+
const keys = Object.keys(params);
|
|
166
|
+
if (keys.length === 0)
|
|
167
|
+
return 0;
|
|
168
|
+
return keys.reduce((total, key) => {
|
|
169
|
+
const arr = params[key];
|
|
170
|
+
return total * (arr?.length ?? 0);
|
|
171
|
+
}, 1);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Generate cartesian product with labels for each dimension
|
|
175
|
+
*
|
|
176
|
+
* Returns combinations with additional metadata about which dimension each value came from.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* import { cartesianWithLabels } from 'ai-experiments'
|
|
181
|
+
*
|
|
182
|
+
* const labeled = cartesianWithLabels({
|
|
183
|
+
* model: ['sonnet', 'opus'],
|
|
184
|
+
* temperature: [0.3, 0.7],
|
|
185
|
+
* })
|
|
186
|
+
* // [
|
|
187
|
+
* // { values: { model: 'sonnet', temperature: 0.3 }, labels: { model: 0, temperature: 0 } },
|
|
188
|
+
* // { values: { model: 'sonnet', temperature: 0.7 }, labels: { model: 0, temperature: 1 } },
|
|
189
|
+
* // { values: { model: 'opus', temperature: 0.3 }, labels: { model: 1, temperature: 0 } },
|
|
190
|
+
* // { values: { model: 'opus', temperature: 0.7 }, labels: { model: 1, temperature: 1 } },
|
|
191
|
+
* // ]
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
export function cartesianWithLabels(params) {
|
|
195
|
+
const keys = Object.keys(params);
|
|
196
|
+
const values = keys.map((k) => params[k]);
|
|
197
|
+
if (keys.length === 0) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
const combinations = cartesianProduct(values);
|
|
201
|
+
return combinations.map((combo) => {
|
|
202
|
+
const valuesObj = {};
|
|
203
|
+
const labelsObj = {};
|
|
204
|
+
keys.forEach((key, i) => {
|
|
205
|
+
const value = combo[i];
|
|
206
|
+
valuesObj[key] = value;
|
|
207
|
+
const arr = params[key];
|
|
208
|
+
labelsObj[key] = arr ? arr.indexOf(value) : -1;
|
|
209
|
+
});
|
|
210
|
+
return {
|
|
211
|
+
values: valuesObj,
|
|
212
|
+
labels: labelsObj,
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=cartesian.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cartesian.js","sourceRoot":"","sources":["../src/cartesian.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClickHouse storage backend for AI experiments.
|
|
3
|
+
*
|
|
4
|
+
* Migrated (per [ADR-0003](../../../docs/adr/0003-storage-strategy-pg-clickhouse-default.md))
|
|
5
|
+
* from the standalone embedded `chdb` adapter to the canonical
|
|
6
|
+
* `ClickHouseProvider` from `ai-database`. Experiment runs are recorded as
|
|
7
|
+
* SVO Actions on the canonical `actions` table:
|
|
8
|
+
*
|
|
9
|
+
* - `verb` — event type (e.g. `variant.complete`)
|
|
10
|
+
* - `subject` — `experimentId`
|
|
11
|
+
* - `object` — `variantId`
|
|
12
|
+
* - `roles` — `{ runId }` (other named roles can be carried here)
|
|
13
|
+
* - `data` — JSON payload (`experimentName`, `variantName`, `dimensions`,
|
|
14
|
+
* `runId`, `success`, `durationMs`, `result`, `metricName`,
|
|
15
|
+
* `metricValue`, `errorMessage`, `errorStack`, `metadata`)
|
|
16
|
+
* - `status` — `'completed'` for successful runs, `'failed'` otherwise
|
|
17
|
+
*
|
|
18
|
+
* Writes go through {@link ClickHouseProvider.recordAction} (and
|
|
19
|
+
* {@link ClickHouseProvider.commitBatch} when bulk-storing). Aggregations
|
|
20
|
+
* use {@link ClickHouseProvider.analyticsQuery} against the `actions` table
|
|
21
|
+
* with `JSONExtract*` against the `data` column. This is the **option (c)
|
|
22
|
+
* hybrid** approach from the migration plan: SVO surface for writes, raw
|
|
23
|
+
* analytical SQL for the experiment-specific aggregations the SVO surface
|
|
24
|
+
* doesn't expose directly (cartesian grids, time-series rollups,
|
|
25
|
+
* best-variant selection by metric).
|
|
26
|
+
*
|
|
27
|
+
* Deployment shift: the previous `chdb` adapter used embedded ClickHouse
|
|
28
|
+
* (file-system path). This adapter is HTTP-based — callers wire up a
|
|
29
|
+
* ClickHouse server (self-hosted or ClickHouse Cloud) via
|
|
30
|
+
* {@link createClickHouseHttpFetcher}. Tests use a fake fetcher.
|
|
31
|
+
*
|
|
32
|
+
* @packageDocumentation
|
|
33
|
+
*/
|
|
34
|
+
import { type ClickHouseHttpFetcher, type ClickHouseProvider } from 'ai-database';
|
|
35
|
+
import type { TrackingBackend, TrackingEvent, ExperimentResult } from './types.js';
|
|
36
|
+
/** Options for {@link ClickHouseExperimentStorage}. */
|
|
37
|
+
export interface ClickHouseExperimentStorageOptions {
|
|
38
|
+
/** HTTP fetcher (typically constructed via `createClickHouseHttpFetcher`). */
|
|
39
|
+
fetcher: ClickHouseHttpFetcher;
|
|
40
|
+
/**
|
|
41
|
+
* ClickHouse database. Must already exist (or call
|
|
42
|
+
* {@link bootstrapExperimentsSchema}).
|
|
43
|
+
*
|
|
44
|
+
* @default 'aidb'
|
|
45
|
+
*/
|
|
46
|
+
database?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Namespace partition for experiment events.
|
|
49
|
+
*
|
|
50
|
+
* @default 'experiments'
|
|
51
|
+
*/
|
|
52
|
+
namespace?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Whether to bootstrap the canonical schema (`things`/`actions`/`verbs`)
|
|
55
|
+
* before the first write.
|
|
56
|
+
*
|
|
57
|
+
* @default false
|
|
58
|
+
*/
|
|
59
|
+
autoBootstrap?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Backwards-compat alias for the prior `ChdbStorageOptions`. The
|
|
63
|
+
* `dataPath` and `autoInit` fields are retained as no-ops to ease the
|
|
64
|
+
* upgrade — they are ignored in favor of HTTP fetcher options.
|
|
65
|
+
*/
|
|
66
|
+
export interface ChdbStorageOptions extends Partial<ClickHouseExperimentStorageOptions> {
|
|
67
|
+
/** @deprecated Embedded chdb is no longer used; supply `fetcher`. */
|
|
68
|
+
dataPath?: string;
|
|
69
|
+
/** @deprecated Replaced by `autoBootstrap`. */
|
|
70
|
+
autoInit?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* ClickHouse-backed experiment storage built on the canonical
|
|
74
|
+
* {@link ClickHouseProvider} adapter. Implements
|
|
75
|
+
* {@link TrackingBackend}.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { configureTracking } from 'ai-experiments'
|
|
80
|
+
* import { createClickHouseExperimentStorage } from 'ai-experiments/storage'
|
|
81
|
+
* import { createClickHouseHttpFetcher } from 'ai-database'
|
|
82
|
+
*
|
|
83
|
+
* const fetcher = createClickHouseHttpFetcher({
|
|
84
|
+
* url: process.env.CLICKHOUSE_URL!,
|
|
85
|
+
* username: process.env.CLICKHOUSE_USER,
|
|
86
|
+
* password: process.env.CLICKHOUSE_PASSWORD,
|
|
87
|
+
* database: 'aidb',
|
|
88
|
+
* })
|
|
89
|
+
* const storage = createClickHouseExperimentStorage({ fetcher })
|
|
90
|
+
*
|
|
91
|
+
* configureTracking({ backend: storage })
|
|
92
|
+
*
|
|
93
|
+
* // Later: analyse results
|
|
94
|
+
* const best = await storage.getBestVariant('my-experiment')
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export declare class ClickHouseExperimentStorage implements TrackingBackend {
|
|
98
|
+
private readonly provider;
|
|
99
|
+
private readonly fetcher;
|
|
100
|
+
private readonly database;
|
|
101
|
+
private readonly namespace;
|
|
102
|
+
private readonly autoBootstrap;
|
|
103
|
+
private bootstrapped;
|
|
104
|
+
private readonly nextEventId;
|
|
105
|
+
constructor(options: ClickHouseExperimentStorageOptions);
|
|
106
|
+
/** Underlying canonical CH provider (escape hatch for advanced callers). */
|
|
107
|
+
getProvider(): ClickHouseProvider;
|
|
108
|
+
private ensureBootstrap;
|
|
109
|
+
track(event: TrackingEvent): Promise<void>;
|
|
110
|
+
flush(): Promise<void>;
|
|
111
|
+
storeResult(result: ExperimentResult): Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* Bulk-store results via {@link ClickHouseProvider.commitBatch}. One
|
|
114
|
+
* HTTP POST per call carries the entire batch as `JSONEachRow`.
|
|
115
|
+
*/
|
|
116
|
+
storeResults(results: ExperimentResult[]): Promise<void>;
|
|
117
|
+
/** Quote a SQL string literal — same shape as the canonical adapter. */
|
|
118
|
+
private quote;
|
|
119
|
+
/**
|
|
120
|
+
* Get all experiments seen in the actions table (variant.complete events).
|
|
121
|
+
*/
|
|
122
|
+
getExperiments(): Promise<Array<{
|
|
123
|
+
experimentId: string;
|
|
124
|
+
experimentName: string;
|
|
125
|
+
variantCount: number;
|
|
126
|
+
runCount: number;
|
|
127
|
+
firstRun: string;
|
|
128
|
+
lastRun: string;
|
|
129
|
+
}>>;
|
|
130
|
+
getVariantStats(experimentId: string): Promise<Array<{
|
|
131
|
+
variantId: string;
|
|
132
|
+
variantName: string;
|
|
133
|
+
runCount: number;
|
|
134
|
+
successCount: number;
|
|
135
|
+
successRate: number;
|
|
136
|
+
avgDuration: number;
|
|
137
|
+
avgMetric: number;
|
|
138
|
+
minMetric: number;
|
|
139
|
+
maxMetric: number;
|
|
140
|
+
}>>;
|
|
141
|
+
getBestVariant(experimentId: string, options?: {
|
|
142
|
+
metric?: 'avgMetric' | 'successRate' | 'avgDuration';
|
|
143
|
+
minimumRuns?: number;
|
|
144
|
+
}): Promise<{
|
|
145
|
+
variantId: string;
|
|
146
|
+
variantName: string;
|
|
147
|
+
metricValue: number;
|
|
148
|
+
runCount: number;
|
|
149
|
+
} | null>;
|
|
150
|
+
getCartesianAnalysis(experimentId: string, dimension: string): Promise<Array<{
|
|
151
|
+
dimensionValue: string;
|
|
152
|
+
runCount: number;
|
|
153
|
+
avgMetric: number;
|
|
154
|
+
successRate: number;
|
|
155
|
+
}>>;
|
|
156
|
+
getCartesianGrid(experimentId: string, dimensions: string[]): Promise<Array<{
|
|
157
|
+
dimensions: Record<string, string>;
|
|
158
|
+
runCount: number;
|
|
159
|
+
avgMetric: number;
|
|
160
|
+
successRate: number;
|
|
161
|
+
}>>;
|
|
162
|
+
getTimeSeries(experimentId: string, options?: {
|
|
163
|
+
interval?: 'hour' | 'day' | 'week';
|
|
164
|
+
variantId?: string;
|
|
165
|
+
}): Promise<Array<{
|
|
166
|
+
period: string;
|
|
167
|
+
runCount: number;
|
|
168
|
+
avgMetric: number;
|
|
169
|
+
successRate: number;
|
|
170
|
+
}>>;
|
|
171
|
+
getEvents(experimentId: string, options?: {
|
|
172
|
+
eventType?: string;
|
|
173
|
+
variantId?: string;
|
|
174
|
+
limit?: number;
|
|
175
|
+
}): Promise<TrackingEvent[]>;
|
|
176
|
+
/**
|
|
177
|
+
* Raw analytical SQL pass-through. Routes to
|
|
178
|
+
* {@link ClickHouseProvider.analyticsQuery}.
|
|
179
|
+
*/
|
|
180
|
+
query(sql: string): Promise<Array<Record<string, unknown>>>;
|
|
181
|
+
/** No-op (kept for backwards compat with the chdb-era API). */
|
|
182
|
+
close(): void;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Bootstrap the canonical CH schema (`things`, `actions`, `verbs`).
|
|
186
|
+
* Convenience wrapper around the canonical
|
|
187
|
+
* {@link bootstrapClickHouseSchema}.
|
|
188
|
+
*/
|
|
189
|
+
export declare function bootstrapExperimentsSchema(fetcher: ClickHouseHttpFetcher, options?: {
|
|
190
|
+
database?: string;
|
|
191
|
+
}): Promise<void>;
|
|
192
|
+
/**
|
|
193
|
+
* Create a ClickHouse-backed experiment storage backend.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```ts
|
|
197
|
+
* import { configureTracking } from 'ai-experiments'
|
|
198
|
+
* import { createClickHouseExperimentStorage } from 'ai-experiments/storage'
|
|
199
|
+
* import { createClickHouseHttpFetcher } from 'ai-database'
|
|
200
|
+
*
|
|
201
|
+
* const fetcher = createClickHouseHttpFetcher({
|
|
202
|
+
* url: process.env.CLICKHOUSE_URL!,
|
|
203
|
+
* username: process.env.CLICKHOUSE_USER,
|
|
204
|
+
* password: process.env.CLICKHOUSE_PASSWORD,
|
|
205
|
+
* database: 'aidb',
|
|
206
|
+
* })
|
|
207
|
+
* const storage = createClickHouseExperimentStorage({ fetcher })
|
|
208
|
+
*
|
|
209
|
+
* configureTracking({ backend: storage })
|
|
210
|
+
*
|
|
211
|
+
* const best = await storage.getBestVariant('my-experiment')
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
export declare function createClickHouseExperimentStorage(options: ClickHouseExperimentStorageOptions): ClickHouseExperimentStorage;
|
|
215
|
+
/**
|
|
216
|
+
* @deprecated Renamed to {@link ClickHouseExperimentStorage}. The class
|
|
217
|
+
* now wraps the canonical `ClickHouseProvider` from `ai-database` instead
|
|
218
|
+
* of embedded chdb. The old `dataPath` constructor option is ignored —
|
|
219
|
+
* supply a `fetcher` instead.
|
|
220
|
+
*/
|
|
221
|
+
export declare const ChdbStorage: typeof ClickHouseExperimentStorage;
|
|
222
|
+
export type ChdbStorage = ClickHouseExperimentStorage;
|
|
223
|
+
/**
|
|
224
|
+
* @deprecated Renamed to {@link createClickHouseExperimentStorage}.
|
|
225
|
+
*/
|
|
226
|
+
export declare function createChdbBackend(options: ClickHouseExperimentStorageOptions): ClickHouseExperimentStorage;
|
|
227
|
+
//# sourceMappingURL=clickhouse-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse-storage.d.ts","sourceRoot":"","sources":["../src/clickhouse-storage.ts"],"names":[],"mappings":"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"}
|