@posthog/ai 2.3.1 → 3.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/ai",
3
- "version": "2.3.1",
3
+ "version": "3.0.0",
4
4
  "description": "PostHog Node.js AI integrations",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,27 +12,26 @@
12
12
  "types": "lib/index.d.ts",
13
13
  "license": "MIT",
14
14
  "devDependencies": {
15
- "@types/jest": "^28.1.5",
16
15
  "@types/node": "^18.0.0",
17
- "jest": "^29.0.0",
18
16
  "node-fetch": "^3.3.2",
19
- "ts-jest": "^29.0.0",
20
- "typescript": "^4.7.4",
21
- "ai": "^4.0.0",
22
- "openai": "^4.0.0"
17
+ "typescript": "^4.7.4"
23
18
  },
24
19
  "keywords": [
25
20
  "posthog",
26
21
  "ai",
27
22
  "openai",
28
23
  "anthropic",
29
- "llm"
24
+ "llm",
25
+ "observability"
30
26
  ],
31
27
  "dependencies": {
32
- "uuid": "^11.0.5",
33
- "zod": "^3.24.1",
28
+ "@anthropic-ai/sdk": "^0.36.3",
29
+ "@langchain/core": "^0.3.37",
34
30
  "ai": "^4.0.0",
35
- "openai": "^4.0.0"
31
+ "langchain": "^0.3.15",
32
+ "openai": "^4.0.0",
33
+ "uuid": "^11.0.5",
34
+ "zod": "^3.24.1"
36
35
  },
