@fallom/trace 0.1.12 → 0.2.1
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 +215 -178
- package/dist/chunk-2BP4H4AD.mjs +3012 -0
- package/dist/chunk-7P6ASYW6.mjs +9 -0
- package/dist/chunk-K7HYYE4Y.mjs +2930 -0
- package/dist/chunk-KAZ5NEU2.mjs +2237 -0
- package/dist/chunk-KMA4IPED.mjs +252 -0
- package/dist/chunk-W6M2RQ3W.mjs +251 -0
- package/dist/index.d.mts +208 -256
- package/dist/index.d.ts +208 -256
- package/dist/index.js +794 -789
- package/dist/index.mjs +594 -590
- package/dist/models-2Y6DRQPS.mjs +9 -0
- package/dist/models-BUHMMTWK.mjs +9 -0
- package/dist/models-JIO5LVMB.mjs +8 -0
- package/dist/models-JKMOBZUO.mjs +8 -0
- package/dist/prompts-XSZHTCX7.mjs +15 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @fallom/trace
|
|
2
2
|
|
|
3
|
-
Model A/B testing, prompt management, and tracing for LLM applications. Zero latency, production-ready.
|
|
3
|
+
Model A/B testing, prompt management, and tracing for LLM applications. Zero latency, production-ready, concurrent-safe.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -12,127 +12,57 @@ npm install @fallom/trace
|
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
14
|
import fallom from "@fallom/trace";
|
|
15
|
-
import
|
|
15
|
+
import * as ai from "ai";
|
|
16
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
16
17
|
|
|
17
|
-
// Initialize Fallom
|
|
18
|
+
// Initialize Fallom once
|
|
18
19
|
await fallom.init({ apiKey: "your-api-key" });
|
|
19
20
|
|
|
20
|
-
//
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// All LLM calls are now automatically traced!
|
|
27
|
-
const response = await openai.chat.completions.create({
|
|
28
|
-
model: "gpt-4o",
|
|
29
|
-
messages: [{ role: "user", content: "Hello!" }],
|
|
21
|
+
// Create a session for this request/conversation
|
|
22
|
+
const session = fallom.session({
|
|
23
|
+
configKey: "my-agent",
|
|
24
|
+
sessionId: "session-123",
|
|
25
|
+
customerId: "user-456", // optional
|
|
30
26
|
});
|
|
31
|
-
```
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
// Wrap AI SDK - all calls are now traced!
|
|
29
|
+
const { generateText } = session.wrapAISDK(ai);
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
import { models } from "@fallom/trace";
|
|
39
|
-
|
|
40
|
-
// Get assigned model for this session
|
|
41
|
-
const model = await models.get("summarizer-config", sessionId);
|
|
42
|
-
// Returns: "gpt-4o" or "claude-3-5-sonnet" based on your config weights
|
|
43
|
-
|
|
44
|
-
const response = await openai.chat.completions.create({ model, ... });
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Fallback for Resilience
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
const model = await models.get("my-config", sessionId, {
|
|
51
|
-
fallback: "gpt-4o-mini", // Used if config not found or Fallom unreachable
|
|
31
|
+
const response = await generateText({
|
|
32
|
+
model: createOpenAI()("gpt-4o"),
|
|
33
|
+
prompt: "Hello!",
|
|
52
34
|
});
|
|
53
35
|
```
|
|
54
36
|
|
|
55
|
-
##
|
|
56
|
-
|
|
57
|
-
Manage prompts centrally and A/B test them with zero latency.
|
|
37
|
+
## Tracing
|
|
58
38
|
|
|
59
|
-
###
|
|
39
|
+
### Vercel AI SDK
|
|
60
40
|
|
|
61
41
|
```typescript
|
|
62
|
-
import
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
variables: { userName: "John", company: "Acme" },
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Use the prompt with any LLM
|
|
70
|
-
const response = await openai.chat.completions.create({
|
|
71
|
-
model: "gpt-4o",
|
|
72
|
-
messages: [
|
|
73
|
-
{ role: "system", content: prompt.system },
|
|
74
|
-
{ role: "user", content: prompt.user },
|
|
75
|
-
],
|
|
76
|
-
});
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
The `prompt` object contains:
|
|
80
|
-
- `key`: The prompt key
|
|
81
|
-
- `version`: The prompt version
|
|
82
|
-
- `system`: The system prompt (with variables replaced)
|
|
83
|
-
- `user`: The user template (with variables replaced)
|
|
84
|
-
|
|
85
|
-
### Prompt A/B Testing
|
|
86
|
-
|
|
87
|
-
Run experiments on different prompt versions:
|
|
42
|
+
import * as ai from "ai";
|
|
43
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
44
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
45
|
+
import fallom from "@fallom/trace";
|
|
88
46
|
|
|
89
|
-
|
|
90
|
-
import { prompts } from "@fallom/trace";
|
|
47
|
+
await fallom.init({ apiKey: "your-api-key" });
|
|
91
48
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
49
|
+
const session = fallom.session({
|
|
50
|
+
configKey: "my-agent",
|
|
51
|
+
sessionId: "session-123",
|
|
95
52
|
});
|
|
96
53
|
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
```
|
|
54
|
+
// Option 1: Wrap the SDK (our style)
|
|
55
|
+
const { generateText, streamText } = session.wrapAISDK(ai);
|
|
100
56
|
|
|
101
|
-
|
|
57
|
+
await generateText({ model: createOpenAI()("gpt-4o"), prompt: "Hello!" });
|
|
58
|
+
await streamText({ model: createAnthropic()("claude-3-5-sonnet"), prompt: "Hi!" });
|
|
102
59
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// Pin to specific version
|
|
108
|
-
const prompt = await prompts.get("my-prompt", { version: 2 });
|
|
60
|
+
// Option 2: Wrap the model directly (PostHog style)
|
|
61
|
+
const model = session.traceModel(createOpenAI()("gpt-4o"));
|
|
62
|
+
await ai.generateText({ model, prompt: "Hello!" });
|
|
109
63
|
```
|
|
110
64
|
|
|
111
|
-
###
|
|
112
|
-
|
|
113
|
-
When you call `prompts.get()` or `prompts.getAB()`, the next LLM call is automatically tagged with the prompt information. This allows you to see which prompts are used in your traces without any extra code.
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
// Get prompt - sets up auto-tagging for next LLM call
|
|
117
|
-
const prompt = await prompts.get("onboarding", {
|
|
118
|
-
variables: { userName: "John" },
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// This call is automatically tagged with promptKey, promptVersion, etc.
|
|
122
|
-
const response = await openai.chat.completions.create({
|
|
123
|
-
model: "gpt-4o",
|
|
124
|
-
messages: [
|
|
125
|
-
{ role: "system", content: prompt.system },
|
|
126
|
-
{ role: "user", content: prompt.user },
|
|
127
|
-
],
|
|
128
|
-
});
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## Tracing
|
|
132
|
-
|
|
133
|
-
Wrap your LLM client once, all calls are automatically traced.
|
|
134
|
-
|
|
135
|
-
### OpenAI (+ OpenRouter, Azure, LiteLLM, etc.)
|
|
65
|
+
### OpenAI SDK
|
|
136
66
|
|
|
137
67
|
```typescript
|
|
138
68
|
import OpenAI from "openai";
|
|
@@ -140,24 +70,26 @@ import fallom from "@fallom/trace";
|
|
|
140
70
|
|
|
141
71
|
await fallom.init({ apiKey: "your-api-key" });
|
|
142
72
|
|
|
143
|
-
|
|
144
|
-
|
|
73
|
+
const session = fallom.session({
|
|
74
|
+
configKey: "my-agent",
|
|
75
|
+
sessionId: "session-123",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Works with any OpenAI-compatible API (OpenRouter, Azure, LiteLLM, etc.)
|
|
79
|
+
const openai = session.wrapOpenAI(
|
|
145
80
|
new OpenAI({
|
|
146
|
-
baseURL: "https://openrouter.ai/api/v1", //
|
|
81
|
+
baseURL: "https://openrouter.ai/api/v1", // optional
|
|
147
82
|
apiKey: "your-provider-key",
|
|
148
83
|
})
|
|
149
84
|
);
|
|
150
85
|
|
|
151
|
-
fallom.trace.setSession("my-config", sessionId);
|
|
152
|
-
|
|
153
|
-
// Automatically traced!
|
|
154
86
|
const response = await openai.chat.completions.create({
|
|
155
87
|
model: "gpt-4o",
|
|
156
88
|
messages: [{ role: "user", content: "Hello!" }],
|
|
157
89
|
});
|
|
158
90
|
```
|
|
159
91
|
|
|
160
|
-
### Anthropic
|
|
92
|
+
### Anthropic SDK
|
|
161
93
|
|
|
162
94
|
```typescript
|
|
163
95
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -165,13 +97,16 @@ import fallom from "@fallom/trace";
|
|
|
165
97
|
|
|
166
98
|
await fallom.init({ apiKey: "your-api-key" });
|
|
167
99
|
|
|
168
|
-
const
|
|
100
|
+
const session = fallom.session({
|
|
101
|
+
configKey: "my-agent",
|
|
102
|
+
sessionId: "session-123",
|
|
103
|
+
});
|
|
169
104
|
|
|
170
|
-
|
|
105
|
+
const anthropic = session.wrapAnthropic(new Anthropic());
|
|
171
106
|
|
|
172
|
-
// Automatically traced!
|
|
173
107
|
const response = await anthropic.messages.create({
|
|
174
108
|
model: "claude-3-5-sonnet-20241022",
|
|
109
|
+
max_tokens: 1024,
|
|
175
110
|
messages: [{ role: "user", content: "Hello!" }],
|
|
176
111
|
});
|
|
177
112
|
```
|
|
@@ -184,42 +119,117 @@ import fallom from "@fallom/trace";
|
|
|
184
119
|
|
|
185
120
|
await fallom.init({ apiKey: "your-api-key" });
|
|
186
121
|
|
|
122
|
+
const session = fallom.session({
|
|
123
|
+
configKey: "my-agent",
|
|
124
|
+
sessionId: "session-123",
|
|
125
|
+
});
|
|
126
|
+
|
|
187
127
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
188
|
-
const model =
|
|
128
|
+
const model = session.wrapGoogleAI(
|
|
189
129
|
genAI.getGenerativeModel({ model: "gemini-pro" })
|
|
190
130
|
);
|
|
191
131
|
|
|
192
|
-
fallom.trace.setSession("my-config", sessionId);
|
|
193
|
-
|
|
194
|
-
// Automatically traced!
|
|
195
132
|
const response = await model.generateContent("Hello!");
|
|
196
133
|
```
|
|
197
134
|
|
|
198
|
-
##
|
|
135
|
+
## Concurrent Sessions
|
|
199
136
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
|
|
137
|
+
Sessions are isolated - safe for concurrent requests:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
async function handleRequest(userId: string, conversationId: string) {
|
|
141
|
+
const session = fallom.session({
|
|
142
|
+
configKey: "my-agent",
|
|
143
|
+
sessionId: conversationId,
|
|
144
|
+
customerId: userId,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const { generateText } = session.wrapAISDK(ai);
|
|
148
|
+
|
|
149
|
+
// This session's context is isolated
|
|
150
|
+
return await generateText({ model: openai("gpt-4o"), prompt: "..." });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Safe to run concurrently!
|
|
154
|
+
await Promise.all([
|
|
155
|
+
handleRequest("user-1", "conv-1"),
|
|
156
|
+
handleRequest("user-2", "conv-2"),
|
|
157
|
+
handleRequest("user-3", "conv-3"),
|
|
158
|
+
]);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Model A/B Testing
|
|
162
|
+
|
|
163
|
+
Run A/B tests on models with zero latency. Same session always gets same model (sticky assignment).
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const session = fallom.session({
|
|
167
|
+
configKey: "summarizer",
|
|
168
|
+
sessionId: "session-123",
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Get assigned model for this session
|
|
172
|
+
const model = await session.getModel({ fallback: "gpt-4o-mini" });
|
|
173
|
+
// Returns: "gpt-4o" or "claude-3-5-sonnet" based on your config weights
|
|
174
|
+
|
|
175
|
+
const { generateText } = session.wrapAISDK(ai);
|
|
176
|
+
await generateText({ model: createOpenAI()(model), prompt: "..." });
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Standalone Model Assignment
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { models } from "@fallom/trace";
|
|
208
183
|
|
|
209
|
-
|
|
184
|
+
// Get model without creating a session
|
|
185
|
+
const model = await models.get("summarizer-config", sessionId, {
|
|
186
|
+
fallback: "gpt-4o-mini",
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Prompt Management
|
|
210
191
|
|
|
211
|
-
|
|
192
|
+
Manage prompts centrally and A/B test them.
|
|
212
193
|
|
|
213
194
|
```typescript
|
|
214
|
-
import {
|
|
195
|
+
import { prompts } from "@fallom/trace";
|
|
215
196
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
197
|
+
// Get a managed prompt (with template variables)
|
|
198
|
+
const prompt = await prompts.get("onboarding", {
|
|
199
|
+
variables: { userName: "John", company: "Acme" },
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Use the prompt
|
|
203
|
+
const response = await openai.chat.completions.create({
|
|
204
|
+
model: "gpt-4o",
|
|
205
|
+
messages: [
|
|
206
|
+
{ role: "system", content: prompt.system },
|
|
207
|
+
{ role: "user", content: prompt.user },
|
|
208
|
+
],
|
|
220
209
|
});
|
|
221
210
|
```
|
|
222
211
|
|
|
212
|
+
### Prompt A/B Testing
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// Get prompt from A/B test (sticky assignment)
|
|
216
|
+
const prompt = await prompts.getAB("onboarding-test", sessionId, {
|
|
217
|
+
variables: { userName: "John" },
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## What Gets Traced
|
|
222
|
+
|
|
223
|
+
For each LLM call, Fallom automatically captures:
|
|
224
|
+
- ✅ Model name
|
|
225
|
+
- ✅ Duration (latency)
|
|
226
|
+
- ✅ Token counts (prompt, completion, total)
|
|
227
|
+
- ✅ Input/output content (can be disabled)
|
|
228
|
+
- ✅ Errors
|
|
229
|
+
- ✅ Config key + session ID
|
|
230
|
+
- ✅ Customer ID
|
|
231
|
+
- ✅ Time to first token (streaming)
|
|
232
|
+
|
|
223
233
|
## Configuration
|
|
224
234
|
|
|
225
235
|
### Environment Variables
|
|
@@ -244,79 +254,106 @@ fallom.init({ captureContent: false });
|
|
|
244
254
|
|
|
245
255
|
### `fallom.init(options?)`
|
|
246
256
|
|
|
247
|
-
Initialize the SDK.
|
|
248
|
-
|
|
249
|
-
### `fallom.trace.wrapOpenAI(client)`
|
|
250
|
-
|
|
251
|
-
Wrap OpenAI client for automatic tracing. Works with any OpenAI-compatible API.
|
|
257
|
+
Initialize the SDK. Call once at app startup.
|
|
252
258
|
|
|
253
|
-
|
|
259
|
+
```typescript
|
|
260
|
+
await fallom.init({
|
|
261
|
+
apiKey: "your-api-key", // or FALLOM_API_KEY env var
|
|
262
|
+
captureContent: true, // capture prompts/completions
|
|
263
|
+
debug: false, // enable debug logging
|
|
264
|
+
});
|
|
265
|
+
```
|
|
254
266
|
|
|
255
|
-
|
|
267
|
+
### `fallom.session(options)`
|
|
256
268
|
|
|
257
|
-
|
|
269
|
+
Create a session-scoped tracer.
|
|
258
270
|
|
|
259
|
-
|
|
271
|
+
```typescript
|
|
272
|
+
const session = fallom.session({
|
|
273
|
+
configKey: "my-agent", // required: your config name
|
|
274
|
+
sessionId: "session-123", // required: conversation/request ID
|
|
275
|
+
customerId: "user-456", // optional: user identifier
|
|
276
|
+
});
|
|
277
|
+
```
|
|
260
278
|
|
|
261
|
-
|
|
279
|
+
Returns a `FallomSession` with these methods:
|
|
262
280
|
|
|
263
|
-
|
|
281
|
+
| Method | Description |
|
|
282
|
+
|--------|-------------|
|
|
283
|
+
| `wrapAISDK(ai)` | Wrap Vercel AI SDK |
|
|
284
|
+
| `wrapOpenAI(client)` | Wrap OpenAI client |
|
|
285
|
+
| `wrapAnthropic(client)` | Wrap Anthropic client |
|
|
286
|
+
| `wrapGoogleAI(model)` | Wrap Google AI model |
|
|
287
|
+
| `wrapMastraAgent(agent)` | Wrap Mastra agent |
|
|
288
|
+
| `traceModel(model)` | Wrap a model directly (PostHog style) |
|
|
289
|
+
| `getModel(options?)` | Get A/B tested model assignment |
|
|
290
|
+
| `getContext()` | Get the session context |
|
|
264
291
|
|
|
265
292
|
### `fallom.models.get(configKey, sessionId, options?)`
|
|
266
293
|
|
|
267
|
-
Get model assignment for A/B testing.
|
|
294
|
+
Get model assignment for A/B testing.
|
|
268
295
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
### `fallom.prompts.getAB(abTestKey, sessionId, options?)`
|
|
296
|
+
```typescript
|
|
297
|
+
const model = await models.get("my-config", sessionId, {
|
|
298
|
+
fallback: "gpt-4o-mini", // used if config not found
|
|
299
|
+
version: 2, // pin to specific config version
|
|
300
|
+
});
|
|
301
|
+
```
|
|
277
302
|
|
|
278
|
-
|
|
279
|
-
- `abTestKey`: Your A/B test key from the dashboard
|
|
280
|
-
- `sessionId`: Session ID for sticky assignment
|
|
281
|
-
- `options.variables`: Template variables
|
|
303
|
+
### `fallom.prompts.get(promptKey, options?)`
|
|
282
304
|
|
|
283
|
-
|
|
305
|
+
Get a managed prompt.
|
|
284
306
|
|
|
285
|
-
|
|
307
|
+
```typescript
|
|
308
|
+
const prompt = await prompts.get("my-prompt", {
|
|
309
|
+
variables: { name: "John" },
|
|
310
|
+
version: 2, // optional: pin version
|
|
311
|
+
});
|
|
312
|
+
// Returns: { key, version, system, user }
|
|
313
|
+
```
|
|
286
314
|
|
|
287
|
-
|
|
315
|
+
### `fallom.prompts.getAB(abTestKey, sessionId, options?)`
|
|
288
316
|
|
|
289
|
-
|
|
317
|
+
Get a prompt from an A/B test.
|
|
290
318
|
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
319
|
+
```typescript
|
|
320
|
+
const prompt = await prompts.getAB("my-test", sessionId, {
|
|
321
|
+
variables: { name: "John" },
|
|
322
|
+
});
|
|
323
|
+
// Returns: { key, version, system, user, abTestKey, variantIndex }
|
|
295
324
|
```
|
|
296
325
|
|
|
297
|
-
##
|
|
326
|
+
## Mastra Integration
|
|
298
327
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
cd sdk/typescript-sdk
|
|
328
|
+
```typescript
|
|
329
|
+
import { FallomExporter } from "@fallom/trace";
|
|
330
|
+
import { Mastra } from "@mastra/core/mastra";
|
|
303
331
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
332
|
+
const session = fallom.session({
|
|
333
|
+
configKey: "my-agent",
|
|
334
|
+
sessionId: "session-123",
|
|
335
|
+
});
|
|
308
336
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
337
|
+
const mastra = new Mastra({
|
|
338
|
+
agents: { myAgent },
|
|
339
|
+
telemetry: {
|
|
340
|
+
serviceName: "my-agent",
|
|
341
|
+
enabled: true,
|
|
342
|
+
export: {
|
|
343
|
+
type: "custom",
|
|
344
|
+
exporter: new FallomExporter({
|
|
345
|
+
session: session.getContext(),
|
|
346
|
+
}),
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
});
|
|
313
350
|
```
|
|
314
351
|
|
|
315
352
|
## Requirements
|
|
316
353
|
|
|
317
354
|
- Node.js >= 18.0.0
|
|
318
355
|
|
|
319
|
-
Works with ESM and CommonJS.
|
|
356
|
+
Works with ESM and CommonJS. Compatible with tsx, ts-node, Bun, and compiled JavaScript.
|
|
320
357
|
|
|
321
358
|
## License
|
|
322
359
|
|