@fallom/trace 0.2.18 → 0.2.21

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/dist/index.mjs CHANGED
@@ -7,6 +7,8 @@ import {
7
7
  DEFAULT_JUDGE_MODEL,
8
8
  EvaluationDataset,
9
9
  METRIC_PROMPTS,
10
+ buildGEvalPrompt,
11
+ calculateAggregateScores,
10
12
  compareModels,
11
13
  createCustomModel,
12
14
  createModelFromCallable,
@@ -14,12 +16,14 @@ import {
14
16
  customMetric,
15
17
  datasetFromFallom,
16
18
  datasetFromTraces,
19
+ detectRegression,
17
20
  evaluate,
18
21
  getMetricName,
19
22
  init as init2,
20
23
  isCustomMetric,
24
+ runGEval,
21
25
  uploadResultsPublic
22
- } from "./chunk-3HBKT4HK.mjs";
26
+ } from "./chunk-GZ6TE7G4.mjs";
23
27
  import {
24
28
  __export
25
29
  } from "./chunk-7P6ASYW6.mjs";
@@ -41,7 +45,7 @@ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
41
45
  // node_modules/@opentelemetry/resources/build/esm/Resource.js
42
46
  import { diag } from "@opentelemetry/api";
43
47
 
44
- // node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions/build/esm/resource/SemanticResourceAttributes.js
48
+ // node_modules/@opentelemetry/semantic-conventions/build/esm/resource/SemanticResourceAttributes.js
45
49
  var SemanticResourceAttributes = {
46
50
  /**
47
51
  * Name of the cloud provider.
@@ -2738,6 +2742,8 @@ __export(evals_exports, {
2738
2742
  DEFAULT_JUDGE_MODEL: () => DEFAULT_JUDGE_MODEL,
2739
2743
  EvaluationDataset: () => EvaluationDataset,
2740
2744
  METRIC_PROMPTS: () => METRIC_PROMPTS,
2745
+ buildGEvalPrompt: () => buildGEvalPrompt,
2746
+ calculateAggregateScores: () => calculateAggregateScores,
2741
2747
  compareModels: () => compareModels,
2742
2748
  createCustomModel: () => createCustomModel,
2743
2749
  createModelFromCallable: () => createModelFromCallable,
@@ -2745,10 +2751,12 @@ __export(evals_exports, {
2745
2751
  customMetric: () => customMetric,
2746
2752
  datasetFromFallom: () => datasetFromFallom,
2747
2753
  datasetFromTraces: () => datasetFromTraces,
2754
+ detectRegression: () => detectRegression,
2748
2755
  evaluate: () => evaluate,
2749
2756
  getMetricName: () => getMetricName,
2750
2757
  init: () => init2,
2751
2758
  isCustomMetric: () => isCustomMetric,
2759
+ runGEval: () => runGEval,
2752
2760
  uploadResults: () => uploadResultsPublic
2753
2761
  });
2754
2762
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fallom/trace",
3
- "version": "0.2.18",
3
+ "version": "0.2.21",
4
4
  "description": "Model A/B testing and tracing for LLM applications. Zero latency, production-ready.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -1,308 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // src/models.ts
8
- var models_exports = {};
9
- __export(models_exports, {
10
- get: () => get,
11
- init: () => init
12
- });
13
- import { createHash } from "crypto";
14
- var apiKey = null;
15
- var baseUrl = "https://configs.fallom.com";
16
- var initialized = false;
17
- var syncInterval = null;
18
- var debugMode = false;
19
- var configCache = /* @__PURE__ */ new Map();
20
- var SYNC_TIMEOUT = 2e3;
21
- var RECORD_TIMEOUT = 1e3;
22
- function log(msg) {
23
- if (debugMode) {
24
- console.log(`[Fallom] ${msg}`);
25
- }
26
- }
27
- function evaluateTargeting(targeting, customerId, context) {
28
- if (!targeting || targeting.enabled === false) {
29
- return null;
30
- }
31
- const evalContext = {
32
- ...context || {},
33
- ...customerId ? { customerId } : {}
34
- };
35
- log(`Evaluating targeting with context: ${JSON.stringify(evalContext)}`);
36
- if (targeting.individualTargets) {
37
- for (const target of targeting.individualTargets) {
38
- const fieldValue = evalContext[target.field];
39
- if (fieldValue === target.value) {
40
- log(`Individual target matched: ${target.field}=${target.value} -> variant ${target.variantIndex}`);
41
- return target.variantIndex;
42
- }
43
- }
44
- }
45
- if (targeting.rules) {
46
- for (const rule of targeting.rules) {
47
- const allConditionsMatch = rule.conditions.every((condition) => {
48
- const fieldValue = evalContext[condition.field];
49
- if (fieldValue === void 0) return false;
50
- switch (condition.operator) {
51
- case "eq":
52
- return fieldValue === condition.value;
53
- case "neq":
54
- return fieldValue !== condition.value;
55
- case "in":
56
- return Array.isArray(condition.value) && condition.value.includes(fieldValue);
57
- case "nin":
58
- return Array.isArray(condition.value) && !condition.value.includes(fieldValue);
59
- case "contains":
60
- return typeof condition.value === "string" && fieldValue.includes(condition.value);
61
- case "startsWith":
62
- return typeof condition.value === "string" && fieldValue.startsWith(condition.value);
63
- case "endsWith":
64
- return typeof condition.value === "string" && fieldValue.endsWith(condition.value);
65
- default:
66
- return false;
67
- }
68
- });
69
- if (allConditionsMatch) {
70
- log(`Rule matched: ${JSON.stringify(rule.conditions)} -> variant ${rule.variantIndex}`);
71
- return rule.variantIndex;
72
- }
73
- }
74
- }
75
- log("No targeting rules matched, falling back to weighted random");
76
- return null;
77
- }
78
- function init(options = {}) {
79
- apiKey = options.apiKey || process.env.FALLOM_API_KEY || null;
80
- baseUrl = options.baseUrl || process.env.FALLOM_CONFIGS_URL || process.env.FALLOM_BASE_URL || "https://configs.fallom.com";
81
- initialized = true;
82
- if (!apiKey) {
83
- return;
84
- }
85
- fetchConfigs().catch(() => {
86
- });
87
- if (!syncInterval) {
88
- syncInterval = setInterval(() => {
89
- fetchConfigs().catch(() => {
90
- });
91
- }, 3e4);
92
- syncInterval.unref();
93
- }
94
- }
95
- function ensureInit() {
96
- if (!initialized) {
97
- try {
98
- init();
99
- } catch {
100
- }
101
- }
102
- }
103
- async function fetchConfigs(timeout = SYNC_TIMEOUT) {
104
- if (!apiKey) {
105
- log("_fetchConfigs: No API key, skipping");
106
- return;
107
- }
108
- try {
109
- log(`Fetching configs from ${baseUrl}/configs`);
110
- const controller = new AbortController();
111
- const timeoutId = setTimeout(() => controller.abort(), timeout);
112
- const resp = await fetch(`${baseUrl}/configs`, {
113
- headers: { Authorization: `Bearer ${apiKey}` },
114
- signal: controller.signal
115
- });
116
- clearTimeout(timeoutId);
117
- log(`Response status: ${resp.status}`);
118
- if (resp.ok) {
119
- const data = await resp.json();
120
- const configs = data.configs || [];
121
- log(`Got ${configs.length} configs: ${configs.map((c) => c.key)}`);
122
- for (const c of configs) {
123
- const key = c.key;
124
- const version = c.version || 1;
125
- log(`Config '${key}' v${version}: ${JSON.stringify(c.variants)}`);
126
- if (!configCache.has(key)) {
127
- configCache.set(key, { versions: /* @__PURE__ */ new Map(), latest: null });
128
- }
129
- const cached = configCache.get(key);
130
- cached.versions.set(version, c);
131
- cached.latest = version;
132
- }
133
- } else {
134
- log(`Fetch failed: ${resp.statusText}`);
135
- }
136
- } catch (e) {
137
- log(`Fetch exception: ${e}`);
138
- }
139
- }
140
- async function fetchSpecificVersion(configKey, version, timeout = SYNC_TIMEOUT) {
141
- if (!apiKey) return null;
142
- try {
143
- const controller = new AbortController();
144
- const timeoutId = setTimeout(() => controller.abort(), timeout);
145
- const resp = await fetch(
146
- `${baseUrl}/configs/${configKey}/version/${version}`,
147
- {
148
- headers: { Authorization: `Bearer ${apiKey}` },
149
- signal: controller.signal
150
- }
151
- );
152
- clearTimeout(timeoutId);
153
- if (resp.ok) {
154
- const config = await resp.json();
155
- if (!configCache.has(configKey)) {
156
- configCache.set(configKey, { versions: /* @__PURE__ */ new Map(), latest: null });
157
- }
158
- configCache.get(configKey).versions.set(version, config);
159
- return config;
160
- }
161
- } catch {
162
- }
163
- return null;
164
- }
165
- async function get(configKey, sessionId, options = {}) {
166
- const { version, fallback, customerId, context, debug = false } = options;
167
- debugMode = debug;
168
- ensureInit();
169
- log(
170
- `get() called: configKey=${configKey}, sessionId=${sessionId}, fallback=${fallback}`
171
- );
172
- try {
173
- let configData = configCache.get(configKey);
174
- log(
175
- `Cache lookup for '${configKey}': ${configData ? "found" : "not found"}`
176
- );
177
- if (!configData) {
178
- log("Not in cache, fetching...");
179
- await fetchConfigs(SYNC_TIMEOUT);
180
- configData = configCache.get(configKey);
181
- log(
182
- `After fetch, cache lookup: ${configData ? "found" : "still not found"}`
183
- );
184
- }
185
- if (!configData) {
186
- log(`Config not found, using fallback: ${fallback}`);
187
- if (fallback) {
188
- console.warn(
189
- `[Fallom WARNING] Config '${configKey}' not found, using fallback model: ${fallback}`
190
- );
191
- return returnModel(configKey, sessionId, fallback, 0);
192
- }
193
- throw new Error(
194
- `Config '${configKey}' not found. Check that it exists in your Fallom dashboard.`
195
- );
196
- }
197
- let config;
198
- let targetVersion;
199
- if (version !== void 0) {
200
- config = configData.versions.get(version);
201
- if (!config) {
202
- config = await fetchSpecificVersion(configKey, version, SYNC_TIMEOUT) || void 0;
203
- }
204
- if (!config) {
205
- if (fallback) {
206
- console.warn(
207
- `[Fallom WARNING] Config '${configKey}' version ${version} not found, using fallback: ${fallback}`
208
- );
209
- return returnModel(configKey, sessionId, fallback, 0);
210
- }
211
- throw new Error(`Config '${configKey}' version ${version} not found.`);
212
- }
213
- targetVersion = version;
214
- } else {
215
- targetVersion = configData.latest;
216
- config = configData.versions.get(targetVersion);
217
- if (!config) {
218
- if (fallback) {
219
- console.warn(
220
- `[Fallom WARNING] Config '${configKey}' has no cached version, using fallback: ${fallback}`
221
- );
222
- return returnModel(configKey, sessionId, fallback, 0);
223
- }
224
- throw new Error(`Config '${configKey}' has no cached version.`);
225
- }
226
- }
227
- const variantsRaw = config.variants;
228
- const configVersion = config.version || targetVersion;
229
- const variants = Array.isArray(variantsRaw) ? variantsRaw : Object.values(variantsRaw);
230
- log(
231
- `Config found! Version: ${configVersion}, Variants: ${JSON.stringify(
232
- variants
233
- )}`
234
- );
235
- const targetedVariantIndex = evaluateTargeting(config.targeting, customerId, context);
236
- if (targetedVariantIndex !== null && variants[targetedVariantIndex]) {
237
- const assignedModel2 = variants[targetedVariantIndex].model;
238
- log(`\u2705 Assigned model via targeting: ${assignedModel2}`);
239
- return returnModel(configKey, sessionId, assignedModel2, configVersion);
240
- }
241
- const hashBytes = createHash("md5").update(sessionId).digest();
242
- const hashVal = hashBytes.readUInt32BE(0) % 1e6;
243
- log(`Session hash: ${hashVal} (out of 1,000,000)`);
244
- let cumulative = 0;
245
- let assignedModel = variants[variants.length - 1].model;
246
- for (const v of variants) {
247
- const oldCumulative = cumulative;
248
- cumulative += v.weight * 1e4;
249
- log(
250
- `Variant ${v.model}: weight=${v.weight}%, range=${oldCumulative}-${cumulative}, hash=${hashVal}, match=${hashVal < cumulative}`
251
- );
252
- if (hashVal < cumulative) {
253
- assignedModel = v.model;
254
- break;
255
- }
256
- }
257
- log(`\u2705 Assigned model via weighted random: ${assignedModel}`);
258
- return returnModel(configKey, sessionId, assignedModel, configVersion);
259
- } catch (e) {
260
- if (e instanceof Error && e.message.includes("not found")) {
261
- throw e;
262
- }
263
- if (fallback) {
264
- console.warn(
265
- `[Fallom WARNING] Error getting model for '${configKey}': ${e}. Using fallback: ${fallback}`
266
- );
267
- return returnModel(configKey, sessionId, fallback, 0);
268
- }
269
- throw e;
270
- }
271
- }
272
- function returnModel(configKey, sessionId, model, version) {
273
- if (version > 0) {
274
- recordSession(configKey, version, sessionId, model).catch(() => {
275
- });
276
- }
277
- return model;
278
- }
279
- async function recordSession(configKey, version, sessionId, model) {
280
- if (!apiKey) return;
281
- try {
282
- const controller = new AbortController();
283
- const timeoutId = setTimeout(() => controller.abort(), RECORD_TIMEOUT);
284
- await fetch(`${baseUrl}/sessions`, {
285
- method: "POST",
286
- headers: {
287
- Authorization: `Bearer ${apiKey}`,
288
- "Content-Type": "application/json"
289
- },
290
- body: JSON.stringify({
291
- config_key: configKey,
292
- config_version: version,
293
- session_id: sessionId,
294
- assigned_model: model
295
- }),
296
- signal: controller.signal
297
- });
298
- clearTimeout(timeoutId);
299
- } catch {
300
- }
301
- }
302
-
303
- export {
304
- __export,
305
- init,
306
- get,
307
- models_exports
308
- };
@@ -1,8 +0,0 @@
1
- import {
2
- get,
3
- init
4
- } from "./chunk-KFD5AQ7V.mjs";
5
- export {
6
- get,
7
- init
8
- };