@posthog/ai 6.4.3 → 6.5.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/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import { wrapLanguageModel } from 'ai';
6
6
  import AnthropicOriginal from '@anthropic-ai/sdk';
7
7
  import { GoogleGenAI } from '@google/genai';
8
8
 
9
- var version = "6.4.3";
9
+ var version = "6.5.0";
10
10
 
11
11
  // Type guards for safer type checking
12
12
  const isString = value => {
@@ -19,6 +19,31 @@ const isObject = value => {
19
19
  // limit large outputs by truncating to 200kb (approx 200k bytes)
20
20
  const MAX_OUTPUT_SIZE = 200000;
21
21
  const STRING_FORMAT = 'utf8';
22
+ /**
23
+ * Safely converts content to a string, preserving structure for objects/arrays.
24
+ * - If content is already a string, returns it as-is
25
+ * - If content is an object or array, stringifies it with JSON.stringify to preserve structure
26
+ * - Otherwise, converts to string with String()
27
+ *
28
+ * This prevents the "[object Object]" bug when objects are naively converted to strings.
29
+ *
30
+ * @param content - The content to convert to a string
31
+ * @returns A string representation that preserves structure for complex types
32
+ */
33
+ function toContentString(content) {
34
+ if (typeof content === 'string') {
35
+ return content;
36
+ }
37
+ if (content !== undefined && content !== null && typeof content === 'object') {
38
+ try {
39
+ return JSON.stringify(content);
40
+ } catch {
41
+ // Fallback for circular refs, BigInt, or objects with throwing toJSON
42
+ return String(content);
43
+ }
44
+ }
45
+ return String(content);
46
+ }
22
47
  const getModelParams = params => {
23
48
  if (!params) {
24
49
  return {};
@@ -446,15 +471,16 @@ function formatOpenAIResponsesInput(input, instructions) {
446
471
  } else if (item && typeof item === 'object') {
447
472
  const obj = item;
448
473
  const role = isString(obj.role) ? obj.role : 'user';
449
- const content = obj.content || obj.text || String(item);
474
+ // Handle content properly - preserve structure for objects/arrays
475
+ const content = obj.content ?? obj.text ?? item;
450
476
  messages.push({
451
477
  role,
452
- content: String(content)
478
+ content: toContentString(content)
453
479
  });
454
480
  } else {
455
481
  messages.push({
456
482
  role: 'user',
457
- content: String(item)
483
+ content: toContentString(item)
458
484
  });
459
485
  }
460
486
  }
@@ -466,7 +492,7 @@ function formatOpenAIResponsesInput(input, instructions) {
466
492
  } else if (input) {
467
493
  messages.push({
468
494
  role: 'user',
469
- content: String(input)
495
+ content: toContentString(input)
470
496
  });
471
497
  }
472
498
  return messages;
@@ -1606,7 +1632,7 @@ const mapVercelPrompt = messages => {
1606
1632
  if (message.role === 'system') {
1607
1633
  content = [{
1608
1634
  type: 'text',
1609
- text: truncate(String(message.content))
1635
+ text: truncate(toContentString(message.content))
1610
1636
  }];
1611
1637
  } else {
1612
1638
  // Handle other roles which have array content
@@ -1664,7 +1690,7 @@ const mapVercelPrompt = messages => {
1664
1690
  // Fallback for non-array content
1665
1691
  content = [{
1666
1692
  type: 'text',
1667
- text: truncate(String(message.content))
1693
+ text: truncate(toContentString(message.content))
1668
1694
  }];
1669
1695
  }
1670
1696
  }
@@ -1792,7 +1818,11 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
1792
1818
  const startTime = Date.now();
1793
1819
  const mergedParams = {
1794
1820
  ...options,
1795
- ...mapVercelParams(params)
1821
+ ...mapVercelParams(params),
1822
+ posthogProperties: {
1823
+ ...options.posthogProperties,
1824
+ $ai_framework: 'vercel'
1825
+ }
1796
1826
  };
1797
1827
  const availableTools = extractAvailableToolCalls('vercel', params);
1798
1828
  try {
@@ -1868,7 +1898,11 @@ const createInstrumentationMiddleware = (phClient, model, options) => {
1868
1898
  let usage = {};
1869
1899
  const mergedParams = {
1870
1900
  ...options,
1871
- ...mapVercelParams(params)
1901
+ ...mapVercelParams(params),
1902
+ posthogProperties: {
1903
+ ...options.posthogProperties,
1904
+ $ai_framework: 'vercel'
1905
+ }
1872
1906
  };
1873
1907
  const modelId = options.posthogModelOverride ?? model.modelId;
1874
1908
  const provider = options.posthogProviderOverride ?? extractProvider(model);
@@ -2479,7 +2513,7 @@ class WrappedModels {
2479
2513
  }
2480
2514
  return {
2481
2515
  role: 'user',
2482
- content: String(item)
2516
+ content: toContentString(item)
2483
2517
  };
2484
2518
  });
2485
2519
  }
@@ -2500,7 +2534,7 @@ class WrappedModels {
2500
2534
  }
2501
2535
  return [{
2502
2536
  role: 'user',
2503
- content: String(contents)
2537
+ content: toContentString(contents)
2504
2538
  }];
2505
2539
  }
2506
2540
  extractSystemInstruction(params) {
@@ -3302,7 +3336,8 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
3302
3336
  $ai_input_state: withPrivacyMode(this.client, this.privacyMode, run.input),
3303
3337
  $ai_latency: latency,
3304
3338
  $ai_span_name: run.name,
3305
- $ai_span_id: runId
3339
+ $ai_span_id: runId,
3340
+ $ai_framework: 'langchain'
3306
3341
  };
3307
3342
  if (parentRunId) {
3308
3343
  eventProperties['$ai_parent_id'] = parentRunId;
@@ -3350,7 +3385,8 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
3350
3385
  $ai_input: withPrivacyMode(this.client, this.privacyMode, run.input),
3351
3386
  $ai_http_status: 200,
3352
3387
  $ai_latency: latency,
3353
- $ai_base_url: run.baseUrl
3388
+ $ai_base_url: run.baseUrl,
3389
+ $ai_framework: 'langchain'
3354
3390
  };
3355
3391
  if (run.tools) {
3356
3392
  eventProperties['$ai_tools'] = run.tools;
@@ -3492,7 +3528,7 @@ class LangChainCallbackHandler extends BaseCallbackHandler {
3492
3528
  default:
3493
3529
  messageDict = {
3494
3530
  role: messageType,
3495
- content: String(message.content)
3531
+ content: toContentString(message.content)
3496
3532
  };
3497
3533
  break;
3498
3534
  }