@fallom/trace 0.1.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 ADDED
@@ -0,0 +1,275 @@
1
+ # @fallom/trace
2
+
3
+ Model A/B testing and tracing for LLM applications. Zero latency, production-ready.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @fallom/trace
9
+
10
+ # With auto-instrumentation for your LLM provider:
11
+ npm install @fallom/trace @traceloop/node-server-sdk
12
+ ```
13
+
14
+ ## Quick Start
15
+
16
+ ```typescript
17
+ import fallom from '@fallom/trace';
18
+ import OpenAI from 'openai';
19
+
20
+ // Initialize FIRST - before importing your LLM libraries
21
+ fallom.init({ apiKey: 'your-api-key' });
22
+
23
+ // Set default session context for tracing
24
+ fallom.trace.setSession('my-agent', sessionId);
25
+
26
+ // All LLM calls are now automatically traced!
27
+ const openai = new OpenAI();
28
+ const response = await openai.chat.completions.create({
29
+ model: 'gpt-4o',
30
+ messages: [{ role: 'user', content: 'Hello!' }],
31
+ });
32
+ ```
33
+
34
+ ## Model A/B Testing
35
+
36
+ Run A/B tests on models with zero latency. Same session always gets same model (sticky assignment).
37
+
38
+ ```typescript
39
+ import { models } from '@fallom/trace';
40
+
41
+ // Get assigned model for this session
42
+ const model = await models.get('summarizer-config', sessionId);
43
+ // Returns: "gpt-4o" or "claude-3-5-sonnet" based on your config weights
44
+
45
+ const agent = new Agent({ model });
46
+ await agent.run(message);
47
+ ```
48
+
49
+ ### Version Pinning
50
+
51
+ Pin to a specific config version, or use latest (default):
52
+
53
+ ```typescript
54
+ // Use latest version (default)
55
+ const model = await models.get('my-config', sessionId);
56
+
57
+ // Pin to specific version
58
+ const model = await models.get('my-config', sessionId, { version: 2 });
59
+ ```
60
+
61
+ ### Fallback for Resilience
62
+
63
+ Always provide a fallback so your app works even if Fallom is down:
64
+
65
+ ```typescript
66
+ const model = await models.get('my-config', sessionId, {
67
+ fallback: 'gpt-4o-mini', // Used if config not found or Fallom unreachable
68
+ });
69
+ ```
70
+
71
+ **Resilience guarantees:**
72
+ - Short timeouts (1-2 seconds max)
73
+ - Background config sync (never blocks your requests)
74
+ - Graceful degradation (returns fallback on any error)
75
+ - Your app is never impacted by Fallom being down
76
+
77
+ ## Tracing
78
+
79
+ Auto-capture all LLM calls with OpenTelemetry instrumentation.
80
+
81
+ > ⚠️ **Important:** Auto-tracing only works with supported LLM SDKs (OpenAI, Anthropic, etc.) - not raw HTTP requests. If you're using an OpenAI-compatible API like OpenRouter, LiteLLM, or a self-hosted model, use the OpenAI SDK with a custom `baseURL`:
82
+ >
83
+ > ```typescript
84
+ > import OpenAI from 'openai';
85
+ >
86
+ > // OpenRouter, LiteLLM, vLLM, etc.
87
+ > const client = new OpenAI({
88
+ > baseURL: 'https://openrouter.ai/api/v1', // or your provider's URL
89
+ > apiKey: 'your-provider-key',
90
+ > });
91
+ >
92
+ > // Now this call will be auto-traced!
93
+ > const response = await client.chat.completions.create({
94
+ > model: 'gpt-4o',
95
+ > messages: [...],
96
+ > });
97
+ > ```
98
+
99
+ ### Automatic Tracing
100
+
101
+ ```typescript
102
+ import fallom from '@fallom/trace';
103
+
104
+ // Initialize before making LLM calls
105
+ fallom.init();
106
+
107
+ // Set session context
108
+ fallom.trace.setSession('my-agent', sessionId);
109
+
110
+ // All LLM calls automatically traced with:
111
+ // - Model, tokens, latency
112
+ // - Prompts and completions
113
+ // - Your config_key and session_id
114
+ const response = await openai.chat.completions.create({
115
+ model: 'gpt-4o',
116
+ messages: [...],
117
+ });
118
+ ```
119
+
120
+ ### Async Context Propagation
121
+
122
+ For proper session context across async boundaries, use `runWithSession`:
123
+
124
+ ```typescript
125
+ import { trace } from '@fallom/trace';
126
+
127
+ await trace.runWithSession('my-agent', sessionId, async () => {
128
+ // All LLM calls in here have session context
129
+ await agent.run(message);
130
+ await anotherAsyncOperation();
131
+ });
132
+ ```
133
+
134
+ ### Custom Metrics
135
+
136
+ Record business metrics that OTEL can't capture automatically:
137
+
138
+ ```typescript
139
+ import { trace } from '@fallom/trace';
140
+
141
+ // Record custom metrics for this session
142
+ trace.span({
143
+ outlier_score: 0.8,
144
+ user_satisfaction: 4,
145
+ conversion: true,
146
+ });
147
+
148
+ // Or explicitly specify session (for batch jobs)
149
+ trace.span(
150
+ { outlier_score: 0.8 },
151
+ { configKey: 'my-agent', sessionId: 'user123-convo456' }
152
+ );
153
+ ```
154
+
155
+ ## Configuration
156
+
157
+ ### Environment Variables
158
+
159
+ ```bash
160
+ FALLOM_API_KEY=your-api-key
161
+ FALLOM_BASE_URL=https://spans.fallom.com # or http://localhost:8001 for local dev
162
+ FALLOM_CAPTURE_CONTENT=true # set to "false" for privacy mode
163
+ ```
164
+
165
+ ### Initialization Options
166
+
167
+ ```typescript
168
+ fallom.init({
169
+ apiKey: 'your-api-key', // Or use FALLOM_API_KEY env var
170
+ baseUrl: 'https://spans.fallom.com', // Or use FALLOM_BASE_URL env var
171
+ captureContent: true, // Set false for privacy mode
172
+ });
173
+ ```
174
+
175
+ ### Privacy Mode
176
+
177
+ For companies with strict data policies, disable prompt/completion capture:
178
+
179
+ ```typescript
180
+ // Via parameter
181
+ fallom.init({ captureContent: false });
182
+
183
+ // Or via environment variable
184
+ // FALLOM_CAPTURE_CONTENT=false
185
+ ```
186
+
187
+ In privacy mode, Fallom still tracks:
188
+ - ✅ Model used
189
+ - ✅ Token counts
190
+ - ✅ Latency
191
+ - ✅ Session/config context
192
+ - ❌ Prompt content (not captured)
193
+ - ❌ Completion content (not captured)
194
+
195
+ ## API Reference
196
+
197
+ ### `fallom.init(options?)`
198
+
199
+ Initialize the SDK. Call this before making LLM calls for auto-instrumentation.
200
+
201
+ | Option | Type | Default | Description |
202
+ |--------|------|---------|-------------|
203
+ | `apiKey` | `string` | `FALLOM_API_KEY` env | Your Fallom API key |
204
+ | `baseUrl` | `string` | `https://spans.fallom.com` | API base URL |
205
+ | `captureContent` | `boolean` | `true` | Capture prompt/completion text |
206
+
207
+ ### `fallom.models.get(configKey, sessionId, options?)`
208
+
209
+ Get model assignment for a session.
210
+
211
+ | Parameter | Type | Description |
212
+ |-----------|------|-------------|
213
+ | `configKey` | `string` | Your config name from the dashboard |
214
+ | `sessionId` | `string` | Unique session/conversation ID (sticky assignment) |
215
+ | `options.version` | `number` | Pin to specific version (default: latest) |
216
+ | `options.fallback` | `string` | Model to return if anything fails |
217
+ | `options.debug` | `boolean` | Enable debug logging |
218
+
219
+ Returns: `Promise<string>` - The assigned model name
220
+
221
+ ### `fallom.trace.setSession(configKey, sessionId)`
222
+
223
+ Set trace context. All subsequent LLM calls will be tagged with this session.
224
+
225
+ ### `fallom.trace.runWithSession(configKey, sessionId, fn)`
226
+
227
+ Run a function with session context that propagates across async boundaries.
228
+
229
+ ### `fallom.trace.clearSession()`
230
+
231
+ Clear trace context.
232
+
233
+ ### `fallom.trace.span(data, options?)`
234
+
235
+ Record custom business metrics.
236
+
237
+ | Parameter | Type | Description |
238
+ |-----------|------|-------------|
239
+ | `data` | `Record<string, unknown>` | Metrics to record |
240
+ | `options.configKey` | `string` | Optional if `setSession()` was called |
241
+ | `options.sessionId` | `string` | Optional if `setSession()` was called |
242
+
243
+ ### `fallom.trace.shutdown()`
244
+
245
+ Gracefully shutdown the tracing SDK. Call this on process exit.
246
+
247
+ ## Supported LLM Providers
248
+
249
+ Auto-instrumentation available for:
250
+ - OpenAI (+ OpenAI-compatible APIs: OpenRouter, LiteLLM, vLLM, Ollama, etc.)
251
+ - Anthropic
252
+ - Cohere
253
+ - AWS Bedrock
254
+ - Google Generative AI
255
+ - Azure OpenAI
256
+ - LangChain
257
+ - And more via Traceloop
258
+
259
+ Install `@traceloop/node-server-sdk` for comprehensive LLM instrumentation.
260
+
261
+ **Note:** You must use the official SDK for your provider. Raw HTTP requests (e.g., `fetch()`) will not be traced. For OpenAI-compatible APIs, use the OpenAI SDK with a custom `baseURL`.
262
+
263
+ ## Examples
264
+
265
+ See the `../examples/` folder for complete examples:
266
+ - `random-fact/` - Simple A/B testing with Hono server
267
+
268
+ ## Requirements
269
+
270
+ - Node.js >= 18.0.0
271
+
272
+ ## License
273
+
274
+ MIT
275
+
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Fallom tracing module.
3
+ *
4
+ * Auto-instruments all LLM calls via OTEL and groups them by session.
5
+ * Also supports custom spans for business metrics.
6
+ */
7
+ interface SessionContext {
8
+ configKey: string;
9
+ sessionId: string;
10
+ }
11
+ /**
12
+ * Initialize Fallom tracing. Auto-instruments all LLM calls.
13
+ *
14
+ * @param options - Configuration options
15
+ * @param options.apiKey - Your Fallom API key. Defaults to FALLOM_API_KEY env var.
16
+ * @param options.baseUrl - API base URL. Defaults to FALLOM_BASE_URL env var, or https://spans.fallom.com
17
+ * @param options.captureContent - Whether to capture prompt/completion content in traces.
18
+ * Set to false for privacy/compliance. Defaults to true.
19
+ * Also respects FALLOM_CAPTURE_CONTENT env var ("true"/"false").
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import fallom from 'fallom';
24
+ *
25
+ * // Normal usage (captures everything)
26
+ * fallom.trace.init();
27
+ *
28
+ * // Privacy mode (no prompts/completions stored)
29
+ * fallom.trace.init({ captureContent: false });
30
+ *
31
+ * fallom.trace.setSession("my-agent", sessionId);
32
+ * await agent.run(message); // Automatically traced
33
+ * ```
34
+ */
35
+ declare function init$2(options?: {
36
+ apiKey?: string;
37
+ baseUrl?: string;
38
+ captureContent?: boolean;
39
+ }): void;
40
+ /**
41
+ * Set the current session context.
42
+ *
43
+ * All subsequent LLM calls in this async context will be
44
+ * automatically tagged with this configKey and sessionId.
45
+ *
46
+ * @param configKey - Your config name (e.g., "linkedin-agent")
47
+ * @param sessionId - Your session/conversation ID
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * trace.setSession("linkedin-agent", sessionId);
52
+ * await agent.run(message); // Automatically traced with session
53
+ * ```
54
+ */
55
+ declare function setSession(configKey: string, sessionId: string): void;
56
+ /**
57
+ * Run a function with session context.
58
+ * Use this to ensure session context propagates across async boundaries.
59
+ *
60
+ * @param configKey - Your config name
61
+ * @param sessionId - Your session ID
62
+ * @param fn - Function to run with session context
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * await trace.runWithSession("my-agent", sessionId, async () => {
67
+ * await agent.run(message); // Has session context
68
+ * });
69
+ * ```
70
+ */
71
+ declare function runWithSession<T>(configKey: string, sessionId: string, fn: () => T): T;
72
+ /**
73
+ * Get current session context, if any.
74
+ */
75
+ declare function getSession(): SessionContext | undefined;
76
+ /**
77
+ * Clear session context.
78
+ */
79
+ declare function clearSession(): void;
80
+ /**
81
+ * Record custom business metrics. Latest value per field wins.
82
+ *
83
+ * Use this for metrics that OTEL can't capture automatically:
84
+ * - Outlier scores
85
+ * - Engagement metrics
86
+ * - Conversion rates
87
+ * - Any business-specific outcome
88
+ *
89
+ * @param data - Dict of metrics to record
90
+ * @param options - Optional session identifiers
91
+ * @param options.configKey - Config name (optional if setSession was called)
92
+ * @param options.sessionId - Session ID (optional if setSession was called)
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * // If session context is set:
97
+ * trace.span({ outlier_score: 0.8, engagement: 42 });
98
+ *
99
+ * // Or explicitly:
100
+ * trace.span(
101
+ * { outlier_score: 0.8 },
102
+ * { configKey: "linkedin-agent", sessionId: "user123-convo456" }
103
+ * );
104
+ * ```
105
+ */
106
+ declare function span(data: Record<string, unknown>, options?: {
107
+ configKey?: string;
108
+ sessionId?: string;
109
+ }): void;
110
+ /**
111
+ * Shutdown the tracing SDK gracefully.
112
+ */
113
+ declare function shutdown(): Promise<void>;
114
+
115
+ declare const trace_clearSession: typeof clearSession;
116
+ declare const trace_getSession: typeof getSession;
117
+ declare const trace_runWithSession: typeof runWithSession;
118
+ declare const trace_setSession: typeof setSession;
119
+ declare const trace_shutdown: typeof shutdown;
120
+ declare const trace_span: typeof span;
121
+ declare namespace trace {
122
+ export { trace_clearSession as clearSession, trace_getSession as getSession, init$2 as init, trace_runWithSession as runWithSession, trace_setSession as setSession, trace_shutdown as shutdown, trace_span as span };
123
+ }
124
+
125
+ /**
126
+ * Fallom models module.
127
+ *
128
+ * Provides model A/B testing with versioned configs.
129
+ * Zero latency on get() - uses local hash + cached config.
130
+ *
131
+ * Design principles:
132
+ * - Never block user's app if Fallom is down
133
+ * - Very short timeouts (1-2 seconds max)
134
+ * - Always return a usable model (fallback if needed)
135
+ * - Background sync keeps configs fresh
136
+ */
137
+ /**
138
+ * Initialize Fallom models.
139
+ *
140
+ * This is optional - get() will auto-init if needed.
141
+ * Non-blocking: starts background config fetch immediately.
142
+ */
143
+ declare function init$1(options?: {
144
+ apiKey?: string;
145
+ baseUrl?: string;
146
+ }): void;
147
+ /**
148
+ * Get model assignment for a session.
149
+ *
150
+ * This is zero latency - uses local hash computation + cached config.
151
+ * No network call on the hot path.
152
+ *
153
+ * Same session_id always returns same model (sticky assignment).
154
+ *
155
+ * Also automatically sets trace context, so all subsequent LLM calls
156
+ * are tagged with this session.
157
+ *
158
+ * @param configKey - Your config name (e.g., "linkedin-agent")
159
+ * @param sessionId - Your session/conversation ID (must be consistent)
160
+ * @param options - Optional settings
161
+ * @param options.version - Pin to specific version (1, 2, etc). undefined = latest
162
+ * @param options.fallback - Model to return if config not found or Fallom is down
163
+ * @param options.debug - Enable debug logging
164
+ * @returns Model string (e.g., "claude-opus", "gpt-4o")
165
+ * @throws Error if config not found AND no fallback provided
166
+ */
167
+ declare function get(configKey: string, sessionId: string, options?: {
168
+ version?: number;
169
+ fallback?: string;
170
+ debug?: boolean;
171
+ }): Promise<string>;
172
+
173
+ declare const models_get: typeof get;
174
+ declare namespace models {
175
+ export { models_get as get, init$1 as init };
176
+ }
177
+
178
+ /**
179
+ * Combined initialization for both trace and models.
180
+ */
181
+ interface InitOptions {
182
+ apiKey?: string;
183
+ baseUrl?: string;
184
+ captureContent?: boolean;
185
+ }
186
+ /**
187
+ * Initialize both trace and models at once.
188
+ *
189
+ * @param options - Configuration options
190
+ * @param options.apiKey - Your Fallom API key. Defaults to FALLOM_API_KEY env var.
191
+ * @param options.baseUrl - API base URL. Defaults to FALLOM_BASE_URL or https://spans.fallom.com
192
+ * @param options.captureContent - Whether to capture prompt/completion content (default: true)
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * import fallom from 'fallom';
197
+ *
198
+ * // Basic initialization
199
+ * fallom.init({ apiKey: "your-api-key" });
200
+ *
201
+ * // Local development
202
+ * fallom.init({ baseUrl: "http://localhost:8001" });
203
+ *
204
+ * // Privacy mode
205
+ * fallom.init({ captureContent: false });
206
+ * ```
207
+ */
208
+ declare function init(options?: InitOptions): void;
209
+
210
+ /**
211
+ * Fallom - Model A/B testing and tracing for LLM applications.
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * import fallom from 'fallom';
216
+ *
217
+ * // Initialize (call this early, before LLM imports if possible)
218
+ * fallom.init({ apiKey: "your-api-key" });
219
+ *
220
+ * // Set session context for tracing
221
+ * fallom.trace.setSession("my-agent", sessionId);
222
+ *
223
+ * // Get A/B tested model
224
+ * const model = await fallom.models.get("my-config", sessionId, {
225
+ * fallback: "gpt-4o-mini"
226
+ * });
227
+ *
228
+ * // Use with OpenAI
229
+ * const response = await openai.chat.completions.create({
230
+ * model,
231
+ * messages: [...]
232
+ * });
233
+ *
234
+ * // Record custom metrics
235
+ * fallom.trace.span({ user_satisfaction: 5 });
236
+ * ```
237
+ */
238
+
239
+ declare const _default: {
240
+ init: typeof init;
241
+ trace: typeof trace;
242
+ models: typeof models;
243
+ };
244
+
245
+ export { type InitOptions, _default as default, init, models, trace };