@fallom/trace 0.1.1 → 0.1.4
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 +194 -162
- package/dist/chunk-IGJD7GBO.mjs +248 -0
- package/dist/chunk-VNUUS74T.mjs +242 -0
- package/dist/index.d.mts +207 -12
- package/dist/index.d.ts +207 -12
- package/dist/index.js +619 -97
- package/dist/index.mjs +327 -59
- package/dist/prompts-67DJ33I4.mjs +14 -0
- package/dist/prompts-ODF4KO2E.mjs +14 -0
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,167 +1,223 @@
|
|
|
1
1
|
# @fallom/trace
|
|
2
2
|
|
|
3
|
-
Model A/B testing 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.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @fallom/trace
|
|
9
|
-
|
|
10
|
-
# With auto-instrumentation for your LLM provider:
|
|
11
|
-
npm install @fallom/trace @traceloop/node-server-sdk
|
|
12
9
|
```
|
|
13
10
|
|
|
14
11
|
## Quick Start
|
|
15
12
|
|
|
16
13
|
```typescript
|
|
17
|
-
|
|
18
|
-
import
|
|
14
|
+
import fallom from "@fallom/trace";
|
|
15
|
+
import OpenAI from "openai";
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
// Initialize Fallom
|
|
18
|
+
await fallom.init({ apiKey: "your-api-key" });
|
|
21
19
|
|
|
22
|
-
//
|
|
23
|
-
const
|
|
20
|
+
// Wrap your LLM client for automatic tracing
|
|
21
|
+
const openai = fallom.trace.wrapOpenAI(new OpenAI());
|
|
24
22
|
|
|
25
|
-
// Set
|
|
26
|
-
fallom.trace.setSession(
|
|
23
|
+
// Set session context
|
|
24
|
+
fallom.trace.setSession("my-agent", sessionId);
|
|
27
25
|
|
|
28
26
|
// All LLM calls are now automatically traced!
|
|
29
|
-
const openai = new OpenAI();
|
|
30
27
|
const response = await openai.chat.completions.create({
|
|
31
|
-
model:
|
|
32
|
-
messages: [{ role:
|
|
28
|
+
model: "gpt-4o",
|
|
29
|
+
messages: [{ role: "user", content: "Hello!" }],
|
|
33
30
|
});
|
|
34
31
|
```
|
|
35
32
|
|
|
36
|
-
> ⚠️ **Import Order Matters!** Auto-instrumentation hooks into libraries when they're imported. You must call `fallom.init()` BEFORE importing `openai`, `@anthropic-ai/sdk`, etc. Use dynamic imports (`await import('openai')`) to ensure correct order.
|
|
37
|
-
|
|
38
33
|
## Model A/B Testing
|
|
39
34
|
|
|
40
35
|
Run A/B tests on models with zero latency. Same session always gets same model (sticky assignment).
|
|
41
36
|
|
|
42
37
|
```typescript
|
|
43
|
-
import { models } from
|
|
38
|
+
import { models } from "@fallom/trace";
|
|
44
39
|
|
|
45
40
|
// Get assigned model for this session
|
|
46
|
-
const model = await models.get(
|
|
41
|
+
const model = await models.get("summarizer-config", sessionId);
|
|
47
42
|
// Returns: "gpt-4o" or "claude-3-5-sonnet" based on your config weights
|
|
48
43
|
|
|
49
|
-
const
|
|
50
|
-
await agent.run(message);
|
|
44
|
+
const response = await openai.chat.completions.create({ model, ... });
|
|
51
45
|
```
|
|
52
46
|
|
|
53
|
-
###
|
|
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
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Prompt Management
|
|
56
|
+
|
|
57
|
+
Manage prompts centrally and A/B test them with zero latency.
|
|
58
|
+
|
|
59
|
+
### Basic Prompt Retrieval
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { prompts } from "@fallom/trace";
|
|
63
|
+
|
|
64
|
+
// Get a managed prompt (with template variables)
|
|
65
|
+
const prompt = await prompts.get("onboarding", {
|
|
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:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { prompts } from "@fallom/trace";
|
|
91
|
+
|
|
92
|
+
// Get prompt from A/B test (sticky assignment based on sessionId)
|
|
93
|
+
const prompt = await prompts.getAB("onboarding-test", sessionId, {
|
|
94
|
+
variables: { userName: "John" },
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// prompt.abTestKey and prompt.variantIndex are set
|
|
98
|
+
// for analytics in your dashboard
|
|
99
|
+
```
|
|
54
100
|
|
|
55
|
-
|
|
101
|
+
### Version Pinning
|
|
56
102
|
|
|
57
103
|
```typescript
|
|
58
104
|
// Use latest version (default)
|
|
59
|
-
const
|
|
105
|
+
const prompt = await prompts.get("my-prompt");
|
|
60
106
|
|
|
61
107
|
// Pin to specific version
|
|
62
|
-
const
|
|
108
|
+
const prompt = await prompts.get("my-prompt", { version: 2 });
|
|
63
109
|
```
|
|
64
110
|
|
|
65
|
-
###
|
|
111
|
+
### Automatic Trace Tagging
|
|
66
112
|
|
|
67
|
-
|
|
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.
|
|
68
114
|
|
|
69
115
|
```typescript
|
|
70
|
-
|
|
71
|
-
|
|
116
|
+
// Get prompt - sets up auto-tagging for next LLM call
|
|
117
|
+
const prompt = await prompts.get("onboarding", {
|
|
118
|
+
variables: { userName: "John" },
|
|
72
119
|
});
|
|
73
|
-
```
|
|
74
120
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
+
```
|
|
80
130
|
|
|
81
131
|
## Tracing
|
|
82
132
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
>
|
|
87
|
-
> ```typescript
|
|
88
|
-
> import OpenAI from 'openai';
|
|
89
|
-
>
|
|
90
|
-
> // OpenRouter, LiteLLM, vLLM, etc.
|
|
91
|
-
> const client = new OpenAI({
|
|
92
|
-
> baseURL: 'https://openrouter.ai/api/v1', // or your provider's URL
|
|
93
|
-
> apiKey: 'your-provider-key',
|
|
94
|
-
> });
|
|
95
|
-
>
|
|
96
|
-
> // Now this call will be auto-traced!
|
|
97
|
-
> const response = await client.chat.completions.create({
|
|
98
|
-
> model: 'gpt-4o',
|
|
99
|
-
> messages: [...],
|
|
100
|
-
> });
|
|
101
|
-
> ```
|
|
102
|
-
|
|
103
|
-
### Automatic Tracing
|
|
133
|
+
Wrap your LLM client once, all calls are automatically traced.
|
|
134
|
+
|
|
135
|
+
### OpenAI (+ OpenRouter, Azure, LiteLLM, etc.)
|
|
104
136
|
|
|
105
137
|
```typescript
|
|
106
|
-
|
|
107
|
-
import fallom from
|
|
108
|
-
fallom.init();
|
|
138
|
+
import OpenAI from "openai";
|
|
139
|
+
import fallom from "@fallom/trace";
|
|
109
140
|
|
|
110
|
-
|
|
111
|
-
const { default: OpenAI } = await import('openai');
|
|
112
|
-
const openai = new OpenAI();
|
|
141
|
+
await fallom.init({ apiKey: "your-api-key" });
|
|
113
142
|
|
|
114
|
-
//
|
|
115
|
-
fallom.trace.
|
|
143
|
+
// Works with any OpenAI-compatible API
|
|
144
|
+
const openai = fallom.trace.wrapOpenAI(
|
|
145
|
+
new OpenAI({
|
|
146
|
+
baseURL: "https://openrouter.ai/api/v1", // or Azure, LiteLLM, etc.
|
|
147
|
+
apiKey: "your-provider-key",
|
|
148
|
+
})
|
|
149
|
+
);
|
|
116
150
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
//
|
|
120
|
-
// - Your config_key and session_id
|
|
151
|
+
fallom.trace.setSession("my-config", sessionId);
|
|
152
|
+
|
|
153
|
+
// Automatically traced!
|
|
121
154
|
const response = await openai.chat.completions.create({
|
|
122
|
-
model:
|
|
123
|
-
messages: [
|
|
155
|
+
model: "gpt-4o",
|
|
156
|
+
messages: [{ role: "user", content: "Hello!" }],
|
|
124
157
|
});
|
|
125
158
|
```
|
|
126
159
|
|
|
127
|
-
|
|
128
|
-
> ```bash
|
|
129
|
-
> npm install @traceloop/node-server-sdk
|
|
130
|
-
> ```
|
|
160
|
+
### Anthropic (Claude)
|
|
131
161
|
|
|
132
|
-
|
|
162
|
+
```typescript
|
|
163
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
164
|
+
import fallom from "@fallom/trace";
|
|
133
165
|
|
|
134
|
-
|
|
166
|
+
await fallom.init({ apiKey: "your-api-key" });
|
|
135
167
|
|
|
136
|
-
|
|
137
|
-
import { trace } from '@fallom/trace';
|
|
168
|
+
const anthropic = fallom.trace.wrapAnthropic(new Anthropic());
|
|
138
169
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
170
|
+
fallom.trace.setSession("my-config", sessionId);
|
|
171
|
+
|
|
172
|
+
// Automatically traced!
|
|
173
|
+
const response = await anthropic.messages.create({
|
|
174
|
+
model: "claude-3-5-sonnet-20241022",
|
|
175
|
+
messages: [{ role: "user", content: "Hello!" }],
|
|
143
176
|
});
|
|
144
177
|
```
|
|
145
178
|
|
|
146
|
-
###
|
|
179
|
+
### Google AI (Gemini)
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
183
|
+
import fallom from "@fallom/trace";
|
|
184
|
+
|
|
185
|
+
await fallom.init({ apiKey: "your-api-key" });
|
|
186
|
+
|
|
187
|
+
const genAI = new GoogleGenerativeAI(apiKey);
|
|
188
|
+
const model = fallom.trace.wrapGoogleAI(
|
|
189
|
+
genAI.getGenerativeModel({ model: "gemini-pro" })
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
fallom.trace.setSession("my-config", sessionId);
|
|
193
|
+
|
|
194
|
+
// Automatically traced!
|
|
195
|
+
const response = await model.generateContent("Hello!");
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## What Gets Traced
|
|
199
|
+
|
|
200
|
+
For each LLM call, Fallom automatically captures:
|
|
201
|
+
- ✅ Model name
|
|
202
|
+
- ✅ Duration (latency)
|
|
203
|
+
- ✅ Token counts (prompt, completion, total)
|
|
204
|
+
- ✅ Input/output content (can be disabled)
|
|
205
|
+
- ✅ Errors
|
|
206
|
+
- ✅ Config key + session ID (for A/B analysis)
|
|
207
|
+
- ✅ Prompt key + version (when using prompt management)
|
|
147
208
|
|
|
148
|
-
|
|
209
|
+
## Custom Metrics
|
|
210
|
+
|
|
211
|
+
Record business metrics for your A/B tests:
|
|
149
212
|
|
|
150
213
|
```typescript
|
|
151
|
-
import { trace } from
|
|
214
|
+
import { trace } from "@fallom/trace";
|
|
152
215
|
|
|
153
|
-
// Record custom metrics for this session
|
|
154
216
|
trace.span({
|
|
155
217
|
outlier_score: 0.8,
|
|
156
218
|
user_satisfaction: 4,
|
|
157
219
|
conversion: true,
|
|
158
220
|
});
|
|
159
|
-
|
|
160
|
-
// Or explicitly specify session (for batch jobs)
|
|
161
|
-
trace.span(
|
|
162
|
-
{ outlier_score: 0.8 },
|
|
163
|
-
{ configKey: 'my-agent', sessionId: 'user123-convo456' }
|
|
164
|
-
);
|
|
165
221
|
```
|
|
166
222
|
|
|
167
223
|
## Configuration
|
|
@@ -170,120 +226,96 @@ trace.span(
|
|
|
170
226
|
|
|
171
227
|
```bash
|
|
172
228
|
FALLOM_API_KEY=your-api-key
|
|
173
|
-
FALLOM_BASE_URL=https://spans.fallom.com
|
|
229
|
+
FALLOM_BASE_URL=https://spans.fallom.com
|
|
174
230
|
FALLOM_CAPTURE_CONTENT=true # set to "false" for privacy mode
|
|
175
231
|
```
|
|
176
232
|
|
|
177
|
-
### Initialization Options
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
fallom.init({
|
|
181
|
-
apiKey: 'your-api-key', // Or use FALLOM_API_KEY env var
|
|
182
|
-
baseUrl: 'https://spans.fallom.com', // Or use FALLOM_BASE_URL env var
|
|
183
|
-
captureContent: true, // Set false for privacy mode
|
|
184
|
-
});
|
|
185
|
-
```
|
|
186
|
-
|
|
187
233
|
### Privacy Mode
|
|
188
234
|
|
|
189
|
-
|
|
235
|
+
Disable prompt/completion capture:
|
|
190
236
|
|
|
191
237
|
```typescript
|
|
192
|
-
// Via parameter
|
|
193
238
|
fallom.init({ captureContent: false });
|
|
194
|
-
|
|
195
|
-
// Or via environment variable
|
|
196
|
-
// FALLOM_CAPTURE_CONTENT=false
|
|
197
239
|
```
|
|
198
240
|
|
|
199
|
-
In privacy mode, Fallom still tracks:
|
|
200
|
-
- ✅ Model used
|
|
201
|
-
- ✅ Token counts
|
|
202
|
-
- ✅ Latency
|
|
203
|
-
- ✅ Session/config context
|
|
204
|
-
- ❌ Prompt content (not captured)
|
|
205
|
-
- ❌ Completion content (not captured)
|
|
206
|
-
|
|
207
241
|
## API Reference
|
|
208
242
|
|
|
209
243
|
### `fallom.init(options?)`
|
|
210
244
|
|
|
211
|
-
Initialize the SDK.
|
|
245
|
+
Initialize the SDK.
|
|
212
246
|
|
|
213
|
-
|
|
214
|
-
|--------|------|---------|-------------|
|
|
215
|
-
| `apiKey` | `string` | `FALLOM_API_KEY` env | Your Fallom API key |
|
|
216
|
-
| `baseUrl` | `string` | `https://spans.fallom.com` | API base URL |
|
|
217
|
-
| `captureContent` | `boolean` | `true` | Capture prompt/completion text |
|
|
247
|
+
### `fallom.trace.wrapOpenAI(client)`
|
|
218
248
|
|
|
219
|
-
|
|
249
|
+
Wrap OpenAI client for automatic tracing. Works with any OpenAI-compatible API.
|
|
220
250
|
|
|
221
|
-
|
|
251
|
+
### `fallom.trace.wrapAnthropic(client)`
|
|
222
252
|
|
|
223
|
-
|
|
224
|
-
|-----------|------|-------------|
|
|
225
|
-
| `configKey` | `string` | Your config name from the dashboard |
|
|
226
|
-
| `sessionId` | `string` | Unique session/conversation ID (sticky assignment) |
|
|
227
|
-
| `options.version` | `number` | Pin to specific version (default: latest) |
|
|
228
|
-
| `options.fallback` | `string` | Model to return if anything fails |
|
|
229
|
-
| `options.debug` | `boolean` | Enable debug logging |
|
|
253
|
+
Wrap Anthropic client for automatic tracing.
|
|
230
254
|
|
|
231
|
-
|
|
255
|
+
### `fallom.trace.wrapGoogleAI(model)`
|
|
256
|
+
|
|
257
|
+
Wrap Google AI model for automatic tracing.
|
|
232
258
|
|
|
233
259
|
### `fallom.trace.setSession(configKey, sessionId)`
|
|
234
260
|
|
|
235
|
-
Set
|
|
261
|
+
Set session context for tracing.
|
|
236
262
|
|
|
237
|
-
### `fallom.
|
|
263
|
+
### `fallom.models.get(configKey, sessionId, options?)`
|
|
238
264
|
|
|
239
|
-
|
|
265
|
+
Get model assignment for A/B testing. Returns `Promise<string>`.
|
|
240
266
|
|
|
241
|
-
### `fallom.
|
|
267
|
+
### `fallom.prompts.get(promptKey, options?)`
|
|
242
268
|
|
|
243
|
-
|
|
269
|
+
Get a managed prompt. Returns `Promise<PromptResult>`.
|
|
270
|
+
- `promptKey`: Your prompt key from the dashboard
|
|
271
|
+
- `options.variables`: Template variables (e.g., `{ userName: "John" }`)
|
|
272
|
+
- `options.version`: Pin to specific version (default: latest)
|
|
244
273
|
|
|
245
|
-
### `fallom.
|
|
274
|
+
### `fallom.prompts.getAB(abTestKey, sessionId, options?)`
|
|
246
275
|
|
|
247
|
-
|
|
276
|
+
Get a prompt from an A/B test. Returns `Promise<PromptResult>`.
|
|
277
|
+
- `abTestKey`: Your A/B test key from the dashboard
|
|
278
|
+
- `sessionId`: Session ID for sticky assignment
|
|
279
|
+
- `options.variables`: Template variables
|
|
280
|
+
|
|
281
|
+
### `fallom.trace.span(data)`
|
|
248
282
|
|
|
249
|
-
|
|
250
|
-
|-----------|------|-------------|
|
|
251
|
-
| `data` | `Record<string, unknown>` | Metrics to record |
|
|
252
|
-
| `options.configKey` | `string` | Optional if `setSession()` was called |
|
|
253
|
-
| `options.sessionId` | `string` | Optional if `setSession()` was called |
|
|
283
|
+
Record custom business metrics.
|
|
254
284
|
|
|
255
|
-
|
|
285
|
+
## Testing
|
|
256
286
|
|
|
257
|
-
|
|
287
|
+
Run the test suite:
|
|
258
288
|
|
|
259
|
-
|
|
289
|
+
```bash
|
|
290
|
+
cd sdk/typescript-sdk
|
|
291
|
+
npm install
|
|
292
|
+
npm test
|
|
293
|
+
```
|
|
260
294
|
|
|
261
|
-
|
|
262
|
-
- OpenAI (+ OpenAI-compatible APIs: OpenRouter, LiteLLM, vLLM, Ollama, etc.)
|
|
263
|
-
- Anthropic
|
|
264
|
-
- Cohere
|
|
265
|
-
- AWS Bedrock
|
|
266
|
-
- Google Generative AI
|
|
267
|
-
- Azure OpenAI
|
|
268
|
-
- LangChain
|
|
269
|
-
- And more via Traceloop
|
|
295
|
+
## Deploying
|
|
270
296
|
|
|
271
|
-
|
|
297
|
+
To publish a new version to npm:
|
|
272
298
|
|
|
273
|
-
|
|
299
|
+
```bash
|
|
300
|
+
cd sdk/typescript-sdk
|
|
274
301
|
|
|
275
|
-
|
|
302
|
+
# Update version in package.json
|
|
303
|
+
# Then:
|
|
304
|
+
npm run build
|
|
305
|
+
npm publish --access public
|
|
276
306
|
|
|
277
|
-
|
|
278
|
-
|
|
307
|
+
# Or use convenience scripts:
|
|
308
|
+
npm run publish:patch # 0.1.0 -> 0.1.1
|
|
309
|
+
npm run publish:minor # 0.1.0 -> 0.2.0
|
|
310
|
+
npm run publish:major # 0.1.0 -> 1.0.0
|
|
311
|
+
```
|
|
279
312
|
|
|
280
313
|
## Requirements
|
|
281
314
|
|
|
282
315
|
- Node.js >= 18.0.0
|
|
283
316
|
|
|
284
|
-
|
|
317
|
+
Works with ESM and CommonJS. Works with tsx, ts-node, Bun, and compiled JavaScript.
|
|
285
318
|
|
|
286
319
|
## License
|
|
287
320
|
|
|
288
321
|
MIT
|
|
289
|
-
|