@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/gemini/index.mjs
CHANGED
|
@@ -2,8 +2,6 @@ import { GoogleGenAI } from '@google/genai';
|
|
|
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 isString = value => {
|
|
@@ -111,6 +109,14 @@ function getTokensSource(posthogProperties) {
|
|
|
111
109
|
}
|
|
112
110
|
return 'sdk';
|
|
113
111
|
}
|
|
112
|
+
const STRING_FORMAT = 'utf8';
|
|
113
|
+
|
|
114
|
+
// Reused across calls to avoid per-invocation allocation; truncate() runs
|
|
115
|
+
// hundreds of times for prompts with many parts.
|
|
116
|
+
new TextEncoder();
|
|
117
|
+
new TextDecoder(STRING_FORMAT, {
|
|
118
|
+
fatal: false
|
|
119
|
+
});
|
|
114
120
|
|
|
115
121
|
/**
|
|
116
122
|
* Safely converts content to a string, preserving structure for objects/arrays.
|
|
@@ -295,73 +301,69 @@ function addDefaults(params) {
|
|
|
295
301
|
traceId: params.traceId ?? v4()
|
|
296
302
|
};
|
|
297
303
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
await sendEventToPosthog(properties);
|
|
323
|
-
return enrichedError;
|
|
324
|
-
};
|
|
325
|
-
const sendEventToPosthog = async ({
|
|
326
|
-
client,
|
|
327
|
-
eventType = AIEvent.Generation,
|
|
328
|
-
distinctId,
|
|
329
|
-
traceId,
|
|
330
|
-
model,
|
|
331
|
-
provider,
|
|
332
|
-
input,
|
|
333
|
-
output,
|
|
334
|
-
latency,
|
|
335
|
-
timeToFirstToken,
|
|
336
|
-
baseURL,
|
|
337
|
-
params,
|
|
338
|
-
httpStatus = 200,
|
|
339
|
-
usage = {},
|
|
340
|
-
error,
|
|
341
|
-
exceptionId,
|
|
342
|
-
stopReason,
|
|
343
|
-
tools,
|
|
344
|
-
captureImmediate = false
|
|
345
|
-
}) => {
|
|
304
|
+
|
|
305
|
+
var version = "7.17.1";
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Options for `captureAiGeneration`. Mirrors the `$ai_generation` event shape
|
|
309
|
+
* directly so that any caller — first-party SDK wrappers and external code
|
|
310
|
+
* alike — produces an identical event.
|
|
311
|
+
*/
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Capture an `$ai_generation` (or `$ai_embedding`) event to PostHog.
|
|
315
|
+
*
|
|
316
|
+
* This is the canonical primitive that every `@posthog/ai` wrapper
|
|
317
|
+
* (`withTracing`, `OpenAI`, `Anthropic`, `GoogleGenAI`, …) funnels through, so
|
|
318
|
+
* external code can use it directly to instrument LLM calls made through
|
|
319
|
+
* arbitrary clients (Cloudflare Workers AI, custom HTTP, etc.) and get the
|
|
320
|
+
* same events the SDK wrappers produce.
|
|
321
|
+
*
|
|
322
|
+
* When `error` is set, the event is captured as an error. If the error is an
|
|
323
|
+
* object, it is mutated in place to set `__posthog_previously_captured_error`
|
|
324
|
+
* so callers can re-throw the original error reference safely.
|
|
325
|
+
*/
|
|
326
|
+
const captureAiGeneration = async (client, options) => {
|
|
346
327
|
if (!client.capture) {
|
|
347
|
-
return
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
const
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const traceId = options.traceId ?? v4();
|
|
331
|
+
const eventType = options.eventType ?? AIEvent.Generation;
|
|
332
|
+
const privacyMode = options.privacyMode ?? false;
|
|
333
|
+
const usage = options.usage ?? {};
|
|
334
|
+
const safeInput = sanitizeValues(options.input);
|
|
335
|
+
const safeOutput = sanitizeValues(options.output);
|
|
336
|
+
let httpStatus = options.httpStatus;
|
|
353
337
|
let errorData = {};
|
|
354
|
-
if (error) {
|
|
338
|
+
if (options.error) {
|
|
339
|
+
if (httpStatus === undefined) {
|
|
340
|
+
if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
|
|
341
|
+
httpStatus = options.error.status;
|
|
342
|
+
} else {
|
|
343
|
+
httpStatus = 500;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
let exceptionId;
|
|
347
|
+
if (client.options?.enableExceptionAutocapture) {
|
|
348
|
+
exceptionId = uuidv7();
|
|
349
|
+
client.captureException(options.error, undefined, {
|
|
350
|
+
$ai_trace_id: traceId
|
|
351
|
+
}, exceptionId);
|
|
352
|
+
if (typeof options.error === 'object') {
|
|
353
|
+
options.error.__posthog_previously_captured_error = true;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
355
356
|
errorData = {
|
|
356
357
|
$ai_is_error: true,
|
|
357
|
-
$ai_error:
|
|
358
|
+
$ai_error: sanitizeValues(JSON.stringify(options.error)),
|
|
358
359
|
$exception_event_id: exceptionId
|
|
359
360
|
};
|
|
360
361
|
}
|
|
362
|
+
httpStatus = httpStatus ?? 200;
|
|
361
363
|
let costOverrideData = {};
|
|
362
|
-
if (
|
|
363
|
-
const inputCostUSD = (
|
|
364
|
-
const outputCostUSD = (
|
|
364
|
+
if (options.costOverride) {
|
|
365
|
+
const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
|
|
366
|
+
const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
|
|
365
367
|
costOverrideData = {
|
|
366
368
|
$ai_input_cost_usd: inputCostUSD,
|
|
367
369
|
$ai_output_cost_usd: outputCostUSD,
|
|
@@ -388,50 +390,48 @@ const sendEventToPosthog = async ({
|
|
|
388
390
|
const properties = {
|
|
389
391
|
$ai_lib: 'posthog-ai',
|
|
390
392
|
$ai_lib_version: version,
|
|
391
|
-
$ai_provider:
|
|
392
|
-
$ai_model:
|
|
393
|
-
$ai_model_parameters:
|
|
394
|
-
$ai_input: withPrivacyMode(client,
|
|
395
|
-
$ai_output_choices: withPrivacyMode(client,
|
|
393
|
+
$ai_provider: options.providerOverride ?? options.provider,
|
|
394
|
+
$ai_model: options.modelOverride ?? options.model,
|
|
395
|
+
$ai_model_parameters: options.modelParameters ?? {},
|
|
396
|
+
$ai_input: withPrivacyMode(client, privacyMode, safeInput),
|
|
397
|
+
$ai_output_choices: withPrivacyMode(client, privacyMode, safeOutput),
|
|
396
398
|
$ai_http_status: httpStatus,
|
|
397
399
|
$ai_input_tokens: usage.inputTokens ?? 0,
|
|
398
400
|
...(usage.outputTokens !== undefined ? {
|
|
399
401
|
$ai_output_tokens: usage.outputTokens
|
|
400
402
|
} : {}),
|
|
401
403
|
...additionalTokenValues,
|
|
402
|
-
$ai_latency: latency,
|
|
403
|
-
...(timeToFirstToken !== undefined ? {
|
|
404
|
-
$ai_time_to_first_token: timeToFirstToken
|
|
404
|
+
$ai_latency: options.latency ?? 0,
|
|
405
|
+
...(options.timeToFirstToken !== undefined ? {
|
|
406
|
+
$ai_time_to_first_token: options.timeToFirstToken
|
|
405
407
|
} : {}),
|
|
406
408
|
$ai_trace_id: traceId,
|
|
407
|
-
$ai_base_url: baseURL,
|
|
408
|
-
...
|
|
409
|
-
$ai_tokens_source: getTokensSource(
|
|
410
|
-
...(distinctId ? {} : {
|
|
409
|
+
$ai_base_url: options.baseURL ?? '',
|
|
410
|
+
...options.properties,
|
|
411
|
+
$ai_tokens_source: getTokensSource(options.properties),
|
|
412
|
+
...(options.distinctId ? {} : {
|
|
411
413
|
$process_person_profile: false
|
|
412
414
|
}),
|
|
413
|
-
...(stopReason ? {
|
|
414
|
-
$ai_stop_reason: stopReason
|
|
415
|
+
...(options.stopReason ? {
|
|
416
|
+
$ai_stop_reason: options.stopReason
|
|
415
417
|
} : {}),
|
|
416
|
-
...(tools ? {
|
|
417
|
-
$ai_tools: tools
|
|
418
|
+
...(options.tools ? {
|
|
419
|
+
$ai_tools: options.tools
|
|
418
420
|
} : {}),
|
|
419
421
|
...errorData,
|
|
420
422
|
...costOverrideData
|
|
421
423
|
};
|
|
422
424
|
const event = {
|
|
423
|
-
distinctId: distinctId ?? traceId,
|
|
425
|
+
distinctId: options.distinctId ?? traceId,
|
|
424
426
|
event: eventType,
|
|
425
427
|
properties,
|
|
426
|
-
groups:
|
|
428
|
+
groups: options.groups
|
|
427
429
|
};
|
|
428
|
-
if (captureImmediate) {
|
|
429
|
-
// await capture promise to send single event in serverless environments
|
|
430
|
+
if (options.captureImmediate) {
|
|
430
431
|
await client.captureImmediate(event);
|
|
431
432
|
} else {
|
|
432
433
|
client.capture(event);
|
|
433
434
|
}
|
|
434
|
-
return Promise.resolve();
|
|
435
435
|
};
|
|
436
436
|
|
|
437
437
|
class PostHogGoogleGenAI {
|
|
@@ -462,8 +462,7 @@ class WrappedModels {
|
|
|
462
462
|
const availableTools = extractAvailableToolCalls('gemini', geminiParams);
|
|
463
463
|
const metadata = response.usageMetadata;
|
|
464
464
|
const finishReason = response.candidates?.[0]?.finishReason;
|
|
465
|
-
await
|
|
466
|
-
client: this.phClient,
|
|
465
|
+
await captureAiGeneration(this.phClient, {
|
|
467
466
|
...posthogParams,
|
|
468
467
|
model: geminiParams.model,
|
|
469
468
|
provider: 'gemini',
|
|
@@ -471,7 +470,7 @@ class WrappedModels {
|
|
|
471
470
|
output: formatResponseGemini(response),
|
|
472
471
|
latency,
|
|
473
472
|
baseURL: 'https://generativelanguage.googleapis.com',
|
|
474
|
-
|
|
473
|
+
modelParameters: getModelParams(params),
|
|
475
474
|
httpStatus: 200,
|
|
476
475
|
usage: {
|
|
477
476
|
inputTokens: metadata?.promptTokenCount ?? 0,
|
|
@@ -487,8 +486,7 @@ class WrappedModels {
|
|
|
487
486
|
return response;
|
|
488
487
|
} catch (error) {
|
|
489
488
|
const latency = (Date.now() - startTime) / 1000;
|
|
490
|
-
|
|
491
|
-
client: this.phClient,
|
|
489
|
+
await captureAiGeneration(this.phClient, {
|
|
492
490
|
...posthogParams,
|
|
493
491
|
model: geminiParams.model,
|
|
494
492
|
provider: 'gemini',
|
|
@@ -496,14 +494,14 @@ class WrappedModels {
|
|
|
496
494
|
output: [],
|
|
497
495
|
latency,
|
|
498
496
|
baseURL: 'https://generativelanguage.googleapis.com',
|
|
499
|
-
|
|
497
|
+
modelParameters: getModelParams(params),
|
|
500
498
|
usage: {
|
|
501
499
|
inputTokens: 0,
|
|
502
500
|
outputTokens: 0
|
|
503
501
|
},
|
|
504
|
-
error
|
|
502
|
+
error
|
|
505
503
|
});
|
|
506
|
-
throw
|
|
504
|
+
throw error;
|
|
507
505
|
}
|
|
508
506
|
}
|
|
509
507
|
async *generateContentStream(params) {
|
|
@@ -607,8 +605,7 @@ class WrappedModels {
|
|
|
607
605
|
role: 'assistant',
|
|
608
606
|
content: accumulatedContent
|
|
609
607
|
}] : [];
|
|
610
|
-
await
|
|
611
|
-
client: this.phClient,
|
|
608
|
+
await captureAiGeneration(this.phClient, {
|
|
612
609
|
...posthogParams,
|
|
613
610
|
model: geminiParams.model,
|
|
614
611
|
provider: 'gemini',
|
|
@@ -617,7 +614,7 @@ class WrappedModels {
|
|
|
617
614
|
latency,
|
|
618
615
|
timeToFirstToken,
|
|
619
616
|
baseURL: 'https://generativelanguage.googleapis.com',
|
|
620
|
-
|
|
617
|
+
modelParameters: getModelParams(params),
|
|
621
618
|
httpStatus: 200,
|
|
622
619
|
usage: {
|
|
623
620
|
...usage,
|
|
@@ -629,8 +626,7 @@ class WrappedModels {
|
|
|
629
626
|
});
|
|
630
627
|
} catch (error) {
|
|
631
628
|
const latency = (Date.now() - startTime) / 1000;
|
|
632
|
-
|
|
633
|
-
client: this.phClient,
|
|
629
|
+
await captureAiGeneration(this.phClient, {
|
|
634
630
|
...posthogParams,
|
|
635
631
|
model: geminiParams.model,
|
|
636
632
|
provider: 'gemini',
|
|
@@ -638,14 +634,14 @@ class WrappedModels {
|
|
|
638
634
|
output: [],
|
|
639
635
|
latency,
|
|
640
636
|
baseURL: 'https://generativelanguage.googleapis.com',
|
|
641
|
-
|
|
637
|
+
modelParameters: getModelParams(params),
|
|
642
638
|
usage: {
|
|
643
639
|
inputTokens: 0,
|
|
644
640
|
outputTokens: 0
|
|
645
641
|
},
|
|
646
|
-
error
|
|
642
|
+
error
|
|
647
643
|
});
|
|
648
|
-
throw
|
|
644
|
+
throw error;
|
|
649
645
|
}
|
|
650
646
|
}
|
|
651
647
|
async embedContent(params) {
|
|
@@ -658,8 +654,7 @@ class WrappedModels {
|
|
|
658
654
|
const response = await this.client.models.embedContent(geminiParams);
|
|
659
655
|
const latency = (Date.now() - startTime) / 1000;
|
|
660
656
|
const inputTokens = extractEmbeddingTokenCount(response);
|
|
661
|
-
await
|
|
662
|
-
client: this.phClient,
|
|
657
|
+
await captureAiGeneration(this.phClient, {
|
|
663
658
|
...posthogParams,
|
|
664
659
|
eventType: AIEvent.Embedding,
|
|
665
660
|
model: geminiParams.model,
|
|
@@ -668,7 +663,7 @@ class WrappedModels {
|
|
|
668
663
|
output: null,
|
|
669
664
|
latency,
|
|
670
665
|
baseURL: 'https://generativelanguage.googleapis.com',
|
|
671
|
-
|
|
666
|
+
modelParameters: getModelParams(params),
|
|
672
667
|
httpStatus: 200,
|
|
673
668
|
usage: {
|
|
674
669
|
inputTokens
|
|
@@ -677,8 +672,7 @@ class WrappedModels {
|
|
|
677
672
|
return response;
|
|
678
673
|
} catch (error) {
|
|
679
674
|
const latency = (Date.now() - startTime) / 1000;
|
|
680
|
-
|
|
681
|
-
client: this.phClient,
|
|
675
|
+
await captureAiGeneration(this.phClient, {
|
|
682
676
|
...posthogParams,
|
|
683
677
|
eventType: AIEvent.Embedding,
|
|
684
678
|
model: geminiParams.model,
|
|
@@ -687,13 +681,13 @@ class WrappedModels {
|
|
|
687
681
|
output: null,
|
|
688
682
|
latency,
|
|
689
683
|
baseURL: 'https://generativelanguage.googleapis.com',
|
|
690
|
-
|
|
684
|
+
modelParameters: getModelParams(params),
|
|
691
685
|
usage: {
|
|
692
686
|
inputTokens: 0
|
|
693
687
|
},
|
|
694
|
-
error
|
|
688
|
+
error
|
|
695
689
|
});
|
|
696
|
-
throw
|
|
690
|
+
throw error;
|
|
697
691
|
}
|
|
698
692
|
}
|
|
699
693
|
formatPartsAsContentBlocks(parts) {
|