@fallom/trace 0.2.3 → 0.2.5
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/README.md +66 -2
- package/dist/{chunk-W6M2RQ3W.mjs → chunk-KFD5AQ7V.mjs} +59 -2
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +85 -4
- package/dist/index.mjs +28 -4
- package/dist/{models-JKMOBZUO.mjs → models-SEFDGZU2.mjs} +1 -1
- package/package.json +1 -1
- package/dist/chunk-2BP4H4AD.mjs +0 -3012
- package/dist/chunk-6MSTRIK4.mjs +0 -255
- package/dist/chunk-7P6ASYW6.mjs +0 -9
- package/dist/chunk-H2EACSBT.mjs +0 -255
- package/dist/chunk-IGJD7GBO.mjs +0 -248
- package/dist/chunk-K7HYYE4Y.mjs +0 -2930
- package/dist/chunk-KAZ5NEU2.mjs +0 -2237
- package/dist/chunk-KMA4IPED.mjs +0 -252
- package/dist/chunk-VNUUS74T.mjs +0 -242
- package/dist/models-2Y6DRQPS.mjs +0 -9
- package/dist/models-BUHMMTWK.mjs +0 -9
- package/dist/models-JIO5LVMB.mjs +0 -8
- package/dist/prompts-67DJ33I4.mjs +0 -14
- package/dist/prompts-ODF4KO2E.mjs +0 -14
- package/dist/prompts-VAN5E3L4.mjs +0 -14
- package/dist/prompts-XSZHTCX7.mjs +0 -15
- package/dist/prompts-ZSLS4DHO.mjs +0 -14
package/README.md
CHANGED
|
@@ -187,6 +187,59 @@ const model = await models.get("summarizer-config", sessionId, {
|
|
|
187
187
|
});
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
+
### User Targeting (LaunchDarkly-style)
|
|
191
|
+
|
|
192
|
+
Override weighted distribution for specific users or segments. Targeting rules are evaluated client-side for zero latency.
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import { models } from "@fallom/trace";
|
|
196
|
+
|
|
197
|
+
// Target specific users to specific variants
|
|
198
|
+
const model = await models.get("my-config", sessionId, {
|
|
199
|
+
fallback: "gpt-4o-mini",
|
|
200
|
+
customerId: "user-123", // For individual targeting
|
|
201
|
+
context: { // For rule-based targeting
|
|
202
|
+
plan: "enterprise",
|
|
203
|
+
region: "us-west",
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Evaluation order:**
|
|
209
|
+
1. **Individual Targets** - Exact match on `customerId` or any field
|
|
210
|
+
2. **Rules** - Condition-based targeting (all conditions must match)
|
|
211
|
+
3. **Fallback** - Weighted random distribution
|
|
212
|
+
|
|
213
|
+
**Configure targeting in the dashboard:**
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"enabled": true,
|
|
218
|
+
"individualTargets": [
|
|
219
|
+
{ "field": "customerId", "value": "vip-user-123", "variantIndex": 1 }
|
|
220
|
+
],
|
|
221
|
+
"rules": [
|
|
222
|
+
{
|
|
223
|
+
"conditions": [
|
|
224
|
+
{ "field": "plan", "operator": "eq", "value": "enterprise" }
|
|
225
|
+
],
|
|
226
|
+
"variantIndex": 1
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Supported operators:**
|
|
233
|
+
| Operator | Description | Example |
|
|
234
|
+
|----------|-------------|---------|
|
|
235
|
+
| `eq` | Equals | `plan = "enterprise"` |
|
|
236
|
+
| `neq` | Not equals | `plan ≠ "free"` |
|
|
237
|
+
| `in` | In list | `plan in ["enterprise", "business"]` |
|
|
238
|
+
| `nin` | Not in list | `region not in ["cn", "ru"]` |
|
|
239
|
+
| `contains` | Contains substring | `email contains "@acme.com"` |
|
|
240
|
+
| `startsWith` | Starts with | `region starts with "eu-"` |
|
|
241
|
+
| `endsWith` | Ends with | `email ends with ".gov"` |
|
|
242
|
+
|
|
190
243
|
## Prompt Management
|
|
191
244
|
|
|
192
245
|
Manage prompts centrally and A/B test them.
|
|
@@ -295,11 +348,22 @@ Get model assignment for A/B testing.
|
|
|
295
348
|
|
|
296
349
|
```typescript
|
|
297
350
|
const model = await models.get("my-config", sessionId, {
|
|
298
|
-
fallback: "gpt-4o-mini",
|
|
299
|
-
version: 2,
|
|
351
|
+
fallback: "gpt-4o-mini", // used if config not found
|
|
352
|
+
version: 2, // pin to specific config version
|
|
353
|
+
customerId: "user-123", // for individual targeting
|
|
354
|
+
context: { plan: "enterprise" }, // for rule-based targeting
|
|
355
|
+
debug: false, // enable debug logging
|
|
300
356
|
});
|
|
301
357
|
```
|
|
302
358
|
|
|
359
|
+
| Option | Type | Description |
|
|
360
|
+
|--------|------|-------------|
|
|
361
|
+
| `fallback` | `string` | Model to return if config not found |
|
|
362
|
+
| `version` | `number` | Pin to specific config version |
|
|
363
|
+
| `customerId` | `string` | User ID for individual targeting |
|
|
364
|
+
| `context` | `Record<string, string>` | Context for rule-based targeting |
|
|
365
|
+
| `debug` | `boolean` | Enable debug logging |
|
|
366
|
+
|
|
303
367
|
### `fallom.prompts.get(promptKey, options?)`
|
|
304
368
|
|
|
305
369
|
Get a managed prompt.
|
|
@@ -24,6 +24,57 @@ function log(msg) {
|
|
|
24
24
|
console.log(`[Fallom] ${msg}`);
|
|
25
25
|
}
|
|
26
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
|
+
}
|
|
27
78
|
function init(options = {}) {
|
|
28
79
|
apiKey = options.apiKey || process.env.FALLOM_API_KEY || null;
|
|
29
80
|
baseUrl = options.baseUrl || process.env.FALLOM_CONFIGS_URL || process.env.FALLOM_BASE_URL || "https://configs.fallom.com";
|
|
@@ -112,7 +163,7 @@ async function fetchSpecificVersion(configKey, version, timeout = SYNC_TIMEOUT)
|
|
|
112
163
|
return null;
|
|
113
164
|
}
|
|
114
165
|
async function get(configKey, sessionId, options = {}) {
|
|
115
|
-
const { version, fallback, debug = false } = options;
|
|
166
|
+
const { version, fallback, customerId, context, debug = false } = options;
|
|
116
167
|
debugMode = debug;
|
|
117
168
|
ensureInit();
|
|
118
169
|
log(
|
|
@@ -181,6 +232,12 @@ async function get(configKey, sessionId, options = {}) {
|
|
|
181
232
|
variants
|
|
182
233
|
)}`
|
|
183
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
|
+
}
|
|
184
241
|
const hashBytes = createHash("md5").update(sessionId).digest();
|
|
185
242
|
const hashVal = hashBytes.readUInt32BE(0) % 1e6;
|
|
186
243
|
log(`Session hash: ${hashVal} (out of 1,000,000)`);
|
|
@@ -197,7 +254,7 @@ async function get(configKey, sessionId, options = {}) {
|
|
|
197
254
|
break;
|
|
198
255
|
}
|
|
199
256
|
}
|
|
200
|
-
log(`\u2705 Assigned model: ${assignedModel}`);
|
|
257
|
+
log(`\u2705 Assigned model via weighted random: ${assignedModel}`);
|
|
201
258
|
return returnModel(configKey, sessionId, assignedModel, configVersion);
|
|
202
259
|
} catch (e) {
|
|
203
260
|
if (e instanceof Error && e.message.includes("not found")) {
|
package/dist/index.d.mts
CHANGED
|
@@ -261,6 +261,8 @@ declare function init$2(options?: {
|
|
|
261
261
|
* @param options - Optional settings
|
|
262
262
|
* @param options.version - Pin to specific version (1, 2, etc). undefined = latest
|
|
263
263
|
* @param options.fallback - Model to return if config not found or Fallom is down
|
|
264
|
+
* @param options.customerId - User ID for individual targeting (e.g., "user-123")
|
|
265
|
+
* @param options.context - Additional context for rule-based targeting (e.g., { plan: "enterprise" })
|
|
264
266
|
* @param options.debug - Enable debug logging
|
|
265
267
|
* @returns Model string (e.g., "claude-opus", "gpt-4o")
|
|
266
268
|
* @throws Error if config not found AND no fallback provided
|
|
@@ -268,6 +270,8 @@ declare function init$2(options?: {
|
|
|
268
270
|
declare function get$1(configKey: string, sessionId: string, options?: {
|
|
269
271
|
version?: number;
|
|
270
272
|
fallback?: string;
|
|
273
|
+
customerId?: string;
|
|
274
|
+
context?: Record<string, string>;
|
|
271
275
|
debug?: boolean;
|
|
272
276
|
}): Promise<string>;
|
|
273
277
|
|
package/dist/index.d.ts
CHANGED
|
@@ -261,6 +261,8 @@ declare function init$2(options?: {
|
|
|
261
261
|
* @param options - Optional settings
|
|
262
262
|
* @param options.version - Pin to specific version (1, 2, etc). undefined = latest
|
|
263
263
|
* @param options.fallback - Model to return if config not found or Fallom is down
|
|
264
|
+
* @param options.customerId - User ID for individual targeting (e.g., "user-123")
|
|
265
|
+
* @param options.context - Additional context for rule-based targeting (e.g., { plan: "enterprise" })
|
|
264
266
|
* @param options.debug - Enable debug logging
|
|
265
267
|
* @returns Model string (e.g., "claude-opus", "gpt-4o")
|
|
266
268
|
* @throws Error if config not found AND no fallback provided
|
|
@@ -268,6 +270,8 @@ declare function init$2(options?: {
|
|
|
268
270
|
declare function get$1(configKey: string, sessionId: string, options?: {
|
|
269
271
|
version?: number;
|
|
270
272
|
fallback?: string;
|
|
273
|
+
customerId?: string;
|
|
274
|
+
context?: Record<string, string>;
|
|
271
275
|
debug?: boolean;
|
|
272
276
|
}): Promise<string>;
|
|
273
277
|
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,57 @@ function log3(msg) {
|
|
|
31
31
|
console.log(`[Fallom] ${msg}`);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
function evaluateTargeting(targeting, customerId, context) {
|
|
35
|
+
if (!targeting || targeting.enabled === false) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const evalContext = {
|
|
39
|
+
...context || {},
|
|
40
|
+
...customerId ? { customerId } : {}
|
|
41
|
+
};
|
|
42
|
+
log3(`Evaluating targeting with context: ${JSON.stringify(evalContext)}`);
|
|
43
|
+
if (targeting.individualTargets) {
|
|
44
|
+
for (const target of targeting.individualTargets) {
|
|
45
|
+
const fieldValue = evalContext[target.field];
|
|
46
|
+
if (fieldValue === target.value) {
|
|
47
|
+
log3(`Individual target matched: ${target.field}=${target.value} -> variant ${target.variantIndex}`);
|
|
48
|
+
return target.variantIndex;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (targeting.rules) {
|
|
53
|
+
for (const rule of targeting.rules) {
|
|
54
|
+
const allConditionsMatch = rule.conditions.every((condition) => {
|
|
55
|
+
const fieldValue = evalContext[condition.field];
|
|
56
|
+
if (fieldValue === void 0) return false;
|
|
57
|
+
switch (condition.operator) {
|
|
58
|
+
case "eq":
|
|
59
|
+
return fieldValue === condition.value;
|
|
60
|
+
case "neq":
|
|
61
|
+
return fieldValue !== condition.value;
|
|
62
|
+
case "in":
|
|
63
|
+
return Array.isArray(condition.value) && condition.value.includes(fieldValue);
|
|
64
|
+
case "nin":
|
|
65
|
+
return Array.isArray(condition.value) && !condition.value.includes(fieldValue);
|
|
66
|
+
case "contains":
|
|
67
|
+
return typeof condition.value === "string" && fieldValue.includes(condition.value);
|
|
68
|
+
case "startsWith":
|
|
69
|
+
return typeof condition.value === "string" && fieldValue.startsWith(condition.value);
|
|
70
|
+
case "endsWith":
|
|
71
|
+
return typeof condition.value === "string" && fieldValue.endsWith(condition.value);
|
|
72
|
+
default:
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
if (allConditionsMatch) {
|
|
77
|
+
log3(`Rule matched: ${JSON.stringify(rule.conditions)} -> variant ${rule.variantIndex}`);
|
|
78
|
+
return rule.variantIndex;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
log3("No targeting rules matched, falling back to weighted random");
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
34
85
|
function init2(options = {}) {
|
|
35
86
|
apiKey2 = options.apiKey || process.env.FALLOM_API_KEY || null;
|
|
36
87
|
baseUrl2 = options.baseUrl || process.env.FALLOM_CONFIGS_URL || process.env.FALLOM_BASE_URL || "https://configs.fallom.com";
|
|
@@ -119,7 +170,7 @@ async function fetchSpecificVersion(configKey, version, timeout = SYNC_TIMEOUT)
|
|
|
119
170
|
return null;
|
|
120
171
|
}
|
|
121
172
|
async function get(configKey, sessionId, options = {}) {
|
|
122
|
-
const { version, fallback, debug = false } = options;
|
|
173
|
+
const { version, fallback, customerId, context, debug = false } = options;
|
|
123
174
|
debugMode2 = debug;
|
|
124
175
|
ensureInit();
|
|
125
176
|
log3(
|
|
@@ -188,6 +239,12 @@ async function get(configKey, sessionId, options = {}) {
|
|
|
188
239
|
variants
|
|
189
240
|
)}`
|
|
190
241
|
);
|
|
242
|
+
const targetedVariantIndex = evaluateTargeting(config.targeting, customerId, context);
|
|
243
|
+
if (targetedVariantIndex !== null && variants[targetedVariantIndex]) {
|
|
244
|
+
const assignedModel2 = variants[targetedVariantIndex].model;
|
|
245
|
+
log3(`\u2705 Assigned model via targeting: ${assignedModel2}`);
|
|
246
|
+
return returnModel(configKey, sessionId, assignedModel2, configVersion);
|
|
247
|
+
}
|
|
191
248
|
const hashBytes = (0, import_crypto.createHash)("md5").update(sessionId).digest();
|
|
192
249
|
const hashVal = hashBytes.readUInt32BE(0) % 1e6;
|
|
193
250
|
log3(`Session hash: ${hashVal} (out of 1,000,000)`);
|
|
@@ -204,7 +261,7 @@ async function get(configKey, sessionId, options = {}) {
|
|
|
204
261
|
break;
|
|
205
262
|
}
|
|
206
263
|
}
|
|
207
|
-
log3(`\u2705 Assigned model: ${assignedModel}`);
|
|
264
|
+
log3(`\u2705 Assigned model via weighted random: ${assignedModel}`);
|
|
208
265
|
return returnModel(configKey, sessionId, assignedModel, configVersion);
|
|
209
266
|
} catch (e) {
|
|
210
267
|
if (e instanceof Error && e.message.includes("not found")) {
|
|
@@ -1444,10 +1501,16 @@ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1444
1501
|
let firstTokenTime = null;
|
|
1445
1502
|
const modelId = params?.model?.modelId || String(params?.model || "unknown");
|
|
1446
1503
|
if (result?.usage) {
|
|
1447
|
-
|
|
1504
|
+
Promise.all([
|
|
1505
|
+
result.usage.catch(() => null),
|
|
1506
|
+
result.text?.catch(() => null),
|
|
1507
|
+
result.finishReason?.catch(() => null)
|
|
1508
|
+
]).then(async ([rawUsage, responseText, finishReason]) => {
|
|
1448
1509
|
const endTime = Date.now();
|
|
1449
1510
|
if (debug || isDebugMode()) {
|
|
1450
1511
|
console.log("\n\u{1F50D} [Fallom Debug] streamText raw usage:", JSON.stringify(rawUsage, null, 2));
|
|
1512
|
+
console.log("\u{1F50D} [Fallom Debug] streamText response text:", responseText?.slice(0, 100));
|
|
1513
|
+
console.log("\u{1F50D} [Fallom Debug] streamText finish reason:", finishReason);
|
|
1451
1514
|
}
|
|
1452
1515
|
let providerMetadata = result?.experimental_providerMetadata;
|
|
1453
1516
|
if (providerMetadata && typeof providerMetadata.then === "function") {
|
|
@@ -1469,6 +1532,12 @@ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1469
1532
|
system: params?.system,
|
|
1470
1533
|
model: modelId
|
|
1471
1534
|
});
|
|
1535
|
+
if (responseText || finishReason) {
|
|
1536
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
1537
|
+
text: responseText,
|
|
1538
|
+
finishReason
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1472
1541
|
}
|
|
1473
1542
|
if (rawUsage) {
|
|
1474
1543
|
attributes["fallom.raw.usage"] = JSON.stringify(rawUsage);
|
|
@@ -1665,10 +1734,16 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1665
1734
|
const parentSpanId = traceCtx?.parentSpanId;
|
|
1666
1735
|
const modelId = params?.model?.modelId || String(params?.model || "unknown");
|
|
1667
1736
|
if (result?.usage) {
|
|
1668
|
-
|
|
1737
|
+
Promise.all([
|
|
1738
|
+
result.usage.catch(() => null),
|
|
1739
|
+
result.object?.catch(() => null),
|
|
1740
|
+
result.finishReason?.catch(() => null)
|
|
1741
|
+
]).then(async ([rawUsage, responseObject, finishReason]) => {
|
|
1669
1742
|
const endTime = Date.now();
|
|
1670
1743
|
if (debug || isDebugMode()) {
|
|
1671
1744
|
console.log("\n\u{1F50D} [Fallom Debug] streamObject raw usage:", JSON.stringify(rawUsage, null, 2));
|
|
1745
|
+
console.log("\u{1F50D} [Fallom Debug] streamObject response object:", JSON.stringify(responseObject)?.slice(0, 100));
|
|
1746
|
+
console.log("\u{1F50D} [Fallom Debug] streamObject finish reason:", finishReason);
|
|
1672
1747
|
}
|
|
1673
1748
|
let providerMetadata = result?.experimental_providerMetadata;
|
|
1674
1749
|
if (providerMetadata && typeof providerMetadata.then === "function") {
|
|
@@ -1691,6 +1766,12 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1691
1766
|
model: modelId,
|
|
1692
1767
|
schema: params?.schema ? "provided" : void 0
|
|
1693
1768
|
});
|
|
1769
|
+
if (responseObject || finishReason) {
|
|
1770
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
1771
|
+
object: responseObject,
|
|
1772
|
+
finishReason
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1694
1775
|
}
|
|
1695
1776
|
if (rawUsage) {
|
|
1696
1777
|
attributes["fallom.raw.usage"] = JSON.stringify(rawUsage);
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
__export,
|
|
3
3
|
init,
|
|
4
4
|
models_exports
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-KFD5AQ7V.mjs";
|
|
6
6
|
|
|
7
7
|
// src/trace.ts
|
|
8
8
|
var trace_exports = {};
|
|
@@ -1166,10 +1166,16 @@ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1166
1166
|
let firstTokenTime = null;
|
|
1167
1167
|
const modelId = params?.model?.modelId || String(params?.model || "unknown");
|
|
1168
1168
|
if (result?.usage) {
|
|
1169
|
-
|
|
1169
|
+
Promise.all([
|
|
1170
|
+
result.usage.catch(() => null),
|
|
1171
|
+
result.text?.catch(() => null),
|
|
1172
|
+
result.finishReason?.catch(() => null)
|
|
1173
|
+
]).then(async ([rawUsage, responseText, finishReason]) => {
|
|
1170
1174
|
const endTime = Date.now();
|
|
1171
1175
|
if (debug || isDebugMode()) {
|
|
1172
1176
|
console.log("\n\u{1F50D} [Fallom Debug] streamText raw usage:", JSON.stringify(rawUsage, null, 2));
|
|
1177
|
+
console.log("\u{1F50D} [Fallom Debug] streamText response text:", responseText?.slice(0, 100));
|
|
1178
|
+
console.log("\u{1F50D} [Fallom Debug] streamText finish reason:", finishReason);
|
|
1173
1179
|
}
|
|
1174
1180
|
let providerMetadata = result?.experimental_providerMetadata;
|
|
1175
1181
|
if (providerMetadata && typeof providerMetadata.then === "function") {
|
|
@@ -1191,6 +1197,12 @@ function createStreamTextWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1191
1197
|
system: params?.system,
|
|
1192
1198
|
model: modelId
|
|
1193
1199
|
});
|
|
1200
|
+
if (responseText || finishReason) {
|
|
1201
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
1202
|
+
text: responseText,
|
|
1203
|
+
finishReason
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1194
1206
|
}
|
|
1195
1207
|
if (rawUsage) {
|
|
1196
1208
|
attributes["fallom.raw.usage"] = JSON.stringify(rawUsage);
|
|
@@ -1387,10 +1399,16 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1387
1399
|
const parentSpanId = traceCtx?.parentSpanId;
|
|
1388
1400
|
const modelId = params?.model?.modelId || String(params?.model || "unknown");
|
|
1389
1401
|
if (result?.usage) {
|
|
1390
|
-
|
|
1402
|
+
Promise.all([
|
|
1403
|
+
result.usage.catch(() => null),
|
|
1404
|
+
result.object?.catch(() => null),
|
|
1405
|
+
result.finishReason?.catch(() => null)
|
|
1406
|
+
]).then(async ([rawUsage, responseObject, finishReason]) => {
|
|
1391
1407
|
const endTime = Date.now();
|
|
1392
1408
|
if (debug || isDebugMode()) {
|
|
1393
1409
|
console.log("\n\u{1F50D} [Fallom Debug] streamObject raw usage:", JSON.stringify(rawUsage, null, 2));
|
|
1410
|
+
console.log("\u{1F50D} [Fallom Debug] streamObject response object:", JSON.stringify(responseObject)?.slice(0, 100));
|
|
1411
|
+
console.log("\u{1F50D} [Fallom Debug] streamObject finish reason:", finishReason);
|
|
1394
1412
|
}
|
|
1395
1413
|
let providerMetadata = result?.experimental_providerMetadata;
|
|
1396
1414
|
if (providerMetadata && typeof providerMetadata.then === "function") {
|
|
@@ -1413,6 +1431,12 @@ function createStreamObjectWrapper(aiModule, sessionCtx, debug = false) {
|
|
|
1413
1431
|
model: modelId,
|
|
1414
1432
|
schema: params?.schema ? "provided" : void 0
|
|
1415
1433
|
});
|
|
1434
|
+
if (responseObject || finishReason) {
|
|
1435
|
+
attributes["fallom.raw.response"] = JSON.stringify({
|
|
1436
|
+
object: responseObject,
|
|
1437
|
+
finishReason
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1416
1440
|
}
|
|
1417
1441
|
if (rawUsage) {
|
|
1418
1442
|
attributes["fallom.raw.usage"] = JSON.stringify(rawUsage);
|
|
@@ -1578,7 +1602,7 @@ var FallomSession = class {
|
|
|
1578
1602
|
configKey = this.ctx.configKey;
|
|
1579
1603
|
opts = configKeyOrOptions || {};
|
|
1580
1604
|
}
|
|
1581
|
-
const { get: get2 } = await import("./models-
|
|
1605
|
+
const { get: get2 } = await import("./models-SEFDGZU2.mjs");
|
|
1582
1606
|
return get2(configKey, this.ctx.sessionId, opts);
|
|
1583
1607
|
}
|
|
1584
1608
|
/**
|