@fallom/trace 0.1.12 → 0.2.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/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 OpenAI from "openai";
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
- // Wrap your LLM client for automatic tracing
21
- const openai = fallom.trace.wrapOpenAI(new OpenAI());
22
-
23
- // Set session context
24
- fallom.trace.setSession("my-agent", sessionId);
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
- ## Model A/B Testing
28
+ // Wrap AI SDK - all calls are now traced!
29
+ const { generateText } = session.wrapAISDK(ai);
34
30
 
35
- Run A/B tests on models with zero latency. Same session always gets same model (sticky assignment).
36
-
37
- ```typescript
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
- ## Prompt Management
56
-
57
- Manage prompts centrally and A/B test them with zero latency.
37
+ ## Tracing
58
38
 
59
- ### Basic Prompt Retrieval
39
+ ### Vercel AI SDK
60
40
 
61
41
  ```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:
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
- ```typescript
90
- import { prompts } from "@fallom/trace";
47
+ await fallom.init({ apiKey: "your-api-key" });
91
48
 
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" },
49
+ const session = fallom.session({
50
+ configKey: "my-agent",
51
+ sessionId: "session-123",
95
52
  });
96
53
 
97
- // prompt.abTestKey and prompt.variantIndex are set
98
- // for analytics in your dashboard
99
- ```
54
+ // Option 1: Wrap the SDK (our style)
55
+ const { generateText, streamText } = session.wrapAISDK(ai);
100
56
 
101
- ### Version Pinning
57
+ await generateText({ model: createOpenAI()("gpt-4o"), prompt: "Hello!" });
58
+ await streamText({ model: createAnthropic()("claude-3-5-sonnet"), prompt: "Hi!" });
102
59
 
103
- ```typescript
104
- // Use latest version (default)
105
- const prompt = await prompts.get("my-prompt");
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
- ### Automatic Trace Tagging
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
- // Works with any OpenAI-compatible API
144
- const openai = fallom.trace.wrapOpenAI(
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", // or Azure, LiteLLM, etc.
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 (Claude)
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 anthropic = fallom.trace.wrapAnthropic(new Anthropic());
100
+ const session = fallom.session({
101
+ configKey: "my-agent",
102
+ sessionId: "session-123",
103
+ });
169
104
 
170
- fallom.trace.setSession("my-config", sessionId);
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 = fallom.trace.wrapGoogleAI(
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
- ## What Gets Traced
135
+ ## Concurrent Sessions
199
136
 
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)
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
- ## Custom Metrics
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
- Record business metrics for your A/B tests:
192
+ Manage prompts centrally and A/B test them.
212
193
 
213
194
  ```typescript
214
- import { trace } from "@fallom/trace";
195
+ import { prompts } from "@fallom/trace";
215
196
 
216
- trace.span({
217
- outlier_score: 0.8,
218
- user_satisfaction: 4,
219
- conversion: true,
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
- ### `fallom.trace.wrapAnthropic(client)`
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
- Wrap Anthropic client for automatic tracing.
267
+ ### `fallom.session(options)`
256
268
 
257
- ### `fallom.trace.wrapGoogleAI(model)`
269
+ Create a session-scoped tracer.
258
270
 
259
- Wrap Google AI model for automatic tracing.
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
- ### `fallom.trace.setSession(configKey, sessionId)`
279
+ Returns a `FallomSession` with these methods:
262
280
 
263
- Set session context for tracing.
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. Returns `Promise<string>`.
294
+ Get model assignment for A/B testing.
268
295
 
269
- ### `fallom.prompts.get(promptKey, options?)`
270
-
271
- Get a managed prompt. Returns `Promise<PromptResult>`.
272
- - `promptKey`: Your prompt key from the dashboard
273
- - `options.variables`: Template variables (e.g., `{ userName: "John" }`)
274
- - `options.version`: Pin to specific version (default: latest)
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
- Get a prompt from an A/B test. Returns `Promise<PromptResult>`.
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
- ### `fallom.trace.span(data)`
305
+ Get a managed prompt.
284
306
 
285
- Record custom business metrics.
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
- ## Testing
315
+ ### `fallom.prompts.getAB(abTestKey, sessionId, options?)`
288
316
 
289
- Run the test suite:
317
+ Get a prompt from an A/B test.
290
318
 
291
- ```bash
292
- cd sdk/typescript-sdk
293
- npm install
294
- npm test
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
- ## Deploying
326
+ ## Mastra Integration
298
327
 
299
- To publish a new version to npm:
300
-
301
- ```bash
302
- cd sdk/typescript-sdk
328
+ ```typescript
329
+ import { FallomExporter } from "@fallom/trace";
330
+ import { Mastra } from "@mastra/core/mastra";
303
331
 
304
- # Update version in package.json
305
- # Then:
306
- npm run build
307
- npm publish --access public
332
+ const session = fallom.session({
333
+ configKey: "my-agent",
334
+ sessionId: "session-123",
335
+ });
308
336
 
309
- # Or use convenience scripts:
310
- npm run publish:patch # 0.1.0 -> 0.1.1
311
- npm run publish:minor # 0.1.0 -> 0.2.0
312
- npm run publish:major # 0.1.0 -> 1.0.0
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. Works with tsx, ts-node, Bun, and compiled JavaScript.
356
+ Works with ESM and CommonJS. Compatible with tsx, ts-node, Bun, and compiled JavaScript.
320
357
 
321
358
  ## License
322
359