@posthog/ai 7.16.15 → 7.17.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 +31 -0
- package/dist/anthropic/index.cjs +91 -95
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +91 -95
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +100 -106
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.mjs +100 -106
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +295 -335
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +83 -2
- package/dist/index.mjs +273 -314
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +11 -3
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.mjs +11 -3
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/openai/index.cjs +169 -185
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +169 -185
- package/dist/openai/index.mjs.map +1 -1
- package/dist/openai-agents/index.cjs +14 -12
- package/dist/openai-agents/index.cjs.map +1 -1
- package/dist/openai-agents/index.mjs +14 -12
- package/dist/openai-agents/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +133 -128
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +133 -128
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/anthropic/index.mjs
CHANGED
|
@@ -2,8 +2,6 @@ import AnthropicOriginal from '@anthropic-ai/sdk';
|
|
|
2
2
|
import { v4 } from 'uuid';
|
|
3
3
|
import { uuidv7 } from '@posthog/core';
|
|
4
4
|
|
|
5
|
-
var version = "7.16.15";
|
|
6
|
-
|
|
7
5
|
// Type guards for safer type checking
|
|
8
6
|
|
|
9
7
|
const isObject = value => {
|
|
@@ -78,6 +76,14 @@ function getTokensSource(posthogProperties) {
|
|
|
78
76
|
}
|
|
79
77
|
return 'sdk';
|
|
80
78
|
}
|
|
79
|
+
const STRING_FORMAT = 'utf8';
|
|
80
|
+
|
|
81
|
+
// Reused across calls to avoid per-invocation allocation; truncate() runs
|
|
82
|
+
// hundreds of times for prompts with many parts.
|
|
83
|
+
new TextEncoder();
|
|
84
|
+
new TextDecoder(STRING_FORMAT, {
|
|
85
|
+
fatal: false
|
|
86
|
+
});
|
|
81
87
|
const getModelParams = params => {
|
|
82
88
|
if (!params) {
|
|
83
89
|
return {};
|
|
@@ -203,73 +209,69 @@ function addDefaults(params) {
|
|
|
203
209
|
traceId: params.traceId ?? v4()
|
|
204
210
|
};
|
|
205
211
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
await sendEventToPosthog(properties);
|
|
231
|
-
return enrichedError;
|
|
232
|
-
};
|
|
233
|
-
const sendEventToPosthog = async ({
|
|
234
|
-
client,
|
|
235
|
-
eventType = AIEvent.Generation,
|
|
236
|
-
distinctId,
|
|
237
|
-
traceId,
|
|
238
|
-
model,
|
|
239
|
-
provider,
|
|
240
|
-
input,
|
|
241
|
-
output,
|
|
242
|
-
latency,
|
|
243
|
-
timeToFirstToken,
|
|
244
|
-
baseURL,
|
|
245
|
-
params,
|
|
246
|
-
httpStatus = 200,
|
|
247
|
-
usage = {},
|
|
248
|
-
error,
|
|
249
|
-
exceptionId,
|
|
250
|
-
stopReason,
|
|
251
|
-
tools,
|
|
252
|
-
captureImmediate = false
|
|
253
|
-
}) => {
|
|
212
|
+
|
|
213
|
+
var version = "7.17.1";
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Options for `captureAiGeneration`. Mirrors the `$ai_generation` event shape
|
|
217
|
+
* directly so that any caller — first-party SDK wrappers and external code
|
|
218
|
+
* alike — produces an identical event.
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Capture an `$ai_generation` (or `$ai_embedding`) event to PostHog.
|
|
223
|
+
*
|
|
224
|
+
* This is the canonical primitive that every `@posthog/ai` wrapper
|
|
225
|
+
* (`withTracing`, `OpenAI`, `Anthropic`, `GoogleGenAI`, …) funnels through, so
|
|
226
|
+
* external code can use it directly to instrument LLM calls made through
|
|
227
|
+
* arbitrary clients (Cloudflare Workers AI, custom HTTP, etc.) and get the
|
|
228
|
+
* same events the SDK wrappers produce.
|
|
229
|
+
*
|
|
230
|
+
* When `error` is set, the event is captured as an error. If the error is an
|
|
231
|
+
* object, it is mutated in place to set `__posthog_previously_captured_error`
|
|
232
|
+
* so callers can re-throw the original error reference safely.
|
|
233
|
+
*/
|
|
234
|
+
const captureAiGeneration = async (client, options) => {
|
|
254
235
|
if (!client.capture) {
|
|
255
|
-
return
|
|
236
|
+
return;
|
|
256
237
|
}
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
const
|
|
238
|
+
const traceId = options.traceId ?? v4();
|
|
239
|
+
const eventType = options.eventType ?? AIEvent.Generation;
|
|
240
|
+
const privacyMode = options.privacyMode ?? false;
|
|
241
|
+
const usage = options.usage ?? {};
|
|
242
|
+
const safeInput = sanitizeValues(options.input);
|
|
243
|
+
const safeOutput = sanitizeValues(options.output);
|
|
244
|
+
let httpStatus = options.httpStatus;
|
|
261
245
|
let errorData = {};
|
|
262
|
-
if (error) {
|
|
246
|
+
if (options.error) {
|
|
247
|
+
if (httpStatus === undefined) {
|
|
248
|
+
if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
|
|
249
|
+
httpStatus = options.error.status;
|
|
250
|
+
} else {
|
|
251
|
+
httpStatus = 500;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
let exceptionId;
|
|
255
|
+
if (client.options?.enableExceptionAutocapture) {
|
|
256
|
+
exceptionId = uuidv7();
|
|
257
|
+
client.captureException(options.error, undefined, {
|
|
258
|
+
$ai_trace_id: traceId
|
|
259
|
+
}, exceptionId);
|
|
260
|
+
if (typeof options.error === 'object') {
|
|
261
|
+
options.error.__posthog_previously_captured_error = true;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
263
264
|
errorData = {
|
|
264
265
|
$ai_is_error: true,
|
|
265
|
-
$ai_error:
|
|
266
|
+
$ai_error: sanitizeValues(JSON.stringify(options.error)),
|
|
266
267
|
$exception_event_id: exceptionId
|
|
267
268
|
};
|
|
268
269
|
}
|
|
270
|
+
httpStatus = httpStatus ?? 200;
|
|
269
271
|
let costOverrideData = {};
|
|
270
|
-
if (
|
|
271
|
-
const inputCostUSD = (
|
|
272
|
-
const outputCostUSD = (
|
|
272
|
+
if (options.costOverride) {
|
|
273
|
+
const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
|
|
274
|
+
const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
|
|
273
275
|
costOverrideData = {
|
|
274
276
|
$ai_input_cost_usd: inputCostUSD,
|
|
275
277
|
$ai_output_cost_usd: outputCostUSD,
|
|
@@ -296,50 +298,48 @@ const sendEventToPosthog = async ({
|
|
|
296
298
|
const properties = {
|
|
297
299
|
$ai_lib: 'posthog-ai',
|
|
298
300
|
$ai_lib_version: version,
|
|
299
|
-
$ai_provider:
|
|
300
|
-
$ai_model:
|
|
301
|
-
$ai_model_parameters:
|
|
302
|
-
$ai_input: withPrivacyMode(client,
|
|
303
|
-
$ai_output_choices: withPrivacyMode(client,
|
|
301
|
+
$ai_provider: options.providerOverride ?? options.provider,
|
|
302
|
+
$ai_model: options.modelOverride ?? options.model,
|
|
303
|
+
$ai_model_parameters: options.modelParameters ?? {},
|
|
304
|
+
$ai_input: withPrivacyMode(client, privacyMode, safeInput),
|
|
305
|
+
$ai_output_choices: withPrivacyMode(client, privacyMode, safeOutput),
|
|
304
306
|
$ai_http_status: httpStatus,
|
|
305
307
|
$ai_input_tokens: usage.inputTokens ?? 0,
|
|
306
308
|
...(usage.outputTokens !== undefined ? {
|
|
307
309
|
$ai_output_tokens: usage.outputTokens
|
|
308
310
|
} : {}),
|
|
309
311
|
...additionalTokenValues,
|
|
310
|
-
$ai_latency: latency,
|
|
311
|
-
...(timeToFirstToken !== undefined ? {
|
|
312
|
-
$ai_time_to_first_token: timeToFirstToken
|
|
312
|
+
$ai_latency: options.latency ?? 0,
|
|
313
|
+
...(options.timeToFirstToken !== undefined ? {
|
|
314
|
+
$ai_time_to_first_token: options.timeToFirstToken
|
|
313
315
|
} : {}),
|
|
314
316
|
$ai_trace_id: traceId,
|
|
315
|
-
$ai_base_url: baseURL,
|
|
316
|
-
...
|
|
317
|
-
$ai_tokens_source: getTokensSource(
|
|
318
|
-
...(distinctId ? {} : {
|
|
317
|
+
$ai_base_url: options.baseURL ?? '',
|
|
318
|
+
...options.properties,
|
|
319
|
+
$ai_tokens_source: getTokensSource(options.properties),
|
|
320
|
+
...(options.distinctId ? {} : {
|
|
319
321
|
$process_person_profile: false
|
|
320
322
|
}),
|
|
321
|
-
...(stopReason ? {
|
|
322
|
-
$ai_stop_reason: stopReason
|
|
323
|
+
...(options.stopReason ? {
|
|
324
|
+
$ai_stop_reason: options.stopReason
|
|
323
325
|
} : {}),
|
|
324
|
-
...(tools ? {
|
|
325
|
-
$ai_tools: tools
|
|
326
|
+
...(options.tools ? {
|
|
327
|
+
$ai_tools: options.tools
|
|
326
328
|
} : {}),
|
|
327
329
|
...errorData,
|
|
328
330
|
...costOverrideData
|
|
329
331
|
};
|
|
330
332
|
const event = {
|
|
331
|
-
distinctId: distinctId ?? traceId,
|
|
333
|
+
distinctId: options.distinctId ?? traceId,
|
|
332
334
|
event: eventType,
|
|
333
335
|
properties,
|
|
334
|
-
groups:
|
|
336
|
+
groups: options.groups
|
|
335
337
|
};
|
|
336
|
-
if (captureImmediate) {
|
|
337
|
-
// await capture promise to send single event in serverless environments
|
|
338
|
+
if (options.captureImmediate) {
|
|
338
339
|
await client.captureImmediate(event);
|
|
339
340
|
} else {
|
|
340
341
|
client.capture(event);
|
|
341
342
|
}
|
|
342
|
-
return Promise.resolve();
|
|
343
343
|
};
|
|
344
344
|
|
|
345
345
|
class PostHogAnthropic extends AnthropicOriginal {
|
|
@@ -501,8 +501,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
501
501
|
text: accumulatedContent
|
|
502
502
|
}]
|
|
503
503
|
}];
|
|
504
|
-
await
|
|
505
|
-
client: this.phClient,
|
|
504
|
+
await captureAiGeneration(this.phClient, {
|
|
506
505
|
...posthogParams,
|
|
507
506
|
model: anthropicParams.model,
|
|
508
507
|
provider: 'anthropic',
|
|
@@ -511,15 +510,14 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
511
510
|
latency,
|
|
512
511
|
timeToFirstToken,
|
|
513
512
|
baseURL: this.baseURL,
|
|
514
|
-
|
|
513
|
+
modelParameters: getModelParams(body),
|
|
515
514
|
httpStatus: 200,
|
|
516
515
|
usage,
|
|
517
516
|
stopReason,
|
|
518
517
|
tools: availableTools
|
|
519
518
|
});
|
|
520
519
|
} catch (error) {
|
|
521
|
-
|
|
522
|
-
client: this.phClient,
|
|
520
|
+
await captureAiGeneration(this.phClient, {
|
|
523
521
|
...posthogParams,
|
|
524
522
|
model: anthropicParams.model,
|
|
525
523
|
provider: 'anthropic',
|
|
@@ -527,14 +525,14 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
527
525
|
output: [],
|
|
528
526
|
latency: 0,
|
|
529
527
|
baseURL: this.baseURL,
|
|
530
|
-
|
|
528
|
+
modelParameters: getModelParams(body),
|
|
531
529
|
usage: {
|
|
532
530
|
inputTokens: 0,
|
|
533
531
|
outputTokens: 0
|
|
534
532
|
},
|
|
535
533
|
error: error
|
|
536
534
|
});
|
|
537
|
-
throw
|
|
535
|
+
throw error;
|
|
538
536
|
}
|
|
539
537
|
})();
|
|
540
538
|
|
|
@@ -548,8 +546,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
548
546
|
if ('content' in result) {
|
|
549
547
|
const latency = (Date.now() - startTime) / 1000;
|
|
550
548
|
const availableTools = extractAvailableToolCalls('anthropic', anthropicParams);
|
|
551
|
-
await
|
|
552
|
-
client: this.phClient,
|
|
549
|
+
await captureAiGeneration(this.phClient, {
|
|
553
550
|
...posthogParams,
|
|
554
551
|
model: anthropicParams.model,
|
|
555
552
|
provider: 'anthropic',
|
|
@@ -557,7 +554,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
557
554
|
output: formatResponseAnthropic(result),
|
|
558
555
|
latency,
|
|
559
556
|
baseURL: this.baseURL,
|
|
560
|
-
|
|
557
|
+
modelParameters: getModelParams(body),
|
|
561
558
|
httpStatus: 200,
|
|
562
559
|
usage: {
|
|
563
560
|
inputTokens: result.usage.input_tokens ?? 0,
|
|
@@ -573,8 +570,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
573
570
|
}
|
|
574
571
|
return result;
|
|
575
572
|
}, async error => {
|
|
576
|
-
await
|
|
577
|
-
client: this.phClient,
|
|
573
|
+
await captureAiGeneration(this.phClient, {
|
|
578
574
|
...posthogParams,
|
|
579
575
|
model: anthropicParams.model,
|
|
580
576
|
provider: 'anthropic',
|
|
@@ -582,13 +578,13 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
582
578
|
output: [],
|
|
583
579
|
latency: 0,
|
|
584
580
|
baseURL: this.baseURL,
|
|
585
|
-
|
|
581
|
+
modelParameters: getModelParams(body),
|
|
586
582
|
httpStatus: error?.status ? error.status : 500,
|
|
587
583
|
usage: {
|
|
588
584
|
inputTokens: 0,
|
|
589
585
|
outputTokens: 0
|
|
590
586
|
},
|
|
591
|
-
error:
|
|
587
|
+
error: error
|
|
592
588
|
});
|
|
593
589
|
throw error;
|
|
594
590
|
});
|