37
36
  "scripts": {
38
37
  "test": "jest",
@@ -0,0 +1,195 @@
1
+ import AnthropicOriginal from '@anthropic-ai/sdk'
2
+ import { PostHog } from 'posthog-node'
3
+ import { v4 as uuidv4 } from 'uuid'
4
+ import { PassThrough } from 'stream'
5
+ import { formatResponseAnthropic, mergeSystemPrompt, MonitoringParams, sendEventToPosthog } from '../utils'
6
+
7
+ type MessageCreateParamsNonStreaming = AnthropicOriginal.Messages.MessageCreateParamsNonStreaming
8
+ type MessageCreateParamsStreaming = AnthropicOriginal.Messages.MessageCreateParamsStreaming
9
+ type MessageCreateParams = AnthropicOriginal.Messages.MessageCreateParams
10
+ type Message = AnthropicOriginal.Messages.Message
11
+ type RawMessageStreamEvent = AnthropicOriginal.Messages.RawMessageStreamEvent
12
+ type MessageCreateParamsBase = AnthropicOriginal.Messages.MessageCreateParams
13
+
14
+ import type { APIPromise, RequestOptions } from '@anthropic-ai/sdk/core'
15
+ import type { Stream } from '@anthropic-ai/sdk/streaming'
16
+
17
+ interface MonitoringAnthropicConfig {
18
+ apiKey: string
19
+ posthog: PostHog
20
+ baseURL?: string
21
+ }
22
+
23
+ export class PostHogAnthropic extends AnthropicOriginal {
24
+ private readonly phClient: PostHog
25
+ public messages: WrappedMessages
26
+
27
+ constructor(config: MonitoringAnthropicConfig) {
28
+ const { posthog, ...anthropicConfig } = config
29
+ super(anthropicConfig)
30
+ this.phClient = posthog
31
+ this.messages = new WrappedMessages(this, this.phClient)
32
+ }
33
+ }
34
+
35
+ export class WrappedMessages extends AnthropicOriginal.Messages {
36
+ private readonly phClient: PostHog
37
+
38
+ constructor(parentClient: PostHogAnthropic, phClient: PostHog) {
39
+ super(parentClient)
40
+ this.phClient = phClient
41
+ }
42
+
43
+ public create(body: MessageCreateParamsNonStreaming, options?: RequestOptions): APIPromise<Message>
44
+ public create(
45
+ body: MessageCreateParamsStreaming & MonitoringParams,
46
+ options?: RequestOptions
47
+ ): APIPromise<Stream<RawMessageStreamEvent>>
48
+ public create(
49
+ body: MessageCreateParamsBase & MonitoringParams,
50
+ options?: RequestOptions
51
+ ): APIPromise<Stream<RawMessageStreamEvent> | Message>
52
+ public create(
53
+ body: MessageCreateParams & MonitoringParams,
54
+ options?: RequestOptions
55
+ ): APIPromise<Message> | APIPromise<Stream<RawMessageStreamEvent>> {
56
+ const {
57
+ posthogDistinctId,
58
+ posthogTraceId,
59
+ posthogProperties,
60
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
61
+ posthogPrivacyMode = false,
62
+ posthogGroups,
63
+ ...anthropicParams
64
+ } = body
65
+
66
+ const traceId = posthogTraceId ?? uuidv4()
67
+ const startTime = Date.now()
68
+
69
+ const parentPromise = super.create(anthropicParams, options)
70
+
71
+ if (anthropicParams.stream) {
72
+ return parentPromise.then((value) => {
73
+ const passThroughStream = new PassThrough({ objectMode: true })
74
+ let accumulatedContent = ''
75
+ const usage: { inputTokens: number; outputTokens: number } = {
76
+ inputTokens: 0,
77
+ outputTokens: 0,
78
+ }
79
+ if ('tee' in value) {
80
+ const anthropicStream = value
81
+ ;(async () => {
82
+ try {
83
+ for await (const chunk of anthropicStream) {
84
+ if ('delta' in chunk) {
85
+ if ('text' in chunk.delta) {
86
+ const delta = chunk?.delta?.text ?? ''
87
+ accumulatedContent += delta
88
+ }
89
+ }
90
+ if (chunk.type == 'message_start') {
91
+ usage.inputTokens = chunk.message.usage.input_tokens ?? 0
92
+ }
93
+ if ('usage' in chunk) {
94
+ usage.outputTokens = chunk.usage.output_tokens ?? 0
95
+ }
96
+ passThroughStream.write(chunk)
97
+ }
98
+ const latency = (Date.now() - startTime) / 1000
99
+ sendEventToPosthog({
100
+ client: this.phClient,
101
+ distinctId: posthogDistinctId ?? traceId,
102
+ traceId,
103
+ model: anthropicParams.model,
104
+ provider: 'anthropic',
105
+ input: mergeSystemPrompt(anthropicParams, 'anthropic'),
106
+ output: [{ content: accumulatedContent, role: 'assistant' }],
107
+ latency,
108
+ baseURL: (this as any).baseURL ?? '',
109
+ params: body,
110
+ httpStatus: 200,
111
+ usage,
112
+ })
113
+ passThroughStream.end()
114
+ } catch (error: any) {
115
+ // error handling
116
+ sendEventToPosthog({
117
+ client: this.phClient,
118
+ distinctId: posthogDistinctId ?? traceId,
119
+ traceId,
120
+ model: anthropicParams.model,
121
+ provider: 'anthropic',
122
+ input: mergeSystemPrompt(anthropicParams, 'anthropic'),
123
+ output: [],
124
+ latency: 0,
125
+ baseURL: (this as any).baseURL ?? '',
126
+ params: body,
127
+ httpStatus: error?.status ? error.status : 500,
128
+ usage: {
129
+ inputTokens: 0,
130
+ outputTokens: 0,
131
+ },
132
+ isError: true,
133
+ error: JSON.stringify(error),
134
+ })
135
+ passThroughStream.emit('error', error)
136
+ }
137
+ })()
138
+ }
139
+ return passThroughStream as unknown as Stream<RawMessageStreamEvent>
140
+ }) as APIPromise<Stream<RawMessageStreamEvent>>
141
+ } else {
142
+ const wrappedPromise = parentPromise.then(
143
+ (result) => {
144
+ if ('content' in result) {
145
+ const latency = (Date.now() - startTime) / 1000
146
+ sendEventToPosthog({
147
+ client: this.phClient,
148
+ distinctId: posthogDistinctId ?? traceId,
149
+ traceId,
150
+ model: anthropicParams.model,
151
+ provider: 'anthropic',
152
+ input: mergeSystemPrompt(anthropicParams, 'anthropic'),
153
+ output: formatResponseAnthropic(result),
154
+ latency,
155
+ baseURL: (this as any).baseURL ?? '',
156
+ params: body,
157
+ httpStatus: 200,
158
+ usage: {
159
+ inputTokens: result.usage.input_tokens ?? 0,
160
+ outputTokens: result.usage.output_tokens ?? 0,
161
+ },
162
+ })
163
+ }
164
+ return result
165
+ },
166
+ (error: any) => {
167
+ sendEventToPosthog({
168
+ client: this.phClient,
169
+ distinctId: posthogDistinctId ?? traceId,
170
+ traceId,
171
+ model: anthropicParams.model,
172
+ provider: 'anthropic',
173
+ input: mergeSystemPrompt(anthropicParams, 'anthropic'),
174
+ output: [],
175
+ latency: 0,
176
+ baseURL: (this as any).baseURL ?? '',
177
+ params: body,
178
+ httpStatus: error?.status ? error.status : 500,
179
+ usage: {
180
+ inputTokens: 0,
181
+ outputTokens: 0,
182
+ },
183
+ isError: true,
184
+ error: JSON.stringify(error),
185
+ })
186
+ throw error
187
+ }
188
+ ) as APIPromise<Message>
189
+
190
+ return wrappedPromise
191
+ }
192
+ }
193
+ }
194
+
195
+ export default PostHogAnthropic
package/src/index.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import PostHogOpenAI from './openai'
2
2
  import PostHogAzureOpenAI from './openai/azure'
3
3
  import { wrapVercelLanguageModel } from './vercel/middleware'
4
+ import PostHogAnthropic from './anthropic'
5
+ import { LangChainCallbackHandler } from './langchain/callbacks'
4
6
 
5
7
  export { PostHogOpenAI as OpenAI }
6
8
  export { PostHogAzureOpenAI as AzureOpenAI }
9
+ export { PostHogAnthropic as Anthropic }
7
10
  export { wrapVercelLanguageModel as withTracing }
11
+ export { LangChainCallbackHandler }