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