@posthog/ai 8.10.0 → 8.10.2

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.
Files changed (51) hide show
  1. package/dist/adk/index.cjs +908 -1198
  2. package/dist/adk/index.cjs.map +1 -1
  3. package/dist/adk/index.d.ts +109 -109
  4. package/dist/adk/index.mjs +907 -1196
  5. package/dist/adk/index.mjs.map +1 -1
  6. package/dist/anthropic/index.cjs +927 -1111
  7. package/dist/anthropic/index.cjs.map +1 -1
  8. package/dist/anthropic/index.d.ts +34 -33
  9. package/dist/anthropic/index.mjs +899 -1102
  10. package/dist/anthropic/index.mjs.map +1 -1
  11. package/dist/gemini/index.cjs +863 -1108
  12. package/dist/gemini/index.cjs.map +1 -1
  13. package/dist/gemini/index.d.ts +38 -35
  14. package/dist/gemini/index.mjs +858 -1103
  15. package/dist/gemini/index.mjs.map +1 -1
  16. package/dist/index.cjs +1218 -1546
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +170 -163
  19. package/dist/index.mjs +1216 -1544
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/langchain/index.cjs +851 -1029
  22. package/dist/langchain/index.cjs.map +1 -1
  23. package/dist/langchain/index.d.ts +75 -75
  24. package/dist/langchain/index.mjs +850 -1027
  25. package/dist/langchain/index.mjs.map +1 -1
  26. package/dist/langchain/middleware/index.cjs +1016 -1225
  27. package/dist/langchain/middleware/index.cjs.map +1 -1
  28. package/dist/langchain/middleware/index.d.ts +29 -25
  29. package/dist/langchain/middleware/index.mjs +1015 -1223
  30. package/dist/langchain/middleware/index.mjs.map +1 -1
  31. package/dist/openai/index.cjs +1990 -2523
  32. package/dist/openai/index.cjs.map +1 -1
  33. package/dist/openai/index.d.ts +106 -104
  34. package/dist/openai/index.mjs +1985 -2518
  35. package/dist/openai/index.mjs.map +1 -1
  36. package/dist/openai-agents/index.cjs +745 -827
  37. package/dist/openai-agents/index.cjs.map +1 -1
  38. package/dist/openai-agents/index.d.ts +48 -47
  39. package/dist/openai-agents/index.mjs +744 -825
  40. package/dist/openai-agents/index.mjs.map +1 -1
  41. package/dist/otel/index.cjs +427 -486
  42. package/dist/otel/index.cjs.map +1 -1
  43. package/dist/otel/index.d.ts +36 -35
  44. package/dist/otel/index.mjs +426 -484
  45. package/dist/otel/index.mjs.map +1 -1
  46. package/dist/vercel/index.cjs +992 -1343
  47. package/dist/vercel/index.cjs.map +1 -1
  48. package/dist/vercel/index.d.ts +21 -16
  49. package/dist/vercel/index.mjs +991 -1341
  50. package/dist/vercel/index.mjs.map +1 -1
  51. package/package.json +15 -14
@@ -1,2676 +1,2143 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var openai = require('openai');
6
- var uuid = require('uuid');
7
- var core = require('@posthog/core');
8
- var streaming = require('openai/streaming');
9
-
10
- // Type guards for safer type checking
11
-
12
- const isString = value => {
13
- return typeof value === 'string';
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ let openai = require("openai");
6
+ let uuid = require("uuid");
7
+ let _posthog_core = require("@posthog/core");
8
+ let openai_streaming = require("openai/streaming");
9
+ //#region src/typeGuards.ts
10
+ const isString = (value) => {
11
+ return typeof value === "string";
14
12
  };
15
-
16
- /** @internal */
17
-
18
- /** @internal */
19
-
13
+ //#endregion
14
+ //#region src/captureAiEvent.ts
20
15
  /** @internal */
21
16
  function isFullAiCaptureEnabled(client) {
22
- return client?.enableFullAiCapture === true;
17
+ return client?.enableFullAiCapture === true;
23
18
  }
24
-
25
19
  /** @internal */
26
20
  function captureAiEvent(client, event) {
27
- if (isFullAiCaptureEnabled(client) && typeof client.captureAi === 'function') {
28
- client.captureAi(event);
29
- return;
30
- }
31
- client.capture(event);
21
+ if (isFullAiCaptureEnabled(client) && typeof client.captureAi === "function") {
22
+ client.captureAi(event);
23
+ return;
24
+ }
25
+ client.capture(event);
32
26
  }
33
-
34
27
  /** @internal */
35
28
  async function captureAiEventImmediate(client, event) {
36
- if (isFullAiCaptureEnabled(client) && typeof client.captureAiImmediate === 'function') {
37
- await client.captureAiImmediate(event);
38
- return;
39
- }
40
- await client.captureImmediate(event);
29
+ if (isFullAiCaptureEnabled(client) && typeof client.captureAiImmediate === "function") {
30
+ await client.captureAiImmediate(event);
31
+ return;
32
+ }
33
+ await client.captureImmediate(event);
41
34
  }
42
-
35
+ //#endregion
36
+ //#region src/sanitization/base64_recognizer.ts
43
37
  const DATA_URL_PREFIX_RE = /^data:([^;,\s]+)(?:;[^;,\s]+)*;base64,/i;
44
38
  const BASE64_ALPHABET_RE = /^[A-Za-z0-9+/_=-]+$/;
45
- class Base64Recognizer {
46
- recognize(value, minLength) {
47
- const dataUrl = DATA_URL_PREFIX_RE.exec(value);
48
- if (dataUrl) return {
49
- kind: 'data-url',
50
- mediaType: dataUrl[1]
51
- };
52
- if (value.length < minLength) return {
53
- kind: 'none'
54
- };
55
- const confidencePrefix = value.slice(0, minLength);
56
- if (BASE64_ALPHABET_RE.test(confidencePrefix)) {
57
- return {
58
- kind: 'raw'
59
- };
60
- } else {
61
- return {
62
- kind: 'none'
63
- };
64
- }
65
- }
66
- }
67
-
68
- const MIME_HINT_KEYS = ['mediaType', 'media_type', 'mimeType', 'mime_type'];
69
- const STRONG_CONTEXT_KEYS = new Set(['data', 'file_data', 'fileData', 'image_url', 'imageUrl', 'video_url', 'videoUrl', 'audio', 'audio_data', 'audioData', 'inline_data', 'inlineData', 'source', 'result']);
70
- const STRONG_CONTEXT_TYPES = new Set(['image', 'image_url', 'input_image', 'audio', 'input_audio', 'video', 'video_url', 'file', 'input_file', 'document', 'media', 'file-data']);
71
- const FILE_FAMILY_TYPES = new Set(['file', 'input_file', 'document', 'media', 'file-data']);
72
- const KNOWN_AUDIO_FORMATS = new Set(['wav', 'mp3', 'ogg', 'flac', 'm4a', 'aac', 'webm']);
73
- class MediaTypeContext {
74
- static EMPTY = new MediaTypeContext(undefined, undefined);
75
- constructor(parent, key, explicitMediaType) {
76
- this.parent = parent;
77
- this.key = key;
78
- this.explicitMediaType = explicitMediaType;
79
- }
80
- inferMediaType() {
81
- return this.inferFromSiblingMime() ?? this.inferFromSiblingFormat() ?? this.inferFromParentType() ?? this.inferFromKey();
82
- }
83
- inferFromSiblingMime() {
84
- if (this.explicitMediaType) return this.explicitMediaType;
85
- if (!this.parent) return undefined;
86
- for (const hint of MIME_HINT_KEYS) {
87
- const v = this.parent[hint];
88
- if (typeof v === 'string') return v;
89
- }
90
- return undefined;
91
- }
92
- inferFromSiblingFormat() {
93
- if (!this.parent) return undefined;
94
- const fmt = this.parent.format;
95
- if (typeof fmt === 'string' && KNOWN_AUDIO_FORMATS.has(fmt.toLowerCase())) {
96
- return `audio/${fmt.toLowerCase()}`;
97
- }
98
- return undefined;
99
- }
100
- inferFromParentType() {
101
- if (!this.parent) return undefined;
102
- const t = this.parent.type;
103
- if (typeof t !== 'string') return undefined;
104
- if (t === 'image' || t === 'image_url' || t === 'input_image') return 'image';
105
- if (t === 'audio' || t === 'input_audio') return 'audio';
106
- if (t === 'video' || t === 'video_url') return 'video';
107
- if (FILE_FAMILY_TYPES.has(t)) return 'application/octet-stream';
108
- return undefined;
109
- }
110
- inferFromKey() {
111
- if (!this.key) return undefined;
112
- const key = this.key.toLowerCase();
113
- if (key.includes('audio')) return 'audio';
114
- if (key.includes('video')) return 'video';
115
- if (key.includes('image')) return 'image';
116
- if (key.includes('file') || key.includes('document')) return 'application/octet-stream';
117
- return undefined;
118
- }
119
- hasExplicitBinaryMediaType() {
120
- if (!this.explicitMediaType && (!this.parent || !this.key || !STRONG_CONTEXT_KEYS.has(this.key))) return false;
121
- const mediaType = this.inferFromSiblingMime();
122
- return mediaType !== undefined && !mediaType.toLowerCase().startsWith('text/');
123
- }
124
- signalsBinary() {
125
- if (this.explicitMediaType) return true;
126
- if (this.parent) {
127
- for (const hint of MIME_HINT_KEYS) {
128
- if (typeof this.parent[hint] === 'string') return true;
129
- }
130
- const fmt = this.parent.format;
131
- if (typeof fmt === 'string' && KNOWN_AUDIO_FORMATS.has(fmt.toLowerCase())) return true;
132
- const t = this.parent.type;
133
- if (typeof t === 'string' && STRONG_CONTEXT_TYPES.has(t)) return true;
134
- }
135
- if (this.key && STRONG_CONTEXT_KEYS.has(this.key)) return true;
136
- return false;
137
- }
138
- }
139
-
39
+ var Base64Recognizer = class {
40
+ recognize(value, minLength) {
41
+ const dataUrl = DATA_URL_PREFIX_RE.exec(value);
42
+ if (dataUrl) return {
43
+ kind: "data-url",
44
+ mediaType: dataUrl[1]
45
+ };
46
+ if (value.length < minLength) return { kind: "none" };
47
+ const confidencePrefix = value.slice(0, minLength);
48
+ if (BASE64_ALPHABET_RE.test(confidencePrefix)) return { kind: "raw" };
49
+ else return { kind: "none" };
50
+ }
51
+ };
52
+ //#endregion
53
+ //#region src/sanitization/media_type_context.ts
54
+ const MIME_HINT_KEYS = [
55
+ "mediaType",
56
+ "media_type",
57
+ "mimeType",
58
+ "mime_type"
59
+ ];
60
+ const STRONG_CONTEXT_KEYS = /* @__PURE__ */ new Set([
61
+ "data",
62
+ "file_data",
63
+ "fileData",
64
+ "image_url",
65
+ "imageUrl",
66
+ "video_url",
67
+ "videoUrl",
68
+ "audio",
69
+ "audio_data",
70
+ "audioData",
71
+ "inline_data",
72
+ "inlineData",
73
+ "source",
74
+ "result"
75
+ ]);
76
+ const STRONG_CONTEXT_TYPES = /* @__PURE__ */ new Set([
77
+ "image",
78
+ "image_url",
79
+ "input_image",
80
+ "audio",
81
+ "input_audio",
82
+ "video",
83
+ "video_url",
84
+ "file",
85
+ "input_file",
86
+ "document",
87
+ "media",
88
+ "file-data"
89
+ ]);
90
+ const FILE_FAMILY_TYPES = /* @__PURE__ */ new Set([
91
+ "file",
92
+ "input_file",
93
+ "document",
94
+ "media",
95
+ "file-data"
96
+ ]);
97
+ const KNOWN_AUDIO_FORMATS = /* @__PURE__ */ new Set([
98
+ "wav",
99
+ "mp3",
100
+ "ogg",
101
+ "flac",
102
+ "m4a",
103
+ "aac",
104
+ "webm"
105
+ ]);
106
+ var MediaTypeContext = class MediaTypeContext {
107
+ static {
108
+ this.EMPTY = new MediaTypeContext(void 0, void 0);
109
+ }
110
+ constructor(parent, key, explicitMediaType) {
111
+ this.parent = parent;
112
+ this.key = key;
113
+ this.explicitMediaType = explicitMediaType;
114
+ }
115
+ inferMediaType() {
116
+ return this.inferFromSiblingMime() ?? this.inferFromSiblingFormat() ?? this.inferFromParentType() ?? this.inferFromKey();
117
+ }
118
+ inferFromSiblingMime() {
119
+ if (this.explicitMediaType) return this.explicitMediaType;
120
+ if (!this.parent) return void 0;
121
+ for (const hint of MIME_HINT_KEYS) {
122
+ const v = this.parent[hint];
123
+ if (typeof v === "string") return v;
124
+ }
125
+ }
126
+ inferFromSiblingFormat() {
127
+ if (!this.parent) return void 0;
128
+ const fmt = this.parent.format;
129
+ if (typeof fmt === "string" && KNOWN_AUDIO_FORMATS.has(fmt.toLowerCase())) return `audio/${fmt.toLowerCase()}`;
130
+ }
131
+ inferFromParentType() {
132
+ if (!this.parent) return void 0;
133
+ const t = this.parent.type;
134
+ if (typeof t !== "string") return void 0;
135
+ if (t === "image" || t === "image_url" || t === "input_image") return "image";
136
+ if (t === "audio" || t === "input_audio") return "audio";
137
+ if (t === "video" || t === "video_url") return "video";
138
+ if (FILE_FAMILY_TYPES.has(t)) return "application/octet-stream";
139
+ }
140
+ inferFromKey() {
141
+ if (!this.key) return void 0;
142
+ const key = this.key.toLowerCase();
143
+ if (key.includes("audio")) return "audio";
144
+ if (key.includes("video")) return "video";
145
+ if (key.includes("image")) return "image";
146
+ if (key.includes("file") || key.includes("document")) return "application/octet-stream";
147
+ }
148
+ hasExplicitBinaryMediaType() {
149
+ if (!this.explicitMediaType && (!this.parent || !this.key || !STRONG_CONTEXT_KEYS.has(this.key))) return false;
150
+ const mediaType = this.inferFromSiblingMime();
151
+ return mediaType !== void 0 && !mediaType.toLowerCase().startsWith("text/");
152
+ }
153
+ signalsBinary() {
154
+ if (this.explicitMediaType) return true;
155
+ if (this.parent) {
156
+ for (const hint of MIME_HINT_KEYS) if (typeof this.parent[hint] === "string") return true;
157
+ const fmt = this.parent.format;
158
+ if (typeof fmt === "string" && KNOWN_AUDIO_FORMATS.has(fmt.toLowerCase())) return true;
159
+ const t = this.parent.type;
160
+ if (typeof t === "string" && STRONG_CONTEXT_TYPES.has(t)) return true;
161
+ }
162
+ if (this.key && STRONG_CONTEXT_KEYS.has(this.key)) return true;
163
+ return false;
164
+ }
165
+ };
166
+ //#endregion
167
+ //#region src/sanitization/binary_content_redactor.ts
140
168
  const STRONG_CONTEXT_MIN_LENGTH = 64;
141
169
  const WEAK_CONTEXT_MIN_LENGTH = 1024;
142
- class BinaryContentRedactor {
143
- visited = new WeakSet();
144
- constructor(recognizer = new Base64Recognizer()) {
145
- this.recognizer = recognizer;
146
- }
147
- redact(value, mediaType) {
148
- this.visited = new WeakSet();
149
- return this.walk(value, mediaType ? new MediaTypeContext(undefined, undefined, mediaType) : MediaTypeContext.EMPTY);
150
- }
151
- walk(value, ctx) {
152
- if (value === null || value === undefined) return value;
153
- if (typeof value === 'string') return this.redactString(value, ctx);
154
- if (typeof value !== 'object') return value;
155
-
156
- // Buffer extends Uint8Array, so this branch catches both.
157
- if (typeof Uint8Array !== 'undefined' && value instanceof Uint8Array) {
158
- return this.placeholderFor(ctx.inferMediaType());
159
- }
160
- if (this.visited.has(value)) return null;
161
- this.visited.add(value);
162
- if (Array.isArray(value)) {
163
- return value.map(item => this.walk(item, ctx));
164
- }
165
- const obj = value;
166
- const out = {};
167
- for (const k of Object.keys(obj)) {
168
- out[k] = this.walk(obj[k], new MediaTypeContext(obj, k));
169
- }
170
- return out;
171
- }
172
- redactString(value, ctx) {
173
- const hasExplicitBinaryMediaType = ctx.hasExplicitBinaryMediaType();
174
- const recognitionValue = hasExplicitBinaryMediaType ? value.replace(/[\r\n]/g, '') : value;
175
- const minLength = hasExplicitBinaryMediaType ? Math.min(recognitionValue.length, STRONG_CONTEXT_MIN_LENGTH) : ctx.signalsBinary() ? STRONG_CONTEXT_MIN_LENGTH : WEAK_CONTEXT_MIN_LENGTH;
176
- const recognition = this.recognizer.recognize(recognitionValue, minLength);
177
- switch (recognition.kind) {
178
- case 'data-url':
179
- return this.placeholderFor(recognition.mediaType);
180
- case 'raw':
181
- return this.placeholderFor(ctx.inferMediaType());
182
- case 'none':
183
- return value;
184
- }
185
- }
186
- placeholderFor(mediaType) {
187
- if (!mediaType) return '[base64 redacted]';
188
- if (mediaType === 'application/octet-stream') return '[base64 file redacted]';
189
- return `[base64 ${mediaType} redacted]`;
190
- }
191
- }
192
-
170
+ var BinaryContentRedactor = class {
171
+ constructor(recognizer = new Base64Recognizer()) {
172
+ this.recognizer = recognizer;
173
+ this.visited = /* @__PURE__ */ new WeakSet();
174
+ }
175
+ redact(value, mediaType) {
176
+ this.visited = /* @__PURE__ */ new WeakSet();
177
+ return this.walk(value, mediaType ? new MediaTypeContext(void 0, void 0, mediaType) : MediaTypeContext.EMPTY);
178
+ }
179
+ walk(value, ctx) {
180
+ if (value === null || value === void 0) return value;
181
+ if (typeof value === "string") return this.redactString(value, ctx);
182
+ if (typeof value !== "object") return value;
183
+ if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return this.placeholderFor(ctx.inferMediaType());
184
+ if (this.visited.has(value)) return null;
185
+ this.visited.add(value);
186
+ if (Array.isArray(value)) return value.map((item) => this.walk(item, ctx));
187
+ const obj = value;
188
+ const out = {};
189
+ for (const k of Object.keys(obj)) out[k] = this.walk(obj[k], new MediaTypeContext(obj, k));
190
+ return out;
191
+ }
192
+ redactString(value, ctx) {
193
+ const hasExplicitBinaryMediaType = ctx.hasExplicitBinaryMediaType();
194
+ const recognitionValue = hasExplicitBinaryMediaType ? value.replace(/[\r\n]/g, "") : value;
195
+ const minLength = hasExplicitBinaryMediaType ? Math.min(recognitionValue.length, STRONG_CONTEXT_MIN_LENGTH) : ctx.signalsBinary() ? STRONG_CONTEXT_MIN_LENGTH : WEAK_CONTEXT_MIN_LENGTH;
196
+ const recognition = this.recognizer.recognize(recognitionValue, minLength);
197
+ switch (recognition.kind) {
198
+ case "data-url": return this.placeholderFor(recognition.mediaType);
199
+ case "raw": return this.placeholderFor(ctx.inferMediaType());
200
+ case "none": return value;
201
+ }
202
+ }
203
+ placeholderFor(mediaType) {
204
+ if (!mediaType) return "[base64 redacted]";
205
+ if (mediaType === "application/octet-stream") return "[base64 file redacted]";
206
+ return `[base64 ${mediaType} redacted]`;
207
+ }
208
+ };
209
+ //#endregion
210
+ //#region src/sanitization.ts
193
211
  const redactor = new BinaryContentRedactor();
194
212
  const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
195
213
  const sanitizeOpenAI = (data, client) => sanitize(data, client);
196
214
  const sanitizeOpenAIResponse = (data, client) => sanitize(data, client);
197
-
198
- const TOKEN_PROPERTY_KEYS = new Set(['$ai_input_tokens', '$ai_output_tokens', '$ai_cache_read_input_tokens', '$ai_cache_creation_input_tokens', '$ai_total_tokens', '$ai_reasoning_tokens']);
199
-
215
+ //#endregion
216
+ //#region src/utils.ts
217
+ const TOKEN_PROPERTY_KEYS = /* @__PURE__ */ new Set([
218
+ "$ai_input_tokens",
219
+ "$ai_output_tokens",
220
+ "$ai_cache_read_input_tokens",
221
+ "$ai_cache_creation_input_tokens",
222
+ "$ai_total_tokens",
223
+ "$ai_reasoning_tokens"
224
+ ]);
200
225
  /**
201
- * Whether the caller supplied their own token counts, which override the ones the SDK
202
- * derived from the provider response.
203
- */
226
+ * Whether the caller supplied their own token counts, which override the ones the SDK
227
+ * derived from the provider response.
228
+ */
204
229
  function hasTokenOverrides(posthogProperties) {
205
- return !!posthogProperties && Object.keys(posthogProperties).some(key => TOKEN_PROPERTY_KEYS.has(key));
230
+ return !!posthogProperties && Object.keys(posthogProperties).some((key) => TOKEN_PROPERTY_KEYS.has(key));
206
231
  }
207
232
  function getTokensSource(posthogProperties) {
208
- return hasTokenOverrides(posthogProperties) ? 'passthrough' : 'sdk';
233
+ return hasTokenOverrides(posthogProperties) ? "passthrough" : "sdk";
209
234
  }
210
- const STRING_FORMAT = 'utf8';
211
-
212
- // Reused across calls to avoid per-invocation allocation; truncate() runs
213
- // hundreds of times for prompts with many parts.
235
+ const STRING_FORMAT = "utf8";
214
236
  new TextEncoder();
215
- new TextDecoder(STRING_FORMAT, {
216
- fatal: false
217
- });
218
-
237
+ new TextDecoder(STRING_FORMAT, { fatal: false });
219
238
  /**
220
- * Safely converts content to a string, preserving structure for objects/arrays.
221
- * - If content is already a string, returns it as-is
222
- * - If content is an object or array, stringifies it with JSON.stringify to preserve structure
223
- * - Otherwise, converts to string with String()
224
- *
225
- * This prevents the "[object Object]" bug when objects are naively converted to strings.
226
- *
227
- * @param content - The content to convert to a string
228
- * @returns A string representation that preserves structure for complex types
229
- */
239
+ * Safely converts content to a string, preserving structure for objects/arrays.
240
+ * - If content is already a string, returns it as-is
241
+ * - If content is an object or array, stringifies it with JSON.stringify to preserve structure
242
+ * - Otherwise, converts to string with String()
243
+ *
244
+ * This prevents the "[object Object]" bug when objects are naively converted to strings.
245
+ *
246
+ * @param content - The content to convert to a string
247
+ * @returns A string representation that preserves structure for complex types
248
+ */
230
249
  function toContentString(content) {
231
- if (typeof content === 'string') {
232
- return content;
233
- }
234
- if (content !== undefined && content !== null && typeof content === 'object') {
235
- try {
236
- return JSON.stringify(content);
237
- } catch {
238
- // Fallback for circular refs, BigInt, or objects with throwing toJSON
239
- return String(content);
240
- }
241
- }
242
- return String(content);
250
+ if (typeof content === "string") return content;
251
+ if (content !== void 0 && content !== null && typeof content === "object") try {
252
+ return JSON.stringify(content);
253
+ } catch {
254
+ return String(content);
255
+ }
256
+ return String(content);
243
257
  }
244
258
  const getModelParams = (params, responseServiceTier) => {
245
- if (!params) {
246
- return {};
247
- }
248
- const modelParams = {};
249
- const paramKeys = ['temperature', 'max_tokens', 'max_completion_tokens', 'top_p', 'frequency_penalty', 'presence_penalty', 'n', 'stop', 'stream', 'streaming', 'language', 'response_format', 'timestamp_granularities', 'service_tier'];
250
- for (const key of paramKeys) {
251
- if (key in params && params[key] !== undefined) {
252
- modelParams[key] = params[key];
253
- }
254
- }
255
- if (responseServiceTier != null) {
256
- modelParams.service_tier = responseServiceTier;
257
- }
258
- return modelParams;
259
+ if (!params) return {};
260
+ const modelParams = {};
261
+ for (const key of [
262
+ "temperature",
263
+ "max_tokens",
264
+ "max_completion_tokens",
265
+ "top_p",
266
+ "frequency_penalty",
267
+ "presence_penalty",
268
+ "n",
269
+ "stop",
270
+ "stream",
271
+ "streaming",
272
+ "language",
273
+ "response_format",
274
+ "timestamp_granularities",
275
+ "service_tier"
276
+ ]) if (key in params && params[key] !== void 0) modelParams[key] = params[key];
277
+ if (responseServiceTier != null) modelParams.service_tier = responseServiceTier;
278
+ return modelParams;
259
279
  };
260
- const formatResponseOpenAI = response => {
261
- const output = [];
262
- if (response.choices) {
263
- for (const choice of response.choices) {
264
- const content = [];
265
- let role = 'assistant';
266
- if (choice.message) {
267
- if (choice.message.role) {
268
- role = choice.message.role;
269
- }
270
- if (choice.message.content) {
271
- content.push({
272
- type: 'text',
273
- text: choice.message.content
274
- });
275
- }
276
- if (choice.message.tool_calls) {
277
- for (const toolCall of choice.message.tool_calls) {
278
- content.push({
279
- type: 'function',
280
- id: toolCall.id,
281
- function: {
282
- name: toolCall.function.name,
283
- arguments: toolCall.function.arguments
284
- }
285
- });
286
- }
287
- }
288
-
289
- // Handle audio output (gpt-4o-audio-preview)
290
- if (choice.message.audio) {
291
- content.push({
292
- type: 'audio',
293
- ...choice.message.audio
294
- });
295
- }
296
- }
297
- if (content.length > 0) {
298
- output.push({
299
- role,
300
- content
301
- });
302
- }
303
- }
304
- }
305
-
306
- // Handle Responses API format
307
- if (response.output) {
308
- const content = [];
309
- let role = 'assistant';
310
- for (const item of response.output) {
311
- if (item.type === 'message') {
312
- role = item.role;
313
- if (item.content && Array.isArray(item.content)) {
314
- for (const contentItem of item.content) {
315
- if (contentItem.type === 'output_text' && contentItem.text) {
316
- content.push({
317
- type: 'text',
318
- text: contentItem.text
319
- });
320
- } else if (contentItem.text) {
321
- content.push({
322
- type: 'text',
323
- text: contentItem.text
324
- });
325
- } else if (contentItem.type === 'input_image' && contentItem.image_url) {
326
- content.push({
327
- type: 'image',
328
- image: contentItem.image_url
329
- });
330
- }
331
- }
332
- } else if (item.content) {
333
- content.push({
334
- type: 'text',
335
- text: String(item.content)
336
- });
337
- }
338
- } else if (item.type === 'function_call') {
339
- content.push({
340
- type: 'function',
341
- id: item.call_id || item.id || '',
342
- function: {
343
- name: item.name,
344
- arguments: item.arguments || {}
345
- }
346
- });
347
- } else if (item.type === 'image_generation_call' && item.result) {
348
- content.push({
349
- type: 'image',
350
- image: item.result
351
- });
352
- }
353
- }
354
- if (content.length > 0) {
355
- output.push({
356
- role,
357
- content
358
- });
359
- }
360
- }
361
- return output;
280
+ const formatResponseOpenAI = (response) => {
281
+ const output = [];
282
+ if (response.choices) for (const choice of response.choices) {
283
+ const content = [];
284
+ let role = "assistant";
285
+ if (choice.message) {
286
+ if (choice.message.role) role = choice.message.role;
287
+ if (choice.message.content) content.push({
288
+ type: "text",
289
+ text: choice.message.content
290
+ });
291
+ if (choice.message.tool_calls) for (const toolCall of choice.message.tool_calls) content.push({
292
+ type: "function",
293
+ id: toolCall.id,
294
+ function: {
295
+ name: toolCall.function.name,
296
+ arguments: toolCall.function.arguments
297
+ }
298
+ });
299
+ if (choice.message.audio) content.push({
300
+ type: "audio",
301
+ ...choice.message.audio
302
+ });
303
+ }
304
+ if (content.length > 0) output.push({
305
+ role,
306
+ content
307
+ });
308
+ }
309
+ if (response.output) {
310
+ const content = [];
311
+ let role = "assistant";
312
+ for (const item of response.output) if (item.type === "message") {
313
+ role = item.role;
314
+ if (item.content && Array.isArray(item.content)) {
315
+ for (const contentItem of item.content) if (contentItem.type === "output_text" && contentItem.text) content.push({
316
+ type: "text",
317
+ text: contentItem.text
318
+ });
319
+ else if (contentItem.text) content.push({
320
+ type: "text",
321
+ text: contentItem.text
322
+ });
323
+ else if (contentItem.type === "input_image" && contentItem.image_url) content.push({
324
+ type: "image",
325
+ image: contentItem.image_url
326
+ });
327
+ } else if (item.content) content.push({
328
+ type: "text",
329
+ text: String(item.content)
330
+ });
331
+ } else if (item.type === "function_call") content.push({
332
+ type: "function",
333
+ id: item.call_id || item.id || "",
334
+ function: {
335
+ name: item.name,
336
+ arguments: item.arguments || {}
337
+ }
338
+ });
339
+ else if (item.type === "image_generation_call" && item.result) content.push({
340
+ type: "image",
341
+ image: item.result
342
+ });
343
+ if (content.length > 0) output.push({
344
+ role,
345
+ content
346
+ });
347
+ }
348
+ return output;
362
349
  };
363
350
  const withPrivacyMode = (client, privacyMode, input) => {
364
- return client.privacy_mode || privacyMode ? null : input;
351
+ return client.privacy_mode || privacyMode ? null : input;
365
352
  };
366
-
367
353
  /**
368
- * Calculate web search count from raw API response.
369
- *
370
- * Uses a two-tier detection strategy:
371
- * Priority 1 (Exact Count): Count actual web search calls when available
372
- * Priority 2 (Binary Detection): Return 1 if web search indicators are present, 0 otherwise
373
- *
374
- * @param result - Raw API response from any provider (OpenAI, Perplexity, OpenRouter, Gemini, etc.)
375
- * @returns Number of web searches performed (exact count or binary 1/0)
376
- */
354
+ * Calculate web search count from raw API response.
355
+ *
356
+ * Uses a two-tier detection strategy:
357
+ * Priority 1 (Exact Count): Count actual web search calls when available
358
+ * Priority 2 (Binary Detection): Return 1 if web search indicators are present, 0 otherwise
359
+ *
360
+ * @param result - Raw API response from any provider (OpenAI, Perplexity, OpenRouter, Gemini, etc.)
361
+ * @returns Number of web searches performed (exact count or binary 1/0)
362
+ */
377
363
  function calculateWebSearchCount(result) {
378
- if (!result || typeof result !== 'object') {
379
- return 0;
380
- }
381
-
382
- // Priority 1: Exact Count
383
- // Check for OpenAI Responses API web_search_call items
384
- if ('output' in result && Array.isArray(result.output)) {
385
- let count = 0;
386
- for (const item of result.output) {
387
- if (typeof item === 'object' && item !== null && 'type' in item && item.type === 'web_search_call') {
388
- count++;
389
- }
390
- }
391
- if (count > 0) {
392
- return count;
393
- }
394
- }
395
-
396
- // Priority 2: Binary Detection (1 or 0)
397
-
398
- // Check for citations at root level (Perplexity)
399
- if ('citations' in result && Array.isArray(result.citations) && result.citations.length > 0) {
400
- return 1;
401
- }
402
-
403
- // Check for search_results at root level (Perplexity via OpenRouter)
404
- if ('search_results' in result && Array.isArray(result.search_results) && result.search_results.length > 0) {
405
- return 1;
406
- }
407
-
408
- // Check for usage.search_context_size (Perplexity via OpenRouter)
409
- if ('usage' in result && typeof result.usage === 'object' && result.usage !== null) {
410
- if ('search_context_size' in result.usage && result.usage.search_context_size) {
411
- return 1;
412
- }
413
- }
414
-
415
- // Check for annotations with url_citation in choices[].message or choices[].delta (OpenAI/Perplexity)
416
- if ('choices' in result && Array.isArray(result.choices)) {
417
- for (const choice of result.choices) {
418
- if (typeof choice === 'object' && choice !== null) {
419
- // Check both message (non-streaming) and delta (streaming) for annotations
420
- const content = ('message' in choice ? choice.message : null) || ('delta' in choice ? choice.delta : null);
421
- if (typeof content === 'object' && content !== null && 'annotations' in content) {
422
- const annotations = content.annotations;
423
- if (Array.isArray(annotations)) {
424
- const hasUrlCitation = annotations.some(ann => {
425
- return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
426
- });
427
- if (hasUrlCitation) {
428
- return 1;
429
- }
430
- }
431
- }
432
- }
433
- }
434
- }
435
-
436
- // Check for annotations in output[].content[] (OpenAI Responses API)
437
- if ('output' in result && Array.isArray(result.output)) {
438
- for (const item of result.output) {
439
- if (typeof item === 'object' && item !== null && 'content' in item) {
440
- const content = item.content;
441
- if (Array.isArray(content)) {
442
- for (const contentItem of content) {
443
- if (typeof contentItem === 'object' && contentItem !== null && 'annotations' in contentItem) {
444
- const annotations = contentItem.annotations;
445
- if (Array.isArray(annotations)) {
446
- const hasUrlCitation = annotations.some(ann => {
447
- return typeof ann === 'object' && ann !== null && 'type' in ann && ann.type === 'url_citation';
448
- });
449
- if (hasUrlCitation) {
450
- return 1;
451
- }
452
- }
453
- }
454
- }
455
- }
456
- }
457
- }
458
- }
459
-
460
- // Check for grounding_metadata (Gemini)
461
- if ('candidates' in result && Array.isArray(result.candidates)) {
462
- for (const candidate of result.candidates) {
463
- if (typeof candidate === 'object' && candidate !== null && 'grounding_metadata' in candidate && candidate.grounding_metadata) {
464
- return 1;
465
- }
466
- }
467
- }
468
- return 0;
364
+ if (!result || typeof result !== "object") return 0;
365
+ if ("output" in result && Array.isArray(result.output)) {
366
+ let count = 0;
367
+ for (const item of result.output) if (typeof item === "object" && item !== null && "type" in item && item.type === "web_search_call") count++;
368
+ if (count > 0) return count;
369
+ }
370
+ if ("citations" in result && Array.isArray(result.citations) && result.citations.length > 0) return 1;
371
+ if ("search_results" in result && Array.isArray(result.search_results) && result.search_results.length > 0) return 1;
372
+ if ("usage" in result && typeof result.usage === "object" && result.usage !== null) {
373
+ if ("search_context_size" in result.usage && result.usage.search_context_size) return 1;
374
+ }
375
+ if ("choices" in result && Array.isArray(result.choices)) {
376
+ for (const choice of result.choices) if (typeof choice === "object" && choice !== null) {
377
+ const content = ("message" in choice ? choice.message : null) || ("delta" in choice ? choice.delta : null);
378
+ if (typeof content === "object" && content !== null && "annotations" in content) {
379
+ const annotations = content.annotations;
380
+ if (Array.isArray(annotations)) {
381
+ if (annotations.some((ann) => {
382
+ return typeof ann === "object" && ann !== null && "type" in ann && ann.type === "url_citation";
383
+ })) return 1;
384
+ }
385
+ }
386
+ }
387
+ }
388
+ if ("output" in result && Array.isArray(result.output)) {
389
+ for (const item of result.output) if (typeof item === "object" && item !== null && "content" in item) {
390
+ const content = item.content;
391
+ if (Array.isArray(content)) {
392
+ for (const contentItem of content) if (typeof contentItem === "object" && contentItem !== null && "annotations" in contentItem) {
393
+ const annotations = contentItem.annotations;
394
+ if (Array.isArray(annotations)) {
395
+ if (annotations.some((ann) => {
396
+ return typeof ann === "object" && ann !== null && "type" in ann && ann.type === "url_citation";
397
+ })) return 1;
398
+ }
399
+ }
400
+ }
401
+ }
402
+ }
403
+ if ("candidates" in result && Array.isArray(result.candidates)) {
404
+ for (const candidate of result.candidates) if (typeof candidate === "object" && candidate !== null && "grounding_metadata" in candidate && candidate.grounding_metadata) return 1;
405
+ }
406
+ return 0;
469
407
  }
470
-
471
408
  /**
472
- * Extract available tool calls from the request parameters.
473
- * These are the tools provided to the LLM, not the tool calls in the response.
474
- */
409
+ * Extract available tool calls from the request parameters.
410
+ * These are the tools provided to the LLM, not the tool calls in the response.
411
+ */
475
412
  const extractAvailableToolCalls = (provider, params) => {
476
- {
477
- if (params.tools) {
478
- return params.tools;
479
- }
480
- return null;
481
- }
413
+ if (provider === "anthropic") {
414
+ if (params.tools) return params.tools;
415
+ return null;
416
+ } else if (provider === "gemini") {
417
+ if (params.config && params.config.tools) return params.config.tools;
418
+ return null;
419
+ } else if (provider === "openai") {
420
+ if (params.tools) return params.tools;
421
+ return null;
422
+ } else if (provider === "vercel") {
423
+ if (params.tools) return params.tools;
424
+ return null;
425
+ }
426
+ return null;
482
427
  };
483
- let AIEvent = /*#__PURE__*/function (AIEvent) {
484
- AIEvent["Generation"] = "$ai_generation";
485
- AIEvent["Embedding"] = "$ai_embedding";
486
- return AIEvent;
487
- }({});
488
428
  function sanitizeValues(obj) {
489
- if (obj === undefined || obj === null) {
490
- return obj;
491
- }
492
- const jsonSafe = JSON.parse(JSON.stringify(obj));
493
- if (typeof jsonSafe === 'string') {
494
- // Sanitize lone surrogates by round-tripping through UTF-8
495
- return new TextDecoder().decode(new TextEncoder().encode(jsonSafe));
496
- } else if (Array.isArray(jsonSafe)) {
497
- return jsonSafe.map(sanitizeValues);
498
- } else if (jsonSafe && typeof jsonSafe === 'object') {
499
- return Object.fromEntries(Object.entries(jsonSafe).map(([k, v]) => [k, sanitizeValues(v)]));
500
- }
501
- return jsonSafe;
429
+ if (obj === void 0 || obj === null) return obj;
430
+ const jsonSafe = JSON.parse(JSON.stringify(obj));
431
+ if (typeof jsonSafe === "string") return new TextDecoder().decode(new TextEncoder().encode(jsonSafe));
432
+ else if (Array.isArray(jsonSafe)) return jsonSafe.map(sanitizeValues);
433
+ else if (jsonSafe && typeof jsonSafe === "object") return Object.fromEntries(Object.entries(jsonSafe).map(([k, v]) => [k, sanitizeValues(v)]));
434
+ return jsonSafe;
502
435
  }
503
436
  const POSTHOG_PARAMS_MAP = {
504
- posthogDistinctId: 'distinctId',
505
- posthogTraceId: 'traceId',
506
- posthogProperties: 'properties',
507
- posthogPrivacyMode: 'privacyMode',
508
- posthogGroups: 'groups',
509
- posthogModelOverride: 'modelOverride',
510
- posthogProviderOverride: 'providerOverride',
511
- posthogCostOverride: 'costOverride',
512
- posthogCaptureImmediate: 'captureImmediate'
437
+ posthogDistinctId: "distinctId",
438
+ posthogTraceId: "traceId",
439
+ posthogProperties: "properties",
440
+ posthogPrivacyMode: "privacyMode",
441
+ posthogGroups: "groups",
442
+ posthogModelOverride: "modelOverride",
443
+ posthogProviderOverride: "providerOverride",
444
+ posthogCostOverride: "costOverride",
445
+ posthogCaptureImmediate: "captureImmediate"
513
446
  };
514
447
  function extractPosthogParams(body) {
515
- const providerParams = {};
516
- const posthogParams = {};
517
- for (const [key, value] of Object.entries(body)) {
518
- if (POSTHOG_PARAMS_MAP[key]) {
519
- posthogParams[POSTHOG_PARAMS_MAP[key]] = value;
520
- } else if (key.startsWith('posthog')) {
521
- console.warn(`Unknown Posthog parameter ${key}`);
522
- } else {
523
- providerParams[key] = value;
524
- }
525
- }
526
- return {
527
- providerParams: providerParams,
528
- posthogParams: addDefaults(posthogParams)
529
- };
448
+ const providerParams = {};
449
+ const posthogParams = {};
450
+ for (const [key, value] of Object.entries(body)) if (POSTHOG_PARAMS_MAP[key]) posthogParams[POSTHOG_PARAMS_MAP[key]] = value;
451
+ else if (key.startsWith("posthog")) console.warn(`Unknown Posthog parameter ${key}`);
452
+ else providerParams[key] = value;
453
+ return {
454
+ providerParams,
455
+ posthogParams: addDefaults(posthogParams)
456
+ };
530
457
  }
531
458
  function addDefaults(params) {
532
- return {
533
- ...params,
534
- privacyMode: params.privacyMode ?? false,
535
- traceId: params.traceId ?? uuid.v4()
536
- };
459
+ return {
460
+ ...params,
461
+ privacyMode: params.privacyMode ?? false,
462
+ traceId: params.traceId ?? (0, uuid.v4)()
463
+ };
537
464
  }
538
465
  function formatOpenAIResponsesInput(input, instructions) {
539
- const messages = [];
540
- if (instructions) {
541
- messages.push({
542
- role: 'system',
543
- content: instructions
544
- });
545
- }
546
- if (Array.isArray(input)) {
547
- for (const item of input) {
548
- if (typeof item === 'string') {
549
- messages.push({
550
- role: 'user',
551
- content: item
552
- });
553
- } else if (item && typeof item === 'object') {
554
- const obj = item;
555
- const role = isString(obj.role) ? obj.role : 'user';
556
-
557
- // Handle content properly - preserve structure for objects/arrays
558
- const content = obj.content ?? obj.text ?? item;
559
- messages.push({
560
- role,
561
- content: toContentString(content)
562
- });
563
- } else {
564
- messages.push({
565
- role: 'user',
566
- content: toContentString(item)
567
- });
568
- }
569
- }
570
- } else if (typeof input === 'string') {
571
- messages.push({
572
- role: 'user',
573
- content: input
574
- });
575
- } else if (input) {
576
- messages.push({
577
- role: 'user',
578
- content: toContentString(input)
579
- });
580
- }
581
- return messages;
466
+ const messages = [];
467
+ if (instructions) messages.push({
468
+ role: "system",
469
+ content: instructions
470
+ });
471
+ if (Array.isArray(input)) for (const item of input) if (typeof item === "string") messages.push({
472
+ role: "user",
473
+ content: item
474
+ });
475
+ else if (item && typeof item === "object") {
476
+ const obj = item;
477
+ const role = isString(obj.role) ? obj.role : "user";
478
+ const content = obj.content ?? obj.text ?? item;
479
+ messages.push({
480
+ role,
481
+ content: toContentString(content)
482
+ });
483
+ } else messages.push({
484
+ role: "user",
485
+ content: toContentString(item)
486
+ });
487
+ else if (typeof input === "string") messages.push({
488
+ role: "user",
489
+ content: input
490
+ });
491
+ else if (input) messages.push({
492
+ role: "user",
493
+ content: toContentString(input)
494
+ });
495
+ return messages;
582
496
  }
583
-
584
- var version = "8.10.0";
585
-
497
+ //#endregion
498
+ //#region package.json
499
+ var version = "8.10.2";
500
+ //#endregion
501
+ //#region src/serializeError.ts
586
502
  const DEFAULT_MAX_DEPTH = 3;
587
503
  const MAX_STACK_LINES = 20;
588
504
  function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
589
- if (depth < 0 || value === null || typeof value !== 'object') {
590
- return value;
591
- }
592
- if (value instanceof Error) {
593
- const out = {
594
- name: value.name,
595
- message: value.message,
596
- stack: truncateStack(value.stack)
597
- };
598
- for (const key of Object.keys(value)) {
599
- out[key] = serializeError(value[key], depth - 1);
600
- }
601
- if (value.cause !== undefined) {
602
- out.cause = serializeError(value.cause, depth - 1);
603
- }
604
- return out;
605
- }
606
- if (Array.isArray(value)) {
607
- return value.map(item => serializeError(item, depth - 1));
608
- }
609
- return value;
505
+ if (depth < 0 || value === null || typeof value !== "object") return value;
506
+ if (value instanceof Error) {
507
+ const out = {
508
+ name: value.name,
509
+ message: value.message,
510
+ stack: truncateStack(value.stack)
511
+ };
512
+ for (const key of Object.keys(value)) out[key] = serializeError(value[key], depth - 1);
513
+ if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
514
+ return out;
515
+ }
516
+ if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
517
+ return value;
610
518
  }
611
519
  function stringifyError(error) {
612
- try {
613
- return JSON.stringify(sanitizeValues(serializeError(error)));
614
- } catch {
615
- if (error instanceof Error) {
616
- return JSON.stringify({
617
- name: error.name,
618
- message: error.message
619
- });
620
- }
621
- return JSON.stringify({
622
- message: String(error)
623
- });
624
- }
520
+ try {
521
+ return JSON.stringify(sanitizeValues(serializeError(error)));
522
+ } catch {
523
+ if (error instanceof Error) return JSON.stringify({
524
+ name: error.name,
525
+ message: error.message
526
+ });
527
+ return JSON.stringify({ message: String(error) });
528
+ }
625
529
  }
626
530
  function truncateStack(stack) {
627
- if (!stack) {
628
- return stack;
629
- }
630
- const lines = stack.split('\n');
631
- if (lines.length <= MAX_STACK_LINES) {
632
- return stack;
633
- }
634
- return [...lines.slice(0, MAX_STACK_LINES), '... (truncated)'].join('\n');
531
+ if (!stack) return stack;
532
+ const lines = stack.split("\n");
533
+ if (lines.length <= MAX_STACK_LINES) return stack;
534
+ return [...lines.slice(0, MAX_STACK_LINES), "... (truncated)"].join("\n");
635
535
  }
636
-
637
- // Warn when a wrapper's base_url points at the PostHog AI Gateway: the gateway
638
- // emits its own $ai_generation, so each call would be captured (and, for billable
639
- // products, billed) twice. We only warn — the wrapper's event carries data the
640
- // gateway never sees (groups, custom properties, trace hierarchy).
641
-
642
- // Keep in sync with the gateway's deployed hosts (see services/llm-gateway in the
643
- // main repo). gateway.us.posthog.com is live today; the rest are listed ahead of
644
- // any traffic moving to them.
645
- const POSTHOG_AI_GATEWAY_HOSTS = ['gateway.posthog.com', 'gateway.us.posthog.com', 'gateway.eu.posthog.com', 'ai-gateway.us.posthog.com', 'ai-gateway.eu.posthog.com'];
646
-
647
- // Swap for the dedicated AI Gateway page once it ships.
648
- const GATEWAY_DOCS_URL = 'https://posthog.com/docs/ai-observability';
649
- const extractHost = baseURL => {
650
- try {
651
- // Tolerate bare hosts that omit a scheme, e.g. "gateway.us.posthog.com/v1".
652
- const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(baseURL);
653
- return new URL(hasScheme ? baseURL : `https://${baseURL}`).hostname.toLowerCase();
654
- } catch {
655
- return undefined;
656
- }
536
+ //#endregion
537
+ //#region src/gatewayWarning.ts
538
+ const POSTHOG_AI_GATEWAY_HOSTS = [
539
+ "gateway.posthog.com",
540
+ "gateway.us.posthog.com",
541
+ "gateway.eu.posthog.com",
542
+ "ai-gateway.us.posthog.com",
543
+ "ai-gateway.eu.posthog.com"
544
+ ];
545
+ const GATEWAY_DOCS_URL = "https://posthog.com/docs/ai-observability";
546
+ const extractHost = (baseURL) => {
547
+ try {
548
+ const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(baseURL);
549
+ return new URL(hasScheme ? baseURL : `https://${baseURL}`).hostname.toLowerCase();
550
+ } catch {
551
+ return;
552
+ }
657
553
  };
658
- const isPostHogAiGatewayUrl = baseURL => {
659
- if (!baseURL) {
660
- return false;
661
- }
662
- const host = extractHost(baseURL);
663
- return host !== undefined && POSTHOG_AI_GATEWAY_HOSTS.includes(host);
554
+ const isPostHogAiGatewayUrl = (baseURL) => {
555
+ if (!baseURL) return false;
556
+ const host = extractHost(baseURL);
557
+ return host !== void 0 && POSTHOG_AI_GATEWAY_HOSTS.includes(host);
664
558
  };
665
-
666
- // Warns on every gateway call by design: the misconfiguration is impossible to
667
- // miss that way, and a doubled bill is worse than noisy logs.
668
- const warnIfPostHogAiGateway = baseURL => {
669
- if (!isPostHogAiGatewayUrl(baseURL)) {
670
- return;
671
- }
672
- console.warn('[PostHog] The PostHog AI wrapper is pointed at the PostHog AI Gateway. ' + 'Both capture $ai_generation, so every call is double-counted and double-billed. ' + `Use one or the other — see ${GATEWAY_DOCS_URL}.`);
559
+ const warnIfPostHogAiGateway = (baseURL) => {
560
+ if (!isPostHogAiGatewayUrl(baseURL)) return;
561
+ console.warn(`[PostHog] The PostHog AI wrapper is pointed at the PostHog AI Gateway. Both capture \$ai_generation, so every call is double-counted and double-billed. Use one or the other see ${GATEWAY_DOCS_URL}.`);
673
562
  };
674
-
675
- /**
676
- * Options for `captureAiGeneration`. Mirrors the `$ai_generation` event shape
677
- * directly so that any caller — first-party SDK wrappers and external code
678
- * alike — produces an identical event.
679
- */
680
-
563
+ //#endregion
564
+ //#region src/captureAiGeneration.ts
681
565
  /**
682
- * Capture an `$ai_generation` (or `$ai_embedding`) event to PostHog.
683
- *
684
- * This is the canonical primitive that every `@posthog/ai` wrapper
685
- * (`withTracing`, `OpenAI`, `Anthropic`, `GoogleGenAI`, …) funnels through, so
686
- * external code can use it directly to instrument LLM calls made through
687
- * arbitrary clients (Cloudflare Workers AI, custom HTTP, etc.) and get the
688
- * same events the SDK wrappers produce.
689
- *
690
- * When `error` is set, the event is captured as an error. If the error is an
691
- * object, it is mutated in place to set `__posthog_previously_captured_error`
692
- * so callers can re-throw the original error reference safely.
693
- */
566
+ * Capture an `$ai_generation` (or `$ai_embedding`) event to PostHog.
567
+ *
568
+ * This is the canonical primitive that every `@posthog/ai` wrapper
569
+ * (`withTracing`, `OpenAI`, `Anthropic`, `GoogleGenAI`, …) funnels through, so
570
+ * external code can use it directly to instrument LLM calls made through
571
+ * arbitrary clients (Cloudflare Workers AI, custom HTTP, etc.) and get the
572
+ * same events the SDK wrappers produce.
573
+ *
574
+ * When `error` is set, the event is captured as an error. If the error is an
575
+ * object, it is mutated in place to set `__posthog_previously_captured_error`
576
+ * so callers can re-throw the original error reference safely.
577
+ */
694
578
  const captureAiGeneration$1 = async (client, options) => {
695
- try {
696
- if (!client.capture) {
697
- return;
698
- }
699
- warnIfPostHogAiGateway(options.baseURL);
700
- const traceId = options.traceId ?? uuid.v4();
701
- const eventType = options.eventType ?? AIEvent.Generation;
702
- const privacyMode = options.privacyMode ?? false;
703
- const usage = options.usage ?? {};
704
-
705
- // Check privacy before reading or traversing input/output. Besides avoiding
706
- // needless work, this ensures hostile getters/proxies cannot observe a value
707
- // that the caller explicitly requested us to redact.
708
- const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
709
- const safeInput = shouldRedact ? null : core.toJsonSafeValue(options.input);
710
- const safeOutput = shouldRedact ? null : core.toJsonSafeValue(options.output);
711
- let httpStatus = options.httpStatus;
712
- let errorData = {};
713
- if (options.error) {
714
- if (httpStatus === undefined) {
715
- if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
716
- httpStatus = options.error.status;
717
- } else if (typeof options.error === 'object' && 'statusCode' in options.error && typeof options.error.statusCode === 'number') {
718
- httpStatus = options.error.statusCode;
719
- } else {
720
- httpStatus = 500;
721
- }
722
- }
723
- let exceptionId;
724
- if (client.options?.enableExceptionAutocapture) {
725
- exceptionId = core.uuidv7();
726
- client.captureException(options.error, undefined, {
727
- $ai_trace_id: traceId
728
- }, exceptionId);
729
- if (typeof options.error === 'object') {
730
- ;
731
- options.error.__posthog_previously_captured_error = true;
732
- }
733
- }
734
- errorData = {
735
- $ai_is_error: true,
736
- $ai_error: stringifyError(options.error),
737
- $exception_event_id: exceptionId
738
- };
739
- }
740
- httpStatus = httpStatus ?? 200;
741
-
742
- // A configured price applies only to a count the provider reported, so a call with no
743
- // reported usage sends no cost instead of asserting $0. $ai_total_cost_usd sums the sides
744
- // that were priced, which makes it the cost of the known side alone when the other side
745
- // went unreported: a lower bound on the true total, not an assertion of it.
746
- const costOverrideData = {};
747
- if (options.costOverride) {
748
- if (usage.inputTokens !== undefined) {
749
- costOverrideData.$ai_input_cost_usd = (options.costOverride.inputCost ?? 0) * usage.inputTokens;
750
- }
751
- if (usage.outputTokens !== undefined) {
752
- costOverrideData.$ai_output_cost_usd = (options.costOverride.outputCost ?? 0) * usage.outputTokens;
753
- }
754
- if (Object.keys(costOverrideData).length > 0) {
755
- costOverrideData.$ai_total_cost_usd = (costOverrideData.$ai_input_cost_usd ?? 0) + (costOverrideData.$ai_output_cost_usd ?? 0);
756
- }
757
- }
758
-
759
- // The caller's own token counts override the SDK-derived ones further down, via the
760
- // `options.properties` spread.
761
- const tokensOverridden = hasTokenOverrides(options.properties);
762
- const additionalTokenValues = {
763
- ...(usage.reasoningTokens ? {
764
- $ai_reasoning_tokens: usage.reasoningTokens
765
- } : {}),
766
- ...(usage.cacheReadInputTokens ? {
767
- $ai_cache_read_input_tokens: usage.cacheReadInputTokens
768
- } : {}),
769
- ...(usage.cacheCreationInputTokens ? {
770
- $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
771
- } : {}),
772
- // Checked against undefined rather than truthiness, because false is the meaningful
773
- // value here and a truthiness guard would drop it.
774
- //
775
- // Dropped entirely when the caller overrides the token counts: the flag describes how
776
- // the SDK-derived counts relate to each other, so against passthrough counts it can be
777
- // wrong in the expensive direction. Declaring inclusive over counts that are actually
778
- // exclusive makes ingestion subtract the cache pool that was never in the input. A
779
- // caller who knows their own accounting model can still pass
780
- // `$ai_cache_reporting_exclusive` themselves, and that value wins.
781
- ...(usage.cacheReportingExclusive !== undefined && !tokensOverridden ? {
782
- $ai_cache_reporting_exclusive: usage.cacheReportingExclusive
783
- } : {}),
784
- ...(usage.webSearchCount ? {
785
- $ai_web_search_count: usage.webSearchCount
786
- } : {}),
787
- ...(usage.rawUsage ? {
788
- $ai_usage: usage.rawUsage
789
- } : {})
790
- };
791
- const properties = {
792
- $ai_lib: 'posthog-ai',
793
- $ai_lib_version: version,
794
- $ai_provider: options.providerOverride ?? options.provider,
795
- $ai_model: options.modelOverride ?? options.model,
796
- $ai_model_parameters: options.modelParameters ?? {},
797
- $ai_input: safeInput,
798
- $ai_output_choices: safeOutput,
799
- $ai_http_status: httpStatus,
800
- ...(usage.inputTokens !== undefined ? {
801
- $ai_input_tokens: usage.inputTokens
802
- } : {}),
803
- ...(usage.outputTokens !== undefined ? {
804
- $ai_output_tokens: usage.outputTokens
805
- } : {}),
806
- ...additionalTokenValues,
807
- ...(options.latency !== undefined ? {
808
- $ai_latency: options.latency
809
- } : {}),
810
- ...(options.timeToFirstToken !== undefined ? {
811
- $ai_time_to_first_token: options.timeToFirstToken
812
- } : {}),
813
- $ai_trace_id: traceId,
814
- ...(options.baseURL === null ? {} : {
815
- $ai_base_url: options.baseURL ?? ''
816
- }),
817
- ...options.properties,
818
- $ai_tokens_source: getTokensSource(options.properties),
819
- ...(options.distinctId ? {} : {
820
- $process_person_profile: false
821
- }),
822
- ...(options.stopReason ? {
823
- $ai_stop_reason: options.stopReason
824
- } : {}),
825
- ...(options.tools ? {
826
- $ai_tools: options.tools
827
- } : {}),
828
- ...(options.completionId ? {
829
- $ai_completion_id: options.completionId
830
- } : {}),
831
- ...(options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? {
832
- $ai_provider_metadata: options.providerMetadata
833
- } : {}),
834
- ...errorData,
835
- ...costOverrideData
836
- };
837
- const event = {
838
- distinctId: options.distinctId ?? traceId,
839
- event: eventType,
840
- properties,
841
- groups: options.groups
842
- };
843
- if (options.captureImmediate) {
844
- await captureAiEventImmediate(client, event);
845
- } else {
846
- captureAiEvent(client, event);
847
- }
848
- } catch (error) {
849
- // Telemetry failures must never affect the instrumented provider call.
850
- try {
851
- options.onError?.(error);
852
- } catch {
853
- // Error reporting must not affect the instrumented provider call either.
854
- }
855
- console.warn('[PostHog AI] Failed to capture generation telemetry:', error);
856
- }
579
+ try {
580
+ if (!client.capture) return;
581
+ warnIfPostHogAiGateway(options.baseURL);
582
+ const traceId = options.traceId ?? (0, uuid.v4)();
583
+ const eventType = options.eventType ?? "$ai_generation";
584
+ const privacyMode = options.privacyMode ?? false;
585
+ const usage = options.usage ?? {};
586
+ const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
587
+ const safeInput = shouldRedact ? null : (0, _posthog_core.toJsonSafeValue)(options.input);
588
+ const safeOutput = shouldRedact ? null : (0, _posthog_core.toJsonSafeValue)(options.output);
589
+ let httpStatus = options.httpStatus;
590
+ let errorData = {};
591
+ if (options.error) {
592
+ if (httpStatus === void 0) {
593
+ if (typeof options.error === "object" && "status" in options.error && typeof options.error.status === "number") httpStatus = options.error.status;
594
+ else if (typeof options.error === "object" && "statusCode" in options.error && typeof options.error.statusCode === "number") httpStatus = options.error.statusCode;
595
+ else httpStatus = 500;
596
+ }
597
+ let exceptionId;
598
+ if (client.options?.enableExceptionAutocapture) {
599
+ exceptionId = (0, _posthog_core.uuidv7)();
600
+ client.captureException(options.error, void 0, { $ai_trace_id: traceId }, exceptionId);
601
+ if (typeof options.error === "object") options.error.__posthog_previously_captured_error = true;
602
+ }
603
+ errorData = {
604
+ $ai_is_error: true,
605
+ $ai_error: stringifyError(options.error),
606
+ $exception_event_id: exceptionId
607
+ };
608
+ }
609
+ httpStatus = httpStatus ?? 200;
610
+ const costOverrideData = {};
611
+ if (options.costOverride) {
612
+ if (usage.inputTokens !== void 0) costOverrideData.$ai_input_cost_usd = (options.costOverride.inputCost ?? 0) * usage.inputTokens;
613
+ if (usage.outputTokens !== void 0) costOverrideData.$ai_output_cost_usd = (options.costOverride.outputCost ?? 0) * usage.outputTokens;
614
+ if (Object.keys(costOverrideData).length > 0) costOverrideData.$ai_total_cost_usd = (costOverrideData.$ai_input_cost_usd ?? 0) + (costOverrideData.$ai_output_cost_usd ?? 0);
615
+ }
616
+ const tokensOverridden = hasTokenOverrides(options.properties);
617
+ const additionalTokenValues = {
618
+ ...usage.reasoningTokens ? { $ai_reasoning_tokens: usage.reasoningTokens } : {},
619
+ ...usage.cacheReadInputTokens ? { $ai_cache_read_input_tokens: usage.cacheReadInputTokens } : {},
620
+ ...usage.cacheCreationInputTokens ? { $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens } : {},
621
+ ...usage.cacheReportingExclusive !== void 0 && !tokensOverridden ? { $ai_cache_reporting_exclusive: usage.cacheReportingExclusive } : {},
622
+ ...usage.webSearchCount ? { $ai_web_search_count: usage.webSearchCount } : {},
623
+ ...usage.rawUsage ? { $ai_usage: usage.rawUsage } : {}
624
+ };
625
+ const properties = {
626
+ $ai_lib: "posthog-ai",
627
+ $ai_lib_version: version,
628
+ $ai_provider: options.providerOverride ?? options.provider,
629
+ $ai_model: options.modelOverride ?? options.model,
630
+ $ai_model_parameters: options.modelParameters ?? {},
631
+ $ai_input: safeInput,
632
+ $ai_output_choices: safeOutput,
633
+ $ai_http_status: httpStatus,
634
+ ...usage.inputTokens !== void 0 ? { $ai_input_tokens: usage.inputTokens } : {},
635
+ ...usage.outputTokens !== void 0 ? { $ai_output_tokens: usage.outputTokens } : {},
636
+ ...additionalTokenValues,
637
+ ...options.latency !== void 0 ? { $ai_latency: options.latency } : {},
638
+ ...options.timeToFirstToken !== void 0 ? { $ai_time_to_first_token: options.timeToFirstToken } : {},
639
+ $ai_trace_id: traceId,
640
+ ...options.baseURL === null ? {} : { $ai_base_url: options.baseURL ?? "" },
641
+ ...options.properties,
642
+ $ai_tokens_source: getTokensSource(options.properties),
643
+ ...options.distinctId ? {} : { $process_person_profile: false },
644
+ ...options.stopReason ? { $ai_stop_reason: options.stopReason } : {},
645
+ ...options.tools ? { $ai_tools: options.tools } : {},
646
+ ...options.completionId ? { $ai_completion_id: options.completionId } : {},
647
+ ...options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? { $ai_provider_metadata: options.providerMetadata } : {},
648
+ ...errorData,
649
+ ...costOverrideData
650
+ };
651
+ const event = {
652
+ distinctId: options.distinctId ?? traceId,
653
+ event: eventType,
654
+ properties,
655
+ groups: options.groups
656
+ };
657
+ if (options.captureImmediate) await captureAiEventImmediate(client, event);
658
+ else captureAiEvent(client, event);
659
+ } catch (error) {
660
+ try {
661
+ options.onError?.(error);
662
+ } catch {}
663
+ console.warn("[PostHog AI] Failed to capture generation telemetry:", error);
664
+ }
857
665
  };
858
-
666
+ //#endregion
667
+ //#region src/openai/capture.ts
859
668
  /**
860
- * The declared convention only describes the wrapper's own usage numbers, so
861
- * when the caller passes any of these through posthogProperties the wrapper no
862
- * longer knows the convention of the reported counts (callers working around
863
- * the double-billing already pass exclusive ones) and must not declare it.
864
- * Output/reasoning token overrides don't affect the input/cache relationship,
865
- * so they don't suppress the declaration. Subset of the input/cache keys in
866
- * `TOKEN_PROPERTY_KEYS` (../utils.ts) — keep in sync if that taxonomy grows.
867
- */
868
- const INPUT_OR_CACHE_TOKEN_KEYS = ['$ai_input_tokens', '$ai_cache_read_input_tokens', '$ai_cache_creation_input_tokens'];
869
-
669
+ * The declared convention only describes the wrapper's own usage numbers, so
670
+ * when the caller passes any of these through posthogProperties the wrapper no
671
+ * longer knows the convention of the reported counts (callers working around
672
+ * the double-billing already pass exclusive ones) and must not declare it.
673
+ * Output/reasoning token overrides don't affect the input/cache relationship,
674
+ * so they don't suppress the declaration. Subset of the input/cache keys in
675
+ * `TOKEN_PROPERTY_KEYS` (../utils.ts) — keep in sync if that taxonomy grows.
676
+ */
677
+ const INPUT_OR_CACHE_TOKEN_KEYS = [
678
+ "$ai_input_tokens",
679
+ "$ai_cache_read_input_tokens",
680
+ "$ai_cache_creation_input_tokens"
681
+ ];
870
682
  /**
871
- * OpenAI-compatible usage reports `prompt_tokens` INCLUSIVE of cached tokens
872
- * (`prompt_tokens_details.cached_tokens` is a subset of it), unlike Anthropic's
873
- * exclusive convention. Ingestion auto-classifies Claude-shaped models as
874
- * exclusive regardless of provider, so events for Claude served through
875
- * OpenAI-compatible hosts (e.g. OpenRouter) would get cache reads billed twice.
876
- * Declaring the convention on every event from this wrapper lets ingestion
877
- * normalize correctly (see PostHog/posthog#49252); for non-Claude models the
878
- * flag is a no-op. Callers can still override it via posthogProperties, and
879
- * when they pass through input or cache token counts themselves the flag stays
880
- * unset unless they declare it explicitly.
881
- */
683
+ * OpenAI-compatible usage reports `prompt_tokens` INCLUSIVE of cached tokens
684
+ * (`prompt_tokens_details.cached_tokens` is a subset of it), unlike Anthropic's
685
+ * exclusive convention. Ingestion auto-classifies Claude-shaped models as
686
+ * exclusive regardless of provider, so events for Claude served through
687
+ * OpenAI-compatible hosts (e.g. OpenRouter) would get cache reads billed twice.
688
+ * Declaring the convention on every event from this wrapper lets ingestion
689
+ * normalize correctly (see PostHog/posthog#49252); for non-Claude models the
690
+ * flag is a no-op. Callers can still override it via posthogProperties, and
691
+ * when they pass through input or cache token counts themselves the flag stays
692
+ * unset unless they declare it explicitly.
693
+ */
882
694
  const captureAiGeneration = (client, options) => {
883
- const props = options.properties;
884
- // Own-property check, matching how getTokensSource detects passthrough and
885
- // how the properties spread actually copies values into the event.
886
- const callerReportsTokens = props !== undefined && INPUT_OR_CACHE_TOKEN_KEYS.some(key => Object.prototype.hasOwnProperty.call(props, key));
887
- return captureAiGeneration$1(client, {
888
- ...options,
889
- properties: callerReportsTokens ? props : {
890
- $ai_cache_reporting_exclusive: false,
891
- ...props
892
- }
893
- });
695
+ const props = options.properties;
696
+ const callerReportsTokens = props !== void 0 && INPUT_OR_CACHE_TOKEN_KEYS.some((key) => Object.prototype.hasOwnProperty.call(props, key));
697
+ return captureAiGeneration$1(client, {
698
+ ...options,
699
+ properties: callerReportsTokens ? props : {
700
+ $ai_cache_reporting_exclusive: false,
701
+ ...props
702
+ }
703
+ });
894
704
  };
895
-
705
+ //#endregion
706
+ //#region src/openai/utils.ts
896
707
  /**
897
- * Checks if a ResponseStreamEvent chunk represents the first token/content from the model.
898
- * This includes various content types like text, reasoning, audio, and refusals.
899
- */
708
+ * Checks if a ResponseStreamEvent chunk represents the first token/content from the model.
709
+ * This includes various content types like text, reasoning, audio, and refusals.
710
+ */
900
711
  function isResponseTokenChunk(chunk) {
901
- return chunk.type === 'response.output_item.added' || chunk.type === 'response.content_part.added' || chunk.type === 'response.output_text.delta' || chunk.type === 'response.reasoning_text.delta' || chunk.type === 'response.reasoning_summary_text.delta' || chunk.type === 'response.audio.delta' || chunk.type === 'response.audio.transcript.delta' || chunk.type === 'response.refusal.delta';
712
+ return chunk.type === "response.output_item.added" || chunk.type === "response.content_part.added" || chunk.type === "response.output_text.delta" || chunk.type === "response.reasoning_text.delta" || chunk.type === "response.reasoning_summary_text.delta" || chunk.type === "response.audio.delta" || chunk.type === "response.audio.transcript.delta" || chunk.type === "response.refusal.delta";
902
713
  }
903
-
904
714
  /**
905
- * Reads the OpenAI SDK's `_request_id` field from a response object. The SDK
906
- * attaches the `x-request-id` response header here, but it is not part of the
907
- * public response types, so it has to be read through a cast. Used to populate
908
- * `$ai_provider_metadata.request_id`.
909
- */
715
+ * Reads the OpenAI SDK's `_request_id` field from a response object. The SDK
716
+ * attaches the `x-request-id` response header here, but it is not part of the
717
+ * public response types, so it has to be read through a cast. Used to populate
718
+ * `$ai_provider_metadata.request_id`.
719
+ */
910
720
  function extractRequestId(result) {
911
- return result?._request_id ?? undefined;
721
+ return result?._request_id ?? void 0;
912
722
  }
913
-
914
723
  /**
915
- * Reads `cache_write_tokens` from a usage details object — Chat Completions'
916
- * `prompt_tokens_details` or the Responses API's `input_tokens_details`, both of
917
- * which carry the field — and returns 0 when it is absent. A defensive reader
918
- * (mirroring `extractRequestId`) that tolerates the loosely-typed usage shapes
919
- * OpenAI-compatible providers return, used to populate
920
- * `$ai_cache_creation_input_tokens`.
921
- */
724
+ * Reads `cache_write_tokens` from a usage details object — Chat Completions'
725
+ * `prompt_tokens_details` or the Responses API's `input_tokens_details`, both of
726
+ * which carry the field — and returns 0 when it is absent. A defensive reader
727
+ * (mirroring `extractRequestId`) that tolerates the loosely-typed usage shapes
728
+ * OpenAI-compatible providers return, used to populate
729
+ * `$ai_cache_creation_input_tokens`.
730
+ */
922
731
  function extractCacheWriteTokens(details) {
923
- return details?.cache_write_tokens ?? 0;
732
+ return details?.cache_write_tokens ?? 0;
924
733
  }
925
-
926
734
  /**
927
- * Assembles the `$ai_provider_metadata` blob for OpenAI / Azure OpenAI events.
928
- * Provider-specific fields (system fingerprint, request id) live here rather
929
- * than in the shared, provider-agnostic `$ai_*` namespace. Only keys with a
930
- * meaningful value are included, and `undefined` is returned when there is nothing
931
- * to report so the property can be omitted from the event entirely.
932
- */
735
+ * Assembles the `$ai_provider_metadata` blob for OpenAI / Azure OpenAI events.
736
+ * Provider-specific fields (system fingerprint, request id) live here rather
737
+ * than in the shared, provider-agnostic `$ai_*` namespace. Only keys with a
738
+ * meaningful value are included, and `undefined` is returned when there is nothing
739
+ * to report so the property can be omitted from the event entirely.
740
+ */
933
741
  function buildProviderMetadata(fields) {
934
- const metadata = {};
935
- if (fields.systemFingerprint) {
936
- metadata.system_fingerprint = fields.systemFingerprint;
937
- }
938
- if (fields.requestId) {
939
- metadata.request_id = fields.requestId;
940
- }
941
- if (fields.incompleteDetails != null) {
942
- metadata.incomplete_details = fields.incompleteDetails;
943
- }
944
- return Object.keys(metadata).length > 0 ? metadata : undefined;
742
+ const metadata = {};
743
+ if (fields.systemFingerprint) metadata.system_fingerprint = fields.systemFingerprint;
744
+ if (fields.requestId) metadata.request_id = fields.requestId;
745
+ if (fields.incompleteDetails != null) metadata.incomplete_details = fields.incompleteDetails;
746
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
945
747
  }
946
- const TERMINAL_RESPONSE_STATUSES = new Set(['completed', 'failed', 'cancelled', 'incomplete']);
947
-
748
+ const TERMINAL_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
749
+ "completed",
750
+ "failed",
751
+ "cancelled",
752
+ "incomplete"
753
+ ]);
948
754
  /**
949
- * Checks whether a Responses API response has reached a status that should
950
- * produce a final `$ai_generation` event.
951
- */
755
+ * Checks whether a Responses API response has reached a status that should
756
+ * produce a final `$ai_generation` event.
757
+ */
952
758
  function isTerminalResponse(response) {
953
- return !!response?.status && TERMINAL_RESPONSE_STATUSES.has(response.status);
759
+ return !!response?.status && TERMINAL_RESPONSE_STATUSES.has(response.status);
760
+ }
761
+ /**
762
+ * Maps a Responses API outcome to a `$ai_stop_reason`. An incomplete run is
763
+ * named by what cut it short (`incomplete_details.reason`, e.g.
764
+ * `max_output_tokens`); the other terminal statuses stand for themselves.
765
+ * Non-terminal lifecycle statuses (`queued`, `in_progress`) are not stop
766
+ * reasons, so they yield undefined.
767
+ */
768
+ function responsesStopReason(response) {
769
+ if (!response || !isTerminalResponse(response)) return;
770
+ if (response.status === "incomplete" && response.incomplete_details?.reason) return response.incomplete_details.reason;
771
+ return response.status ?? void 0;
954
772
  }
955
-
956
773
  /**
957
- * Returns an isolated copy of a failed Responses API error for `$ai_error`, or
958
- * creates a fallback error when the provider omitted failure details.
959
- */
774
+ * Returns an isolated copy of a failed Responses API error for `$ai_error`, or
775
+ * creates a fallback error when the provider omitted failure details.
776
+ */
960
777
  function getResponseFailure(response) {
961
- if (response?.status !== 'failed') {
962
- return undefined;
963
- }
964
- return response.error ? {
965
- ...response.error
966
- } : new Error(`OpenAI response ${response.id} failed without error details`);
778
+ if (response?.status !== "failed") return;
779
+ return response.error ? { ...response.error } : /* @__PURE__ */ new Error(`OpenAI response ${response.id} failed without error details`);
967
780
  }
968
-
781
+ //#endregion
782
+ //#region src/openai/background-responses.ts
969
783
  function isPendingBackgroundResponse(params, response) {
970
- return params.background === true && !!response.status && !isTerminalResponse(response);
784
+ return params.background === true && !!response.status && !isTerminalResponse(response);
971
785
  }
972
-
973
786
  /**
974
- * Uses provider timestamps so background polling cadence does not inflate
975
- * generation latency. Non-completed responses do not expose a terminal time.
976
- */
787
+ * Uses provider timestamps so background polling cadence does not inflate
788
+ * generation latency. Non-completed responses do not expose a terminal time.
789
+ */
977
790
  function getBackgroundResponseLatency(response) {
978
- if (typeof response.created_at !== 'number' || typeof response.completed_at !== 'number') {
979
- return undefined;
980
- }
981
- return Math.max(0, response.completed_at - response.created_at);
791
+ if (typeof response.created_at !== "number" || typeof response.completed_at !== "number") return;
792
+ return Math.max(0, response.completed_at - response.created_at);
982
793
  }
983
-
984
794
  /**
985
- * Keeps the original create context available while a background response is
986
- * polled. Entries are insertion ordered, so the oldest context is discarded
987
- * when the bound is reached.
988
- */
989
- class BackgroundResponseTracker {
990
- contexts = new Map();
991
- constructor(maxEntries = 1000) {
992
- this.maxEntries = maxEntries;
993
- }
994
- set(responseID, context) {
995
- // Refresh an existing response's insertion order.
996
- this.contexts.delete(responseID);
997
- this.contexts.set(responseID, context);
998
- while (this.contexts.size > this.maxEntries) {
999
- const oldestResponseID = this.contexts.keys().next().value;
1000
- if (oldestResponseID === undefined) {
1001
- break;
1002
- }
1003
- this.contexts.delete(oldestResponseID);
1004
- }
1005
- }
1006
- get(responseID) {
1007
- return this.contexts.get(responseID);
1008
- }
1009
- take(responseID) {
1010
- const context = this.contexts.get(responseID);
1011
- if (context !== undefined) {
1012
- this.contexts.delete(responseID);
1013
- }
1014
- return context;
1015
- }
1016
- }
1017
-
795
+ * Keeps the original create context available while a background response is
796
+ * polled. Entries are insertion ordered, so the oldest context is discarded
797
+ * when the bound is reached.
798
+ */
799
+ var BackgroundResponseTracker = class {
800
+ constructor(maxEntries = 1e3) {
801
+ this.maxEntries = maxEntries;
802
+ this.contexts = /* @__PURE__ */ new Map();
803
+ }
804
+ set(responseID, context) {
805
+ this.contexts.delete(responseID);
806
+ this.contexts.set(responseID, context);
807
+ while (this.contexts.size > this.maxEntries) {
808
+ const oldestResponseID = this.contexts.keys().next().value;
809
+ if (oldestResponseID === void 0) break;
810
+ this.contexts.delete(oldestResponseID);
811
+ }
812
+ }
813
+ get(responseID) {
814
+ return this.contexts.get(responseID);
815
+ }
816
+ take(responseID) {
817
+ const context = this.contexts.get(responseID);
818
+ if (context !== void 0) this.contexts.delete(responseID);
819
+ return context;
820
+ }
821
+ };
1018
822
  /**
1019
- * Inspects a streamed background retrieval without consuming it on the
1020
- * caller's behalf. The stored create context is consumed only by a terminal
1021
- * response; an interrupted or nonterminal stream may be followed by another
1022
- * retrieval while the background job continues.
1023
- */
823
+ * Inspects a streamed background retrieval without consuming it on the
824
+ * caller's behalf. The stored create context is consumed only by a terminal
825
+ * response; an interrupted or nonterminal stream may be followed by another
826
+ * retrieval while the background job continues.
827
+ */
1024
828
  function wrapBackgroundResponseStream(stream, responseID, tracker, captureTerminalResponse) {
1025
- async function* inspectStream() {
1026
- for await (const event of stream) {
1027
- if ('response' in event && isTerminalResponse(event.response)) {
1028
- const context = tracker.take(responseID);
1029
- if (context) {
1030
- // Monitoring must not delay or disrupt delivery of the provider stream.
1031
- void captureTerminalResponse(event.response, context).catch(() => undefined);
1032
- }
1033
- }
1034
- yield event;
1035
- }
1036
- }
1037
- return new streaming.Stream(() => inspectStream(), stream.controller);
829
+ async function* inspectStream() {
830
+ for await (const event of stream) {
831
+ if ("response" in event && isTerminalResponse(event.response)) {
832
+ const context = tracker.take(responseID);
833
+ if (context) captureTerminalResponse(event.response, context).catch(() => void 0);
834
+ }
835
+ yield event;
836
+ }
837
+ }
838
+ return new openai_streaming.Stream(() => inspectStream(), stream.controller);
1038
839
  }
1039
-
840
+ //#endregion
841
+ //#region src/providerPromise.ts
1040
842
  function addResponseIds(result, response, requestIdHeader, workspaceIdHeader) {
1041
- if (!result || typeof result !== 'object' || Array.isArray(result)) {
1042
- return result;
1043
- }
1044
- const properties = {
1045
- _request_id: {
1046
- value: response.headers.get(requestIdHeader),
1047
- enumerable: false
1048
- }
1049
- };
1050
- if (workspaceIdHeader) {
1051
- properties._workspace_id = {
1052
- value: response.headers.get(workspaceIdHeader),
1053
- enumerable: false
1054
- };
1055
- }
1056
- return Object.defineProperties(result, properties);
843
+ if (!result || typeof result !== "object" || Array.isArray(result)) return result;
844
+ const properties = { _request_id: {
845
+ value: response.headers.get(requestIdHeader),
846
+ enumerable: false
847
+ } };
848
+ if (workspaceIdHeader) properties._workspace_id = {
849
+ value: response.headers.get(workspaceIdHeader),
850
+ enumerable: false
851
+ };
852
+ return Object.defineProperties(result, properties);
1057
853
  }
1058
854
  function getResponsePropsPromise(parentPromise) {
1059
- const responsePromise = parentPromise.responsePromise;
1060
- if (!responsePromise || typeof responsePromise.then !== 'function') {
1061
- return undefined;
1062
- }
1063
- return responsePromise;
855
+ const responsePromise = parentPromise.responsePromise;
856
+ if (!responsePromise || typeof responsePromise.then !== "function") return;
857
+ return responsePromise;
1064
858
  }
1065
859
  function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestIdHeader, workspaceIdHeader, preserveThenUnwrap) {
1066
- const providerPromise = wrappedPromise;
1067
- if (responsePropsPromise) {
1068
- providerPromise.asResponse = async () => (await responsePropsPromise).response;
1069
- providerPromise.withResponse = async () => {
1070
- const [props, data] = await Promise.all([responsePropsPromise, wrappedPromise]);
1071
- return {
1072
- response: props.response,
1073
- data,
1074
- request_id: props.response.headers.get(requestIdHeader),
1075
- ...(workspaceIdHeader ? {
1076
- workspace_id: props.response.headers.get(workspaceIdHeader)
1077
- } : {})
1078
- };
1079
- };
1080
- }
1081
- if (preserveThenUnwrap) {
1082
- providerPromise._thenUnwrap = transform => {
1083
- if (!responsePropsPromise) {
1084
- throw new Error('The provider promise response metadata is unavailable');
1085
- }
1086
- const transformedPromise = Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addResponseIds(transform(data, props), props.response, requestIdHeader, workspaceIdHeader));
1087
- return decorateProviderPromise(transformedPromise, responsePropsPromise, requestIdHeader, workspaceIdHeader, true);
1088
- };
1089
- }
1090
- return providerPromise;
860
+ const providerPromise = wrappedPromise;
861
+ if (responsePropsPromise) {
862
+ providerPromise.asResponse = async () => (await responsePropsPromise).response;
863
+ providerPromise.withResponse = async () => {
864
+ const [props, data] = await Promise.all([responsePropsPromise, wrappedPromise]);
865
+ return {
866
+ response: props.response,
867
+ data,
868
+ request_id: props.response.headers.get(requestIdHeader),
869
+ ...workspaceIdHeader ? { workspace_id: props.response.headers.get(workspaceIdHeader) } : {}
870
+ };
871
+ };
872
+ }
873
+ if (preserveThenUnwrap) providerPromise._thenUnwrap = (transform) => {
874
+ if (!responsePropsPromise) throw new Error("The provider promise response metadata is unavailable");
875
+ return decorateProviderPromise(Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addResponseIds(transform(data, props), props.response, requestIdHeader, workspaceIdHeader)), responsePropsPromise, requestIdHeader, workspaceIdHeader, true);
876
+ };
877
+ return providerPromise;
1091
878
  }
1092
-
1093
- /**
1094
- * Keep the provider SDK helpers on a promise whose resolved value is instrumented.
1095
- * OpenAI's parse helpers compose create calls through `_thenUnwrap`, while both
1096
- * OpenAI and Anthropic expose the raw response through `asResponse` and
1097
- * `withResponse`.
1098
- */
1099
-
1100
879
  function preserveProviderPromise(parentPromise, wrappedPromise, options = {}) {
1101
- const responsePropsPromise = getResponsePropsPromise(parentPromise);
1102
- const preserveThenUnwrap = typeof parentPromise._thenUnwrap === 'function';
1103
- const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? 'x-request-id', options.workspaceIdHeader, preserveThenUnwrap);
1104
- if (!responsePropsPromise) {
1105
- const asResponse = parentPromise.asResponse?.bind(parentPromise);
1106
- if (asResponse) {
1107
- providerPromise.asResponse = asResponse;
1108
- }
1109
- const withResponse = parentPromise.withResponse?.bind(parentPromise);
1110
- if (withResponse) {
1111
- providerPromise.withResponse = async () => {
1112
- const [response, data] = await Promise.all([withResponse(), wrappedPromise]);
1113
- return {
1114
- ...response,
1115
- data
1116
- };
1117
- };
1118
- }
1119
- }
1120
- return providerPromise;
880
+ const responsePropsPromise = getResponsePropsPromise(parentPromise);
881
+ const preserveThenUnwrap = typeof parentPromise._thenUnwrap === "function";
882
+ const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? "x-request-id", options.workspaceIdHeader, preserveThenUnwrap);
883
+ if (!responsePropsPromise) {
884
+ const asResponse = parentPromise.asResponse?.bind(parentPromise);
885
+ if (asResponse) providerPromise.asResponse = asResponse;
886
+ const withResponse = parentPromise.withResponse?.bind(parentPromise);
887
+ if (withResponse) providerPromise.withResponse = async () => {
888
+ const [response, data] = await Promise.all([withResponse(), wrappedPromise]);
889
+ return {
890
+ ...response,
891
+ data
892
+ };
893
+ };
894
+ }
895
+ return providerPromise;
1121
896
  }
1122
-
1123
897
  /**
1124
- * OpenAI's `Responses.parse` dispatches through `this._client.responses.create`.
1125
- * Temporarily use the provider's original `create` implementation so parsing a
1126
- * wrapped response does not capture the same request twice.
1127
- */
898
+ * OpenAI's `Responses.parse` dispatches through `this._client.responses.create`.
899
+ * Temporarily use the provider's original `create` implementation so parsing a
900
+ * wrapped response does not capture the same request twice.
901
+ */
1128
902
  function callWithOriginalCreate(resource, originalCreate, callback) {
1129
- const resourceRecord = resource;
1130
- const hadOwnCreate = Object.prototype.hasOwnProperty.call(resource, 'create');
1131
- const wrappedCreate = resourceRecord['create'];
1132
- resourceRecord['create'] = originalCreate;
1133
- try {
1134
- return callback();
1135
- } finally {
1136
- if (hadOwnCreate) {
1137
- resourceRecord['create'] = wrappedCreate;
1138
- } else {
1139
- delete resourceRecord['create'];
1140
- }
1141
- }
903
+ const resourceRecord = resource;
904
+ const hadOwnCreate = Object.prototype.hasOwnProperty.call(resource, "create");
905
+ const wrappedCreate = resourceRecord["create"];
906
+ resourceRecord["create"] = originalCreate;
907
+ try {
908
+ return callback();
909
+ } finally {
910
+ if (hadOwnCreate) resourceRecord["create"] = wrappedCreate;
911
+ else delete resourceRecord["create"];
912
+ }
1142
913
  }
1143
-
914
+ //#endregion
915
+ //#region src/stream.ts
1144
916
  /**
1145
- * Splits an SDK stream into a monitoring branch and a caller branch without
1146
- * allowing either branch to read ahead of the other. Unlike the SDKs' `tee()`
1147
- * implementations, this keeps at most one result in flight and makes caller
1148
- * cancellation terminate the monitoring branch and the source iterator.
1149
- */
917
+ * Splits an SDK stream into a monitoring branch and a caller branch without
918
+ * allowing either branch to read ahead of the other. Unlike the SDKs' `tee()`
919
+ * implementations, this keeps at most one result in flight and makes caller
920
+ * cancellation terminate the monitoring branch and the source iterator.
921
+ */
1150
922
  function monitoredStreamTee(source, createStream) {
1151
- const controller = source.controller ?? new AbortController();
1152
- const sourceIterator = source[Symbol.asyncIterator]();
1153
- const callerQueue = [];
1154
- let monitorPending;
1155
- let monitorActive = true;
1156
- let operationInFlight = false;
1157
- let terminalResult;
1158
- let bufferedMonitorResult;
1159
- let terminalError;
1160
- let hasTerminalError = false;
1161
- let cancellationPromise;
1162
- let abortListener;
1163
- const removeAbortListener = () => {
1164
- if (abortListener) {
1165
- controller.signal.removeEventListener('abort', abortListener);
1166
- abortListener = undefined;
1167
- }
1168
- };
1169
- const settleMonitorTerminal = () => {
1170
- if (!monitorPending) {
1171
- return;
1172
- }
1173
- const pending = monitorPending;
1174
- monitorPending = undefined;
1175
- if (hasTerminalError) {
1176
- pending.reject(terminalError);
1177
- } else if (terminalResult) {
1178
- pending.resolve(terminalResult);
1179
- }
1180
- };
1181
- const settleCallersTerminal = () => {
1182
- while (callerQueue.length > 0) {
1183
- const pending = callerQueue.shift();
1184
- if (hasTerminalError) {
1185
- pending.reject(terminalError);
1186
- } else if (terminalResult) {
1187
- pending.resolve(terminalResult);
1188
- }
1189
- }
1190
- };
1191
- const pump = () => {
1192
- if (operationInFlight || callerQueue.length === 0 || monitorActive && !monitorPending) {
1193
- return;
1194
- }
1195
- const pendingCaller = callerQueue.shift();
1196
- const pendingMonitor = monitorPending;
1197
- monitorPending = undefined;
1198
- operationInFlight = true;
1199
- void sourceIterator.next().then(result => {
1200
- operationInFlight = false;
1201
- if (result.done) {
1202
- terminalResult = result;
1203
- removeAbortListener();
1204
- }
1205
- pendingCaller.resolve(result);
1206
- pendingMonitor?.resolve(result);
1207
- if (result.done) {
1208
- settleCallersTerminal();
1209
- } else {
1210
- pump();
1211
- }
1212
- }, error => {
1213
- operationInFlight = false;
1214
- terminalError = error;
1215
- hasTerminalError = true;
1216
- removeAbortListener();
1217
- pendingCaller.reject(error);
1218
- pendingMonitor?.reject(error);
1219
- settleCallersTerminal();
1220
- });
1221
- };
1222
- const monitoringStream = {
1223
- [Symbol.asyncIterator]() {
1224
- return {
1225
- next: () => {
1226
- if (hasTerminalError) {
1227
- return Promise.reject(terminalError);
1228
- }
1229
- if (terminalResult) {
1230
- return Promise.resolve(terminalResult);
1231
- }
1232
- if (bufferedMonitorResult) {
1233
- const result = bufferedMonitorResult;
1234
- bufferedMonitorResult = undefined;
1235
- return Promise.resolve(result);
1236
- }
1237
- return new Promise((resolve, reject) => {
1238
- monitorPending = {
1239
- resolve,
1240
- reject
1241
- };
1242
- pump();
1243
- });
1244
- },
1245
- return: async value => {
1246
- monitorActive = false;
1247
- monitorPending = undefined;
1248
- pump();
1249
- return {
1250
- done: true,
1251
- value: value
1252
- };
1253
- }
1254
- };
1255
- }
1256
- };
1257
- const cancelSource = value => {
1258
- if (cancellationPromise) {
1259
- return cancellationPromise;
1260
- }
1261
- removeAbortListener();
1262
- if (!controller.signal.aborted) {
1263
- controller.abort();
1264
- }
1265
- cancellationPromise = (async () => {
1266
- try {
1267
- const defaultResult = {
1268
- done: true,
1269
- value
1270
- };
1271
- const result = sourceIterator.return ? await sourceIterator.return(value) : defaultResult;
1272
- if (result.done) {
1273
- terminalResult = result;
1274
- removeAbortListener();
1275
- settleMonitorTerminal();
1276
- settleCallersTerminal();
1277
- } else if (monitorPending) {
1278
- monitorPending.resolve(result);
1279
- monitorPending = undefined;
1280
- cancellationPromise = undefined;
1281
- } else {
1282
- bufferedMonitorResult = result;
1283
- cancellationPromise = undefined;
1284
- }
1285
- return result;
1286
- } catch (error) {
1287
- terminalError = error;
1288
- hasTerminalError = true;
1289
- removeAbortListener();
1290
- settleMonitorTerminal();
1291
- settleCallersTerminal();
1292
- throw error;
1293
- }
1294
- })();
1295
- // An AbortController cancellation has no caller awaiting this promise.
1296
- void cancellationPromise.catch(() => undefined);
1297
- return cancellationPromise;
1298
- };
1299
- abortListener = () => {
1300
- void cancelSource();
1301
- };
1302
- if (controller.signal.aborted) {
1303
- abortListener();
1304
- } else {
1305
- controller.signal.addEventListener('abort', abortListener, {
1306
- once: true
1307
- });
1308
- }
1309
- const callerStream = createStream(() => ({
1310
- next: () => {
1311
- if (hasTerminalError) {
1312
- return Promise.reject(terminalError);
1313
- }
1314
- if (terminalResult) {
1315
- return Promise.resolve(terminalResult);
1316
- }
1317
- return new Promise((resolve, reject) => {
1318
- callerQueue.push({
1319
- resolve,
1320
- reject
1321
- });
1322
- pump();
1323
- });
1324
- },
1325
- return: value => cancelSource(value),
1326
- throw: async error => {
1327
- if (!sourceIterator.throw) {
1328
- await cancelSource();
1329
- throw error;
1330
- }
1331
- try {
1332
- const result = await sourceIterator.throw(error);
1333
- if (result.done) {
1334
- terminalResult = result;
1335
- removeAbortListener();
1336
- settleCallersTerminal();
1337
- }
1338
- if (monitorPending) {
1339
- monitorPending.resolve(result);
1340
- monitorPending = undefined;
1341
- } else {
1342
- bufferedMonitorResult = result;
1343
- }
1344
- return result;
1345
- } catch (sourceError) {
1346
- terminalError = sourceError;
1347
- hasTerminalError = true;
1348
- removeAbortListener();
1349
- settleMonitorTerminal();
1350
- settleCallersTerminal();
1351
- throw sourceError;
1352
- }
1353
- }
1354
- }), controller);
1355
- return [monitoringStream, callerStream];
923
+ const controller = source.controller ?? new AbortController();
924
+ const sourceIterator = source[Symbol.asyncIterator]();
925
+ const callerQueue = [];
926
+ let monitorPending;
927
+ let monitorActive = true;
928
+ let operationInFlight = false;
929
+ let terminalResult;
930
+ let bufferedMonitorResult;
931
+ let terminalError;
932
+ let hasTerminalError = false;
933
+ let cancellationPromise;
934
+ let abortListener;
935
+ const removeAbortListener = () => {
936
+ if (abortListener) {
937
+ controller.signal.removeEventListener("abort", abortListener);
938
+ abortListener = void 0;
939
+ }
940
+ };
941
+ const settleMonitorTerminal = () => {
942
+ if (!monitorPending) return;
943
+ const pending = monitorPending;
944
+ monitorPending = void 0;
945
+ if (hasTerminalError) pending.reject(terminalError);
946
+ else if (terminalResult) pending.resolve(terminalResult);
947
+ };
948
+ const settleCallersTerminal = () => {
949
+ while (callerQueue.length > 0) {
950
+ const pending = callerQueue.shift();
951
+ if (hasTerminalError) pending.reject(terminalError);
952
+ else if (terminalResult) pending.resolve(terminalResult);
953
+ }
954
+ };
955
+ const pump = () => {
956
+ if (operationInFlight || callerQueue.length === 0 || monitorActive && !monitorPending) return;
957
+ const pendingCaller = callerQueue.shift();
958
+ const pendingMonitor = monitorPending;
959
+ monitorPending = void 0;
960
+ operationInFlight = true;
961
+ sourceIterator.next().then((result) => {
962
+ operationInFlight = false;
963
+ if (result.done) {
964
+ terminalResult = result;
965
+ removeAbortListener();
966
+ }
967
+ pendingCaller.resolve(result);
968
+ pendingMonitor?.resolve(result);
969
+ if (result.done) settleCallersTerminal();
970
+ else pump();
971
+ }, (error) => {
972
+ operationInFlight = false;
973
+ terminalError = error;
974
+ hasTerminalError = true;
975
+ removeAbortListener();
976
+ pendingCaller.reject(error);
977
+ pendingMonitor?.reject(error);
978
+ settleCallersTerminal();
979
+ });
980
+ };
981
+ const monitoringStream = { [Symbol.asyncIterator]() {
982
+ return {
983
+ next: () => {
984
+ if (hasTerminalError) return Promise.reject(terminalError);
985
+ if (terminalResult) return Promise.resolve(terminalResult);
986
+ if (bufferedMonitorResult) {
987
+ const result = bufferedMonitorResult;
988
+ bufferedMonitorResult = void 0;
989
+ return Promise.resolve(result);
990
+ }
991
+ return new Promise((resolve, reject) => {
992
+ monitorPending = {
993
+ resolve,
994
+ reject
995
+ };
996
+ pump();
997
+ });
998
+ },
999
+ return: async (value) => {
1000
+ monitorActive = false;
1001
+ monitorPending = void 0;
1002
+ pump();
1003
+ return {
1004
+ done: true,
1005
+ value
1006
+ };
1007
+ }
1008
+ };
1009
+ } };
1010
+ const cancelSource = (value) => {
1011
+ if (cancellationPromise) return cancellationPromise;
1012
+ removeAbortListener();
1013
+ if (!controller.signal.aborted) controller.abort();
1014
+ cancellationPromise = (async () => {
1015
+ try {
1016
+ const defaultResult = {
1017
+ done: true,
1018
+ value
1019
+ };
1020
+ const result = sourceIterator.return ? await sourceIterator.return(value) : defaultResult;
1021
+ if (result.done) {
1022
+ terminalResult = result;
1023
+ removeAbortListener();
1024
+ settleMonitorTerminal();
1025
+ settleCallersTerminal();
1026
+ } else if (monitorPending) {
1027
+ monitorPending.resolve(result);
1028
+ monitorPending = void 0;
1029
+ cancellationPromise = void 0;
1030
+ } else {
1031
+ bufferedMonitorResult = result;
1032
+ cancellationPromise = void 0;
1033
+ }
1034
+ return result;
1035
+ } catch (error) {
1036
+ terminalError = error;
1037
+ hasTerminalError = true;
1038
+ removeAbortListener();
1039
+ settleMonitorTerminal();
1040
+ settleCallersTerminal();
1041
+ throw error;
1042
+ }
1043
+ })();
1044
+ cancellationPromise.catch(() => void 0);
1045
+ return cancellationPromise;
1046
+ };
1047
+ abortListener = () => {
1048
+ cancelSource();
1049
+ };
1050
+ if (controller.signal.aborted) abortListener();
1051
+ else controller.signal.addEventListener("abort", abortListener, { once: true });
1052
+ return [monitoringStream, createStream(() => ({
1053
+ next: () => {
1054
+ if (hasTerminalError) return Promise.reject(terminalError);
1055
+ if (terminalResult) return Promise.resolve(terminalResult);
1056
+ return new Promise((resolve, reject) => {
1057
+ callerQueue.push({
1058
+ resolve,
1059
+ reject
1060
+ });
1061
+ pump();
1062
+ });
1063
+ },
1064
+ return: (value) => cancelSource(value),
1065
+ throw: async (error) => {
1066
+ if (!sourceIterator.throw) {
1067
+ await cancelSource();
1068
+ throw error;
1069
+ }
1070
+ try {
1071
+ const result = await sourceIterator.throw(error);
1072
+ if (result.done) {
1073
+ terminalResult = result;
1074
+ removeAbortListener();
1075
+ settleCallersTerminal();
1076
+ }
1077
+ if (monitorPending) {
1078
+ monitorPending.resolve(result);
1079
+ monitorPending = void 0;
1080
+ } else bufferedMonitorResult = result;
1081
+ return result;
1082
+ } catch (sourceError) {
1083
+ terminalError = sourceError;
1084
+ hasTerminalError = true;
1085
+ removeAbortListener();
1086
+ settleMonitorTerminal();
1087
+ settleCallersTerminal();
1088
+ throw sourceError;
1089
+ }
1090
+ }
1091
+ }), controller)];
1356
1092
  }
1357
-
1093
+ //#endregion
1094
+ //#region src/openai/stream-accumulators.ts
1358
1095
  /** Pure state accumulator for OpenAI-compatible Chat Completions chunks. */
1359
- class OpenAIChatStreamAccumulator {
1360
- accumulatedContent = '';
1361
- usage = {
1362
- webSearchCount: 0
1363
- };
1364
- toolCalls = new Map();
1365
- consume(chunk, receivedAt = Date.now()) {
1366
- this.model ||= chunk.model || undefined;
1367
- this.completionId ||= chunk.id || undefined;
1368
- this.systemFingerprint ||= chunk.system_fingerprint || undefined;
1369
- if (chunk.service_tier != null) {
1370
- this.serviceTier = chunk.service_tier;
1371
- }
1372
- const choice = chunk.choices?.[0];
1373
- if (choice?.finish_reason) {
1374
- this.stopReason = choice.finish_reason;
1375
- }
1376
- const webSearchCount = calculateWebSearchCount(chunk);
1377
- if (webSearchCount > (this.usage.webSearchCount ?? 0)) {
1378
- this.usage.webSearchCount = webSearchCount;
1379
- }
1380
- if (choice?.delta?.content) {
1381
- this.firstTokenTime ??= receivedAt;
1382
- this.accumulatedContent += choice.delta.content;
1383
- }
1384
- if (Array.isArray(choice?.delta?.tool_calls)) {
1385
- this.firstTokenTime ??= receivedAt;
1386
- for (const toolCall of choice.delta.tool_calls) {
1387
- if (toolCall.index === undefined) {
1388
- continue;
1389
- }
1390
- const current = this.toolCalls.get(toolCall.index) ?? {
1391
- id: '',
1392
- name: '',
1393
- arguments: ''
1394
- };
1395
- if (toolCall.id) {
1396
- current.id = toolCall.id;
1397
- }
1398
- if (toolCall.function?.name) {
1399
- current.name = toolCall.function.name;
1400
- }
1401
- if (toolCall.function?.arguments) {
1402
- current.arguments += toolCall.function.arguments;
1403
- }
1404
- this.toolCalls.set(toolCall.index, current);
1405
- }
1406
- }
1407
- if (chunk.usage) {
1408
- this.usage = {
1409
- ...this.usage,
1410
- inputTokens: chunk.usage.prompt_tokens ?? 0,
1411
- outputTokens: chunk.usage.completion_tokens ?? 0,
1412
- reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
1413
- cacheReadInputTokens: chunk.usage.prompt_tokens_details?.cached_tokens ?? 0,
1414
- cacheCreationInputTokens: extractCacheWriteTokens(chunk.usage.prompt_tokens_details),
1415
- rawUsage: chunk.usage
1416
- };
1417
- }
1418
- }
1419
- result() {
1420
- const content = [];
1421
- if (this.accumulatedContent) {
1422
- content.push({
1423
- type: 'text',
1424
- text: this.accumulatedContent
1425
- });
1426
- }
1427
- for (const toolCall of this.toolCalls.values()) {
1428
- if (toolCall.name) {
1429
- content.push({
1430
- type: 'function',
1431
- id: toolCall.id,
1432
- function: {
1433
- name: toolCall.name,
1434
- arguments: toolCall.arguments
1435
- }
1436
- });
1437
- }
1438
- }
1439
- return {
1440
- output: [{
1441
- role: 'assistant',
1442
- content: content.length > 0 ? content : [{
1443
- type: 'text',
1444
- text: ''
1445
- }]
1446
- }],
1447
- model: this.model,
1448
- completionId: this.completionId,
1449
- systemFingerprint: this.systemFingerprint,
1450
- serviceTier: this.serviceTier,
1451
- firstTokenTime: this.firstTokenTime,
1452
- stopReason: this.stopReason,
1453
- usage: {
1454
- ...this.usage
1455
- }
1456
- };
1457
- }
1458
- }
1096
+ var OpenAIChatStreamAccumulator = class {
1097
+ constructor() {
1098
+ this.accumulatedContent = "";
1099
+ this.usage = { webSearchCount: 0 };
1100
+ this.toolCalls = /* @__PURE__ */ new Map();
1101
+ }
1102
+ consume(chunk, receivedAt = Date.now()) {
1103
+ this.model ||= chunk.model || void 0;
1104
+ this.completionId ||= chunk.id || void 0;
1105
+ this.systemFingerprint ||= chunk.system_fingerprint || void 0;
1106
+ if (chunk.service_tier != null) this.serviceTier = chunk.service_tier;
1107
+ const choice = chunk.choices?.[0];
1108
+ if (choice?.finish_reason) this.stopReason = choice.finish_reason;
1109
+ const webSearchCount = calculateWebSearchCount(chunk);
1110
+ if (webSearchCount > (this.usage.webSearchCount ?? 0)) this.usage.webSearchCount = webSearchCount;
1111
+ if (choice?.delta?.content) {
1112
+ this.firstTokenTime ??= receivedAt;
1113
+ this.accumulatedContent += choice.delta.content;
1114
+ }
1115
+ if (Array.isArray(choice?.delta?.tool_calls)) {
1116
+ this.firstTokenTime ??= receivedAt;
1117
+ for (const toolCall of choice.delta.tool_calls) {
1118
+ if (toolCall.index === void 0) continue;
1119
+ const current = this.toolCalls.get(toolCall.index) ?? {
1120
+ id: "",
1121
+ name: "",
1122
+ arguments: ""
1123
+ };
1124
+ if (toolCall.id) current.id = toolCall.id;
1125
+ if (toolCall.function?.name) current.name = toolCall.function.name;
1126
+ if (toolCall.function?.arguments) current.arguments += toolCall.function.arguments;
1127
+ this.toolCalls.set(toolCall.index, current);
1128
+ }
1129
+ }
1130
+ if (chunk.usage) this.usage = {
1131
+ ...this.usage,
1132
+ inputTokens: chunk.usage.prompt_tokens ?? 0,
1133
+ outputTokens: chunk.usage.completion_tokens ?? 0,
1134
+ reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
1135
+ cacheReadInputTokens: chunk.usage.prompt_tokens_details?.cached_tokens ?? 0,
1136
+ cacheCreationInputTokens: extractCacheWriteTokens(chunk.usage.prompt_tokens_details),
1137
+ rawUsage: chunk.usage
1138
+ };
1139
+ }
1140
+ result() {
1141
+ const content = [];
1142
+ if (this.accumulatedContent) content.push({
1143
+ type: "text",
1144
+ text: this.accumulatedContent
1145
+ });
1146
+ for (const toolCall of this.toolCalls.values()) if (toolCall.name) content.push({
1147
+ type: "function",
1148
+ id: toolCall.id,
1149
+ function: {
1150
+ name: toolCall.name,
1151
+ arguments: toolCall.arguments
1152
+ }
1153
+ });
1154
+ return {
1155
+ output: [{
1156
+ role: "assistant",
1157
+ content: content.length > 0 ? content : [{
1158
+ type: "text",
1159
+ text: ""
1160
+ }]
1161
+ }],
1162
+ model: this.model,
1163
+ completionId: this.completionId,
1164
+ systemFingerprint: this.systemFingerprint,
1165
+ serviceTier: this.serviceTier,
1166
+ firstTokenTime: this.firstTokenTime,
1167
+ stopReason: this.stopReason,
1168
+ usage: { ...this.usage }
1169
+ };
1170
+ }
1171
+ };
1459
1172
  /** Pure state accumulator for OpenAI-compatible Responses stream events. */
1460
- class OpenAIResponsesStreamAccumulator {
1461
- output = [];
1462
- usage = {
1463
- webSearchCount: 0
1464
- };
1465
- consume(event, receivedAt = Date.now()) {
1466
- if (this.firstTokenTime === undefined && isResponseTokenChunk(event)) {
1467
- this.firstTokenTime = receivedAt;
1468
- }
1469
- if (!('response' in event) || !event.response) {
1470
- return;
1471
- }
1472
- const response = event.response;
1473
- this.model ||= response.model || undefined;
1474
- this.completionId ||= response.id || undefined;
1475
- if (response.service_tier != null) {
1476
- this.serviceTier = response.service_tier;
1477
- }
1478
- const webSearchCount = calculateWebSearchCount(response);
1479
- if (webSearchCount > (this.usage.webSearchCount ?? 0)) {
1480
- this.usage.webSearchCount = webSearchCount;
1481
- }
1482
- if (response.usage) {
1483
- this.usage = {
1484
- ...this.usage,
1485
- inputTokens: response.usage.input_tokens ?? 0,
1486
- outputTokens: response.usage.output_tokens ?? 0,
1487
- reasoningTokens: response.usage.output_tokens_details?.reasoning_tokens ?? 0,
1488
- cacheReadInputTokens: response.usage.input_tokens_details?.cached_tokens ?? 0,
1489
- cacheCreationInputTokens: extractCacheWriteTokens(response.usage.input_tokens_details),
1490
- rawUsage: response.usage
1491
- };
1492
- }
1493
- if (isTerminalResponse(response)) {
1494
- this.terminalResponse = response;
1495
- this.output = response.output ?? [];
1496
- this.stopReason = response.status;
1497
- }
1498
- }
1499
- result() {
1500
- return {
1501
- output: [...this.output],
1502
- model: this.model,
1503
- completionId: this.completionId,
1504
- serviceTier: this.serviceTier,
1505
- firstTokenTime: this.firstTokenTime,
1506
- stopReason: this.stopReason,
1507
- usage: {
1508
- ...this.usage
1509
- },
1510
- terminalResponse: this.terminalResponse
1511
- };
1512
- }
1513
- }
1514
-
1173
+ var OpenAIResponsesStreamAccumulator = class {
1174
+ constructor() {
1175
+ this.output = [];
1176
+ this.usage = { webSearchCount: 0 };
1177
+ }
1178
+ consume(event, receivedAt = Date.now()) {
1179
+ if (this.firstTokenTime === void 0 && isResponseTokenChunk(event)) this.firstTokenTime = receivedAt;
1180
+ if (!("response" in event) || !event.response) return;
1181
+ const response = event.response;
1182
+ this.model ||= response.model || void 0;
1183
+ this.completionId ||= response.id || void 0;
1184
+ if (response.service_tier != null) this.serviceTier = response.service_tier;
1185
+ const webSearchCount = calculateWebSearchCount(response);
1186
+ if (webSearchCount > (this.usage.webSearchCount ?? 0)) this.usage.webSearchCount = webSearchCount;
1187
+ if (response.usage) this.usage = {
1188
+ ...this.usage,
1189
+ inputTokens: response.usage.input_tokens ?? 0,
1190
+ outputTokens: response.usage.output_tokens ?? 0,
1191
+ reasoningTokens: response.usage.output_tokens_details?.reasoning_tokens ?? 0,
1192
+ cacheReadInputTokens: response.usage.input_tokens_details?.cached_tokens ?? 0,
1193
+ cacheCreationInputTokens: extractCacheWriteTokens(response.usage.input_tokens_details),
1194
+ rawUsage: response.usage
1195
+ };
1196
+ if (isTerminalResponse(response)) {
1197
+ this.terminalResponse = response;
1198
+ this.output = response.output ?? [];
1199
+ this.stopReason = responsesStopReason(response);
1200
+ }
1201
+ }
1202
+ result() {
1203
+ return {
1204
+ output: [...this.output],
1205
+ model: this.model,
1206
+ completionId: this.completionId,
1207
+ serviceTier: this.serviceTier,
1208
+ firstTokenTime: this.firstTokenTime,
1209
+ stopReason: this.stopReason,
1210
+ usage: { ...this.usage },
1211
+ terminalResponse: this.terminalResponse
1212
+ };
1213
+ }
1214
+ };
1215
+ //#endregion
1216
+ //#region src/openai/telemetry.ts
1515
1217
  function captureAiGenerationInBackground(...args) {
1516
- void captureAiGeneration(...args).catch(() => undefined);
1218
+ captureAiGeneration(...args).catch(() => void 0);
1517
1219
  }
1518
-
1519
1220
  /** Preserve immediate delivery while isolating normal telemetry from provider latency/failures. */
1520
1221
  async function captureAiGenerationAfterSuccess(...args) {
1521
- if (args[1].captureImmediate) {
1522
- await captureAiGeneration(...args);
1523
- } else {
1524
- captureAiGenerationInBackground(...args);
1525
- }
1222
+ if (args[1].captureImmediate) await captureAiGeneration(...args);
1223
+ else captureAiGenerationInBackground(...args);
1526
1224
  }
1527
1225
  function buildChatUsage(usage, webSearchSource) {
1528
- return {
1529
- inputTokens: usage?.prompt_tokens ?? 0,
1530
- outputTokens: usage?.completion_tokens ?? 0,
1531
- reasoningTokens: usage?.completion_tokens_details?.reasoning_tokens ?? 0,
1532
- cacheReadInputTokens: usage?.prompt_tokens_details?.cached_tokens ?? 0,
1533
- cacheCreationInputTokens: extractCacheWriteTokens(usage?.prompt_tokens_details),
1534
- webSearchCount: calculateWebSearchCount(webSearchSource),
1535
- rawUsage: usage
1536
- };
1226
+ return {
1227
+ inputTokens: usage?.prompt_tokens ?? 0,
1228
+ outputTokens: usage?.completion_tokens ?? 0,
1229
+ reasoningTokens: usage?.completion_tokens_details?.reasoning_tokens ?? 0,
1230
+ cacheReadInputTokens: usage?.prompt_tokens_details?.cached_tokens ?? 0,
1231
+ cacheCreationInputTokens: extractCacheWriteTokens(usage?.prompt_tokens_details),
1232
+ webSearchCount: calculateWebSearchCount(webSearchSource),
1233
+ rawUsage: usage
1234
+ };
1537
1235
  }
1538
1236
  function buildResponsesUsage(usage, webSearchSource) {
1539
- return {
1540
- inputTokens: usage?.input_tokens ?? 0,
1541
- outputTokens: usage?.output_tokens ?? 0,
1542
- reasoningTokens: usage?.output_tokens_details?.reasoning_tokens ?? 0,
1543
- cacheReadInputTokens: usage?.input_tokens_details?.cached_tokens ?? 0,
1544
- cacheCreationInputTokens: extractCacheWriteTokens(usage?.input_tokens_details),
1545
- webSearchCount: calculateWebSearchCount(webSearchSource),
1546
- rawUsage: usage
1547
- };
1237
+ return {
1238
+ inputTokens: usage?.input_tokens ?? 0,
1239
+ outputTokens: usage?.output_tokens ?? 0,
1240
+ reasoningTokens: usage?.output_tokens_details?.reasoning_tokens ?? 0,
1241
+ cacheReadInputTokens: usage?.input_tokens_details?.cached_tokens ?? 0,
1242
+ cacheCreationInputTokens: extractCacheWriteTokens(usage?.input_tokens_details),
1243
+ webSearchCount: calculateWebSearchCount(webSearchSource),
1244
+ rawUsage: usage
1245
+ };
1548
1246
  }
1549
1247
  function buildChatSuccessOptions(context, result) {
1550
- return {
1551
- ...context.monitoring,
1552
- model: context.params.model ?? result.model,
1553
- provider: context.provider,
1554
- input: sanitizeOpenAI(context.params.messages, context.client),
1555
- output: sanitizeOpenAIResponse(result.output, context.client),
1556
- latency: result.latency,
1557
- timeToFirstToken: result.timeToFirstToken,
1558
- baseURL: context.baseURL,
1559
- modelParameters: getModelParams(context.modelParametersSource, result.serviceTier),
1560
- httpStatus: 200,
1561
- usage: result.usage,
1562
- stopReason: result.stopReason,
1563
- tools: extractAvailableToolCalls('openai', context.params),
1564
- completionId: result.completionId,
1565
- providerMetadata: buildProviderMetadata({
1566
- systemFingerprint: result.systemFingerprint,
1567
- requestId: result.requestId
1568
- })
1569
- };
1248
+ return {
1249
+ ...context.monitoring,
1250
+ model: context.params.model ?? result.model,
1251
+ provider: context.provider,
1252
+ input: sanitizeOpenAI(context.params.messages, context.client),
1253
+ output: sanitizeOpenAIResponse(result.output, context.client),
1254
+ latency: result.latency,
1255
+ timeToFirstToken: result.timeToFirstToken,
1256
+ baseURL: context.baseURL,
1257
+ modelParameters: getModelParams(context.modelParametersSource, result.serviceTier),
1258
+ httpStatus: 200,
1259
+ usage: result.usage,
1260
+ stopReason: result.stopReason,
1261
+ tools: extractAvailableToolCalls("openai", context.params),
1262
+ completionId: result.completionId,
1263
+ providerMetadata: buildProviderMetadata({
1264
+ systemFingerprint: result.systemFingerprint,
1265
+ requestId: result.requestId
1266
+ })
1267
+ };
1570
1268
  }
1571
1269
  function buildChatErrorOptions(context, error, metadata) {
1572
- return {
1573
- ...context.monitoring,
1574
- model: context.params.model,
1575
- provider: context.provider,
1576
- input: sanitizeOpenAI(context.params.messages, context.client),
1577
- output: [],
1578
- latency: metadata.latency,
1579
- baseURL: context.baseURL,
1580
- modelParameters: getModelParams(context.modelParametersSource),
1581
- usage: metadata.usage ?? {},
1582
- completionId: metadata.completionId,
1583
- providerMetadata: buildProviderMetadata({
1584
- systemFingerprint: metadata.systemFingerprint
1585
- }),
1586
- error
1587
- };
1270
+ return {
1271
+ ...context.monitoring,
1272
+ model: context.params.model,
1273
+ provider: context.provider,
1274
+ input: sanitizeOpenAI(context.params.messages, context.client),
1275
+ output: [],
1276
+ latency: metadata.latency,
1277
+ baseURL: context.baseURL,
1278
+ modelParameters: getModelParams(context.modelParametersSource),
1279
+ usage: metadata.usage ?? {},
1280
+ completionId: metadata.completionId,
1281
+ providerMetadata: buildProviderMetadata({ systemFingerprint: metadata.systemFingerprint }),
1282
+ error
1283
+ };
1588
1284
  }
1589
1285
  function buildSanitizedResponsesInput(context) {
1590
- return formatOpenAIResponsesInput(sanitizeOpenAIResponse(context.params.input, context.client), sanitizeOpenAIResponse(context.params.instructions, context.client));
1286
+ return formatOpenAIResponsesInput(sanitizeOpenAIResponse(context.params.input, context.client), sanitizeOpenAIResponse(context.params.instructions, context.client));
1591
1287
  }
1592
1288
  function buildResponsesSuccessOptions(context, result) {
1593
- const response = result.response;
1594
- return {
1595
- ...context.monitoring,
1596
- model: context.params.model ?? response.model,
1597
- provider: context.provider,
1598
- input: buildSanitizedResponsesInput(context),
1599
- output: sanitizeOpenAIResponse(result.output, context.client),
1600
- latency: result.latency,
1601
- timeToFirstToken: result.timeToFirstToken,
1602
- baseURL: context.baseURL,
1603
- modelParameters: getModelParams(context.modelParametersSource, response.service_tier),
1604
- httpStatus: 200,
1605
- usage: result.usage ?? buildResponsesUsage(response.usage, response),
1606
- stopReason: response.status ?? undefined,
1607
- tools: result.includeTools ? extractAvailableToolCalls('openai', context.params) : undefined,
1608
- completionId: response.id,
1609
- providerMetadata: buildProviderMetadata({
1610
- requestId: result.includeRequestId ? extractRequestId(response) : undefined,
1611
- incompleteDetails: response.incomplete_details
1612
- }),
1613
- error: getResponseFailure({
1614
- id: response.id,
1615
- status: response.status,
1616
- error: response.error ?? null
1617
- })
1618
- };
1289
+ const response = result.response;
1290
+ return {
1291
+ ...context.monitoring,
1292
+ model: context.params.model ?? response.model,
1293
+ provider: context.provider,
1294
+ input: buildSanitizedResponsesInput(context),
1295
+ output: sanitizeOpenAIResponse(result.output, context.client),
1296
+ latency: result.latency,
1297
+ timeToFirstToken: result.timeToFirstToken,
1298
+ baseURL: context.baseURL,
1299
+ modelParameters: getModelParams(context.modelParametersSource, response.service_tier),
1300
+ httpStatus: 200,
1301
+ usage: result.usage ?? buildResponsesUsage(response.usage, response),
1302
+ stopReason: responsesStopReason(response),
1303
+ tools: result.includeTools ? extractAvailableToolCalls("openai", context.params) : void 0,
1304
+ completionId: response.id,
1305
+ providerMetadata: buildProviderMetadata({
1306
+ requestId: result.includeRequestId ? extractRequestId(response) : void 0,
1307
+ incompleteDetails: response.incomplete_details
1308
+ }),
1309
+ error: getResponseFailure({
1310
+ id: response.id,
1311
+ status: response.status,
1312
+ error: response.error ?? null
1313
+ })
1314
+ };
1619
1315
  }
1620
1316
  function buildBackgroundResponseOptions(context, response) {
1621
- return buildResponsesSuccessOptions(context, {
1622
- response,
1623
- output: formatResponseOpenAI({
1624
- output: response.output
1625
- }),
1626
- latency: getBackgroundResponseLatency(response),
1627
- includeTools: true,
1628
- includeRequestId: true
1629
- });
1317
+ return buildResponsesSuccessOptions(context, {
1318
+ response,
1319
+ output: formatResponseOpenAI({ output: response.output }),
1320
+ latency: getBackgroundResponseLatency(response),
1321
+ includeTools: true,
1322
+ includeRequestId: true
1323
+ });
1630
1324
  }
1631
1325
  function buildResponsesErrorOptions(context, error, metadata) {
1632
- return {
1633
- ...context.monitoring,
1634
- model: context.params.model,
1635
- provider: context.provider,
1636
- input: buildSanitizedResponsesInput(context),
1637
- output: [],
1638
- latency: metadata.latency,
1639
- baseURL: context.baseURL,
1640
- modelParameters: getModelParams(context.modelParametersSource),
1641
- usage: metadata.usage ?? {},
1642
- completionId: metadata.completionId,
1643
- error
1644
- };
1326
+ return {
1327
+ ...context.monitoring,
1328
+ model: context.params.model,
1329
+ provider: context.provider,
1330
+ input: buildSanitizedResponsesInput(context),
1331
+ output: [],
1332
+ latency: metadata.latency,
1333
+ baseURL: context.baseURL,
1334
+ modelParameters: getModelParams(context.modelParametersSource),
1335
+ usage: metadata.usage ?? {},
1336
+ completionId: metadata.completionId,
1337
+ error
1338
+ };
1645
1339
  }
1646
1340
  function buildEmbeddingSuccessOptions(context, usage, latency) {
1647
- return {
1648
- eventType: AIEvent.Embedding,
1649
- ...context.monitoring,
1650
- model: context.params.model,
1651
- provider: context.provider,
1652
- input: withPrivacyMode(context.client, context.monitoring.privacyMode, context.params.input),
1653
- output: null,
1654
- latency,
1655
- baseURL: context.baseURL,
1656
- modelParameters: getModelParams(context.modelParametersSource),
1657
- httpStatus: 200,
1658
- usage: {
1659
- inputTokens: usage?.prompt_tokens ?? 0,
1660
- rawUsage: usage
1661
- }
1662
- };
1341
+ return {
1342
+ eventType: "$ai_embedding",
1343
+ ...context.monitoring,
1344
+ model: context.params.model,
1345
+ provider: context.provider,
1346
+ input: withPrivacyMode(context.client, context.monitoring.privacyMode, context.params.input),
1347
+ output: null,
1348
+ latency,
1349
+ baseURL: context.baseURL,
1350
+ modelParameters: getModelParams(context.modelParametersSource),
1351
+ httpStatus: 200,
1352
+ usage: {
1353
+ inputTokens: usage?.prompt_tokens ?? 0,
1354
+ rawUsage: usage
1355
+ }
1356
+ };
1663
1357
  }
1664
1358
  function buildEmbeddingErrorOptions(context, error, latency) {
1665
- return {
1666
- eventType: AIEvent.Embedding,
1667
- ...context.monitoring,
1668
- model: context.params.model,
1669
- provider: context.provider,
1670
- input: withPrivacyMode(context.client, context.monitoring.privacyMode, context.params.input),
1671
- output: null,
1672
- latency,
1673
- baseURL: context.baseURL,
1674
- modelParameters: getModelParams(context.modelParametersSource),
1675
- usage: {},
1676
- error
1677
- };
1678
- }
1679
-
1680
- class PostHogAzureOpenAI extends openai.AzureOpenAI {
1681
- constructor(config) {
1682
- const {
1683
- posthog,
1684
- ...openAIConfig
1685
- } = config;
1686
- super(openAIConfig);
1687
- this.phClient = posthog;
1688
- this.chat = new WrappedChat$1(this, this.phClient);
1689
- this.responses = new WrappedResponses$1(this, this.phClient);
1690
- this.embeddings = new WrappedEmbeddings$1(this, this.phClient);
1691
- }
1359
+ return {
1360
+ eventType: "$ai_embedding",
1361
+ ...context.monitoring,
1362
+ model: context.params.model,
1363
+ provider: context.provider,
1364
+ input: withPrivacyMode(context.client, context.monitoring.privacyMode, context.params.input),
1365
+ output: null,
1366
+ latency,
1367
+ baseURL: context.baseURL,
1368
+ modelParameters: getModelParams(context.modelParametersSource),
1369
+ usage: {},
1370
+ error
1371
+ };
1692
1372
  }
1693
- let WrappedChat$1 = class WrappedChat extends openai.AzureOpenAI.Chat {
1694
- constructor(parentClient, phClient) {
1695
- super(parentClient);
1696
- this.completions = new WrappedCompletions$1(parentClient, phClient);
1697
- }
1373
+ //#endregion
1374
+ //#region src/openai/azure.ts
1375
+ var PostHogAzureOpenAI = class extends openai.AzureOpenAI {
1376
+ constructor(config) {
1377
+ const { posthog, ...openAIConfig } = config;
1378
+ super(openAIConfig);
1379
+ this.phClient = posthog;
1380
+ this.chat = new WrappedChat$1(this, this.phClient);
1381
+ this.responses = new WrappedResponses$1(this, this.phClient);
1382
+ this.embeddings = new WrappedEmbeddings$1(this, this.phClient);
1383
+ }
1698
1384
  };
1699
- let WrappedCompletions$1 = class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
1700
- constructor(client, phClient) {
1701
- super(client);
1702
- this.phClient = phClient;
1703
- this.baseURL = client.baseURL;
1704
- }
1705
-
1706
- // --- Overload #1: Non-streaming
1707
-
1708
- // --- Overload #2: Streaming
1709
-
1710
- // --- Overload #3: Generic base
1711
-
1712
- // --- Implementation Signature
1713
- create(body, options) {
1714
- const {
1715
- providerParams: openAIParams,
1716
- posthogParams
1717
- } = extractPosthogParams(body);
1718
- const startTime = Date.now();
1719
- const parentPromise = super.create(openAIParams, options);
1720
- if (openAIParams.stream) {
1721
- const wrappedPromise = parentPromise.then(value => {
1722
- if (Symbol.asyncIterator in value) {
1723
- const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
1724
- (async () => {
1725
- const accumulator = new OpenAIChatStreamAccumulator();
1726
- try {
1727
- for await (const chunk of stream1) {
1728
- accumulator.consume(chunk);
1729
- }
1730
- const accumulated = accumulator.result();
1731
- await captureAiGeneration(this.phClient, buildChatSuccessOptions({
1732
- client: this.phClient,
1733
- provider: 'azure',
1734
- baseURL: this.baseURL,
1735
- params: openAIParams,
1736
- monitoring: posthogParams,
1737
- modelParametersSource: body
1738
- }, {
1739
- ...accumulated,
1740
- latency: (Date.now() - startTime) / 1000,
1741
- timeToFirstToken: accumulated.firstTokenTime === undefined ? undefined : (accumulated.firstTokenTime - startTime) / 1000
1742
- }));
1743
- } catch (error) {
1744
- const accumulated = accumulator.result();
1745
- await captureAiGeneration(this.phClient, buildChatErrorOptions({
1746
- client: this.phClient,
1747
- provider: 'azure',
1748
- baseURL: this.baseURL,
1749
- params: openAIParams,
1750
- monitoring: posthogParams,
1751
- modelParametersSource: body
1752
- }, error, {
1753
- completionId: accumulated.completionId,
1754
- systemFingerprint: accumulated.systemFingerprint,
1755
- usage: accumulated.usage,
1756
- latency: (Date.now() - startTime) / 1000
1757
- }));
1758
- throw error;
1759
- }
1760
- })().catch(() => {
1761
- // Swallow: analytics must never crash the host process. The caller
1762
- // already receives this error via their own tee of the stream.
1763
- });
1764
-
1765
- // Return the other stream to the user
1766
- return stream2;
1767
- }
1768
- return value;
1769
- });
1770
- return preserveProviderPromise(parentPromise, wrappedPromise);
1771
- } else {
1772
- const wrappedPromise = parentPromise.then(async result => {
1773
- if ('choices' in result) {
1774
- await captureAiGenerationAfterSuccess(this.phClient, buildChatSuccessOptions({
1775
- client: this.phClient,
1776
- provider: 'azure',
1777
- baseURL: this.baseURL,
1778
- params: openAIParams,
1779
- monitoring: posthogParams,
1780
- modelParametersSource: body
1781
- }, {
1782
- output: formatResponseOpenAI(result),
1783
- model: result.model,
1784
- serviceTier: result.service_tier ?? undefined,
1785
- latency: (Date.now() - startTime) / 1000,
1786
- usage: buildChatUsage(result.usage, result),
1787
- stopReason: result.choices[0]?.finish_reason ?? undefined,
1788
- completionId: result.id,
1789
- systemFingerprint: result.system_fingerprint,
1790
- requestId: result._request_id
1791
- }));
1792
- }
1793
- return result;
1794
- }, async error => {
1795
- await captureAiGeneration(this.phClient, buildChatErrorOptions({
1796
- client: this.phClient,
1797
- provider: 'azure',
1798
- baseURL: this.baseURL,
1799
- params: openAIParams,
1800
- monitoring: posthogParams,
1801
- modelParametersSource: body
1802
- }, error, {
1803
- latency: (Date.now() - startTime) / 1000
1804
- }));
1805
- throw error;
1806
- });
1807
- return preserveProviderPromise(parentPromise, wrappedPromise);
1808
- }
1809
- }
1385
+ var WrappedChat$1 = class extends openai.AzureOpenAI.Chat {
1386
+ constructor(parentClient, phClient) {
1387
+ super(parentClient);
1388
+ this.completions = new WrappedCompletions$1(parentClient, phClient);
1389
+ }
1810
1390
  };
1811
- let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Responses {
1812
- backgroundResponses = new BackgroundResponseTracker();
1813
- constructor(client, phClient) {
1814
- super(client);
1815
- this.phClient = phClient;
1816
- this.baseURL = client.baseURL;
1817
- }
1818
- async captureBackgroundResponse(result, context) {
1819
- const {
1820
- openAIParams,
1821
- posthogParams
1822
- } = context;
1823
- await captureAiGenerationAfterSuccess(this.phClient, buildBackgroundResponseOptions({
1824
- client: this.phClient,
1825
- provider: 'azure',
1826
- baseURL: this.baseURL,
1827
- params: openAIParams,
1828
- monitoring: posthogParams,
1829
- modelParametersSource: openAIParams
1830
- }, result));
1831
- }
1832
-
1833
- // --- Overload #1: Non-streaming
1834
-
1835
- // --- Overload #2: Streaming
1836
-
1837
- // --- Overload #3: Generic base
1838
-
1839
- // --- Implementation Signature
1840
- create(body, options) {
1841
- const {
1842
- providerParams: openAIParams,
1843
- posthogParams
1844
- } = extractPosthogParams(body);
1845
- const startTime = Date.now();
1846
- const parentPromise = super.create(openAIParams, options);
1847
- if (openAIParams.stream) {
1848
- const wrappedPromise = parentPromise.then(value => {
1849
- if (Symbol.asyncIterator in value) {
1850
- const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
1851
- (async () => {
1852
- const accumulator = new OpenAIResponsesStreamAccumulator();
1853
- try {
1854
- for await (const chunk of stream1) {
1855
- accumulator.consume(chunk);
1856
- if (openAIParams.background === true && 'response' in chunk && chunk.response && !this.backgroundResponses.get(chunk.response.id)) {
1857
- this.backgroundResponses.set(chunk.response.id, {
1858
- openAIParams,
1859
- posthogParams
1860
- });
1861
- }
1862
- }
1863
- const accumulated = accumulator.result();
1864
- if (openAIParams.background === true) {
1865
- if (accumulated.terminalResponse) {
1866
- const context = this.backgroundResponses.take(accumulated.terminalResponse.id);
1867
- if (context) {
1868
- await this.captureBackgroundResponse(accumulated.terminalResponse, context).catch(() => undefined);
1869
- }
1870
- }
1871
- return;
1872
- }
1873
- const response = accumulated.terminalResponse ?? {
1874
- id: accumulated.completionId ?? '',
1875
- model: accumulated.model ?? openAIParams.model,
1876
- status: accumulated.stopReason,
1877
- service_tier: accumulated.serviceTier
1878
- };
1879
- await captureAiGeneration(this.phClient, buildResponsesSuccessOptions({
1880
- client: this.phClient,
1881
- provider: 'azure',
1882
- baseURL: this.baseURL,
1883
- params: openAIParams,
1884
- monitoring: posthogParams,
1885
- modelParametersSource: body
1886
- }, {
1887
- response,
1888
- output: accumulated.output,
1889
- latency: (Date.now() - startTime) / 1000,
1890
- timeToFirstToken: accumulated.firstTokenTime === undefined ? undefined : (accumulated.firstTokenTime - startTime) / 1000,
1891
- usage: accumulated.usage,
1892
- includeTools: true
1893
- }));
1894
- } catch (error) {
1895
- const accumulated = accumulator.result();
1896
- if (openAIParams.background === true && accumulated.completionId && this.backgroundResponses.get(accumulated.completionId)) {
1897
- throw error;
1898
- }
1899
- await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
1900
- client: this.phClient,
1901
- provider: 'azure',
1902
- baseURL: this.baseURL,
1903
- params: openAIParams,
1904
- monitoring: posthogParams,
1905
- modelParametersSource: body
1906
- }, error, {
1907
- completionId: accumulated.completionId,
1908
- usage: accumulated.usage,
1909
- latency: (Date.now() - startTime) / 1000
1910
- }));
1911
- throw error;
1912
- }
1913
- })().catch(() => {
1914
- // Swallow: analytics must never crash the host process. The caller
1915
- // already receives this error via their own tee of the stream.
1916
- });
1917
- return stream2;
1918
- }
1919
- return value;
1920
- });
1921
- return preserveProviderPromise(parentPromise, wrappedPromise);
1922
- } else {
1923
- const wrappedPromise = parentPromise.then(async result => {
1924
- if ('output' in result) {
1925
- if (isPendingBackgroundResponse(openAIParams, result)) {
1926
- this.backgroundResponses.set(result.id, {
1927
- openAIParams,
1928
- posthogParams
1929
- });
1930
- return result;
1931
- }
1932
- await captureAiGenerationAfterSuccess(this.phClient, buildResponsesSuccessOptions({
1933
- client: this.phClient,
1934
- provider: 'azure',
1935
- baseURL: this.baseURL,
1936
- params: openAIParams,
1937
- monitoring: posthogParams,
1938
- modelParametersSource: body
1939
- }, {
1940
- response: result,
1941
- output: formatResponseOpenAI({
1942
- output: result.output
1943
- }),
1944
- latency: (Date.now() - startTime) / 1000,
1945
- includeTools: true,
1946
- includeRequestId: true
1947
- }));
1948
- }
1949
- return result;
1950
- }, async error => {
1951
- await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
1952
- client: this.phClient,
1953
- provider: 'azure',
1954
- baseURL: this.baseURL,
1955
- params: openAIParams,
1956
- monitoring: posthogParams,
1957
- modelParametersSource: body
1958
- }, error, {
1959
- latency: (Date.now() - startTime) / 1000
1960
- }));
1961
- throw error;
1962
- });
1963
- return preserveProviderPromise(parentPromise, wrappedPromise);
1964
- }
1965
- }
1966
- retrieve(responseID, query = {}, options) {
1967
- const parentPromise = super.retrieve(responseID, query, options);
1968
-
1969
- // Preserve the upstream promise and stream unchanged for responses that
1970
- // were not created through this client.
1971
- if (!this.backgroundResponses.get(responseID)) {
1972
- return parentPromise;
1973
- }
1974
- if (query.stream) {
1975
- return parentPromise._thenUnwrap(result => {
1976
- if ('controller' in result) {
1977
- return wrapBackgroundResponseStream(result, responseID, this.backgroundResponses, (response, context) => this.captureBackgroundResponse(response, context));
1978
- }
1979
- return result;
1980
- });
1981
- }
1982
- return parentPromise._thenUnwrap(async result => {
1983
- if (!('output' in result) || !isTerminalResponse(result)) {
1984
- return result;
1985
- }
1986
-
1987
- // Removing the context before capture makes concurrent or repeated
1988
- // terminal polls idempotent.
1989
- const context = this.backgroundResponses.take(responseID);
1990
- if (context) {
1991
- await this.captureBackgroundResponse(result, context).catch(() => undefined);
1992
- }
1993
- return result;
1994
- });
1995
- }
1996
- cancel(responseID, options) {
1997
- const parentPromise = super.cancel(responseID, options);
1998
-
1999
- // Avoid wrapping calls that do not belong to a background response created
2000
- // through this client, preserving the upstream APIPromise unchanged.
2001
- if (!this.backgroundResponses.get(responseID)) {
2002
- return parentPromise;
2003
- }
2004
- return parentPromise._thenUnwrap(async result => {
2005
- if (!isTerminalResponse(result)) {
2006
- return result;
2007
- }
2008
- const context = this.backgroundResponses.take(responseID);
2009
- if (context) {
2010
- await this.captureBackgroundResponse(result, context).catch(() => undefined);
2011
- }
2012
- return result;
2013
- });
2014
- }
2015
- parse(body, options) {
2016
- const {
2017
- providerParams: openAIParams,
2018
- posthogParams
2019
- } = extractPosthogParams(body);
2020
- const startTime = Date.now();
2021
- const parentPromise = callWithOriginalCreate(this, super.create.bind(this), () => super.parse(openAIParams, options));
2022
- const wrappedPromise = parentPromise.then(async result => {
2023
- if (isPendingBackgroundResponse(openAIParams, result)) {
2024
- this.backgroundResponses.set(result.id, {
2025
- openAIParams,
2026
- posthogParams
2027
- });
2028
- return result;
2029
- }
2030
- await captureAiGeneration(this.phClient, buildResponsesSuccessOptions({
2031
- client: this.phClient,
2032
- provider: 'azure',
2033
- baseURL: this.baseURL,
2034
- params: openAIParams,
2035
- monitoring: posthogParams,
2036
- modelParametersSource: body
2037
- }, {
2038
- response: result,
2039
- output: result.output,
2040
- latency: (Date.now() - startTime) / 1000,
2041
- includeRequestId: true
2042
- }));
2043
- return result;
2044
- }, async error => {
2045
- await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
2046
- client: this.phClient,
2047
- provider: 'azure',
2048
- baseURL: this.baseURL,
2049
- params: openAIParams,
2050
- monitoring: posthogParams,
2051
- modelParametersSource: body
2052
- }, error, {
2053
- latency: (Date.now() - startTime) / 1000
2054
- }));
2055
- throw error;
2056
- });
2057
- return preserveProviderPromise(parentPromise, wrappedPromise);
2058
- }
1391
+ var WrappedCompletions$1 = class extends openai.AzureOpenAI.Chat.Completions {
1392
+ constructor(client, phClient) {
1393
+ super(client);
1394
+ this.phClient = phClient;
1395
+ this.baseURL = client.baseURL;
1396
+ }
1397
+ create(body, options) {
1398
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
1399
+ const startTime = Date.now();
1400
+ const parentPromise = super.create(openAIParams, options);
1401
+ if (openAIParams.stream) return preserveProviderPromise(parentPromise, parentPromise.then((value) => {
1402
+ if (Symbol.asyncIterator in value) {
1403
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new openai_streaming.Stream(iterator, controller));
1404
+ (async () => {
1405
+ const accumulator = new OpenAIChatStreamAccumulator();
1406
+ try {
1407
+ for await (const chunk of stream1) accumulator.consume(chunk);
1408
+ const accumulated = accumulator.result();
1409
+ await captureAiGeneration(this.phClient, buildChatSuccessOptions({
1410
+ client: this.phClient,
1411
+ provider: "azure",
1412
+ baseURL: this.baseURL,
1413
+ params: openAIParams,
1414
+ monitoring: posthogParams,
1415
+ modelParametersSource: body
1416
+ }, {
1417
+ ...accumulated,
1418
+ latency: (Date.now() - startTime) / 1e3,
1419
+ timeToFirstToken: accumulated.firstTokenTime === void 0 ? void 0 : (accumulated.firstTokenTime - startTime) / 1e3
1420
+ }));
1421
+ } catch (error) {
1422
+ const accumulated = accumulator.result();
1423
+ await captureAiGeneration(this.phClient, buildChatErrorOptions({
1424
+ client: this.phClient,
1425
+ provider: "azure",
1426
+ baseURL: this.baseURL,
1427
+ params: openAIParams,
1428
+ monitoring: posthogParams,
1429
+ modelParametersSource: body
1430
+ }, error, {
1431
+ completionId: accumulated.completionId,
1432
+ systemFingerprint: accumulated.systemFingerprint,
1433
+ usage: accumulated.usage,
1434
+ latency: (Date.now() - startTime) / 1e3
1435
+ }));
1436
+ throw error;
1437
+ }
1438
+ })().catch(() => {});
1439
+ return stream2;
1440
+ }
1441
+ return value;
1442
+ }));
1443
+ else return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
1444
+ if ("choices" in result) await captureAiGenerationAfterSuccess(this.phClient, buildChatSuccessOptions({
1445
+ client: this.phClient,
1446
+ provider: "azure",
1447
+ baseURL: this.baseURL,
1448
+ params: openAIParams,
1449
+ monitoring: posthogParams,
1450
+ modelParametersSource: body
1451
+ }, {
1452
+ output: formatResponseOpenAI(result),
1453
+ model: result.model,
1454
+ serviceTier: result.service_tier ?? void 0,
1455
+ latency: (Date.now() - startTime) / 1e3,
1456
+ usage: buildChatUsage(result.usage, result),
1457
+ stopReason: result.choices[0]?.finish_reason ?? void 0,
1458
+ completionId: result.id,
1459
+ systemFingerprint: result.system_fingerprint,
1460
+ requestId: result._request_id
1461
+ }));
1462
+ return result;
1463
+ }, async (error) => {
1464
+ await captureAiGeneration(this.phClient, buildChatErrorOptions({
1465
+ client: this.phClient,
1466
+ provider: "azure",
1467
+ baseURL: this.baseURL,
1468
+ params: openAIParams,
1469
+ monitoring: posthogParams,
1470
+ modelParametersSource: body
1471
+ }, error, { latency: (Date.now() - startTime) / 1e3 }));
1472
+ throw error;
1473
+ }));
1474
+ }
2059
1475
  };
2060
- let WrappedEmbeddings$1 = class WrappedEmbeddings extends openai.AzureOpenAI.Embeddings {
2061
- constructor(client, phClient) {
2062
- super(client);
2063
- this.phClient = phClient;
2064
- this.baseURL = client.baseURL;
2065
- }
2066
- create(body, options) {
2067
- const {
2068
- providerParams: openAIParams,
2069
- posthogParams
2070
- } = extractPosthogParams(body);
2071
- const startTime = Date.now();
2072
- const parentPromise = super.create(openAIParams, options);
2073
- const wrappedPromise = parentPromise.then(async result => {
2074
- await captureAiGeneration(this.phClient, buildEmbeddingSuccessOptions({
2075
- client: this.phClient,
2076
- provider: 'azure',
2077
- baseURL: this.baseURL,
2078
- params: openAIParams,
2079
- monitoring: posthogParams,
2080
- modelParametersSource: body
2081
- }, result.usage, (Date.now() - startTime) / 1000));
2082
- return result;
2083
- }, async error => {
2084
- await captureAiGeneration(this.phClient, buildEmbeddingErrorOptions({
2085
- client: this.phClient,
2086
- provider: 'azure',
2087
- baseURL: this.baseURL,
2088
- params: openAIParams,
2089
- monitoring: posthogParams,
2090
- modelParametersSource: body
2091
- }, error, (Date.now() - startTime) / 1000));
2092
- throw error;
2093
- });
2094
- return preserveProviderPromise(parentPromise, wrappedPromise);
2095
- }
1476
+ var WrappedResponses$1 = class extends openai.AzureOpenAI.Responses {
1477
+ constructor(client, phClient) {
1478
+ super(client);
1479
+ this.backgroundResponses = new BackgroundResponseTracker();
1480
+ this.phClient = phClient;
1481
+ this.baseURL = client.baseURL;
1482
+ }
1483
+ async captureBackgroundResponse(result, context) {
1484
+ const { openAIParams, posthogParams } = context;
1485
+ await captureAiGenerationAfterSuccess(this.phClient, buildBackgroundResponseOptions({
1486
+ client: this.phClient,
1487
+ provider: "azure",
1488
+ baseURL: this.baseURL,
1489
+ params: openAIParams,
1490
+ monitoring: posthogParams,
1491
+ modelParametersSource: openAIParams
1492
+ }, result));
1493
+ }
1494
+ create(body, options) {
1495
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
1496
+ const startTime = Date.now();
1497
+ const parentPromise = super.create(openAIParams, options);
1498
+ if (openAIParams.stream) return preserveProviderPromise(parentPromise, parentPromise.then((value) => {
1499
+ if (Symbol.asyncIterator in value) {
1500
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new openai_streaming.Stream(iterator, controller));
1501
+ (async () => {
1502
+ const accumulator = new OpenAIResponsesStreamAccumulator();
1503
+ try {
1504
+ for await (const chunk of stream1) {
1505
+ accumulator.consume(chunk);
1506
+ if (openAIParams.background === true && "response" in chunk && chunk.response && !this.backgroundResponses.get(chunk.response.id)) this.backgroundResponses.set(chunk.response.id, {
1507
+ openAIParams,
1508
+ posthogParams
1509
+ });
1510
+ }
1511
+ const accumulated = accumulator.result();
1512
+ if (openAIParams.background === true) {
1513
+ if (accumulated.terminalResponse) {
1514
+ const context = this.backgroundResponses.take(accumulated.terminalResponse.id);
1515
+ if (context) await this.captureBackgroundResponse(accumulated.terminalResponse, context).catch(() => void 0);
1516
+ }
1517
+ return;
1518
+ }
1519
+ const response = accumulated.terminalResponse ?? {
1520
+ id: accumulated.completionId ?? "",
1521
+ model: accumulated.model ?? openAIParams.model,
1522
+ service_tier: accumulated.serviceTier
1523
+ };
1524
+ await captureAiGeneration(this.phClient, buildResponsesSuccessOptions({
1525
+ client: this.phClient,
1526
+ provider: "azure",
1527
+ baseURL: this.baseURL,
1528
+ params: openAIParams,
1529
+ monitoring: posthogParams,
1530
+ modelParametersSource: body
1531
+ }, {
1532
+ response,
1533
+ output: accumulated.output,
1534
+ latency: (Date.now() - startTime) / 1e3,
1535
+ timeToFirstToken: accumulated.firstTokenTime === void 0 ? void 0 : (accumulated.firstTokenTime - startTime) / 1e3,
1536
+ usage: accumulated.usage,
1537
+ includeTools: true
1538
+ }));
1539
+ } catch (error) {
1540
+ const accumulated = accumulator.result();
1541
+ if (openAIParams.background === true && accumulated.completionId && this.backgroundResponses.get(accumulated.completionId)) throw error;
1542
+ await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
1543
+ client: this.phClient,
1544
+ provider: "azure",
1545
+ baseURL: this.baseURL,
1546
+ params: openAIParams,
1547
+ monitoring: posthogParams,
1548
+ modelParametersSource: body
1549
+ }, error, {
1550
+ completionId: accumulated.completionId,
1551
+ usage: accumulated.usage,
1552
+ latency: (Date.now() - startTime) / 1e3
1553
+ }));
1554
+ throw error;
1555
+ }
1556
+ })().catch(() => {});
1557
+ return stream2;
1558
+ }
1559
+ return value;
1560
+ }));
1561
+ else return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
1562
+ if ("output" in result) {
1563
+ if (isPendingBackgroundResponse(openAIParams, result)) {
1564
+ this.backgroundResponses.set(result.id, {
1565
+ openAIParams,
1566
+ posthogParams
1567
+ });
1568
+ return result;
1569
+ }
1570
+ await captureAiGenerationAfterSuccess(this.phClient, buildResponsesSuccessOptions({
1571
+ client: this.phClient,
1572
+ provider: "azure",
1573
+ baseURL: this.baseURL,
1574
+ params: openAIParams,
1575
+ monitoring: posthogParams,
1576
+ modelParametersSource: body
1577
+ }, {
1578
+ response: result,
1579
+ output: formatResponseOpenAI({ output: result.output }),
1580
+ latency: (Date.now() - startTime) / 1e3,
1581
+ includeTools: true,
1582
+ includeRequestId: true
1583
+ }));
1584
+ }
1585
+ return result;
1586
+ }, async (error) => {
1587
+ await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
1588
+ client: this.phClient,
1589
+ provider: "azure",
1590
+ baseURL: this.baseURL,
1591
+ params: openAIParams,
1592
+ monitoring: posthogParams,
1593
+ modelParametersSource: body
1594
+ }, error, { latency: (Date.now() - startTime) / 1e3 }));
1595
+ throw error;
1596
+ }));
1597
+ }
1598
+ retrieve(responseID, query = {}, options) {
1599
+ const parentPromise = super.retrieve(responseID, query, options);
1600
+ if (!this.backgroundResponses.get(responseID)) return parentPromise;
1601
+ if (query.stream) return parentPromise._thenUnwrap((result) => {
1602
+ if ("controller" in result) return wrapBackgroundResponseStream(result, responseID, this.backgroundResponses, (response, context) => this.captureBackgroundResponse(response, context));
1603
+ return result;
1604
+ });
1605
+ return parentPromise._thenUnwrap(async (result) => {
1606
+ if (!("output" in result) || !isTerminalResponse(result)) return result;
1607
+ const context = this.backgroundResponses.take(responseID);
1608
+ if (context) await this.captureBackgroundResponse(result, context).catch(() => void 0);
1609
+ return result;
1610
+ });
1611
+ }
1612
+ cancel(responseID, options) {
1613
+ const parentPromise = super.cancel(responseID, options);
1614
+ if (!this.backgroundResponses.get(responseID)) return parentPromise;
1615
+ return parentPromise._thenUnwrap(async (result) => {
1616
+ if (!isTerminalResponse(result)) return result;
1617
+ const context = this.backgroundResponses.take(responseID);
1618
+ if (context) await this.captureBackgroundResponse(result, context).catch(() => void 0);
1619
+ return result;
1620
+ });
1621
+ }
1622
+ parse(body, options) {
1623
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
1624
+ const startTime = Date.now();
1625
+ const parentPromise = callWithOriginalCreate(this, super.create.bind(this), () => super.parse(openAIParams, options));
1626
+ return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
1627
+ if (isPendingBackgroundResponse(openAIParams, result)) {
1628
+ this.backgroundResponses.set(result.id, {
1629
+ openAIParams,
1630
+ posthogParams
1631
+ });
1632
+ return result;
1633
+ }
1634
+ await captureAiGeneration(this.phClient, buildResponsesSuccessOptions({
1635
+ client: this.phClient,
1636
+ provider: "azure",
1637
+ baseURL: this.baseURL,
1638
+ params: openAIParams,
1639
+ monitoring: posthogParams,
1640
+ modelParametersSource: body
1641
+ }, {
1642
+ response: result,
1643
+ output: result.output,
1644
+ latency: (Date.now() - startTime) / 1e3,
1645
+ includeRequestId: true
1646
+ }));
1647
+ return result;
1648
+ }, async (error) => {
1649
+ await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
1650
+ client: this.phClient,
1651
+ provider: "azure",
1652
+ baseURL: this.baseURL,
1653
+ params: openAIParams,
1654
+ monitoring: posthogParams,
1655
+ modelParametersSource: body
1656
+ }, error, { latency: (Date.now() - startTime) / 1e3 }));
1657
+ throw error;
1658
+ }));
1659
+ }
2096
1660
  };
2097
-
1661
+ var WrappedEmbeddings$1 = class extends openai.AzureOpenAI.Embeddings {
1662
+ constructor(client, phClient) {
1663
+ super(client);
1664
+ this.phClient = phClient;
1665
+ this.baseURL = client.baseURL;
1666
+ }
1667
+ create(body, options) {
1668
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
1669
+ const startTime = Date.now();
1670
+ const parentPromise = super.create(openAIParams, options);
1671
+ return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
1672
+ await captureAiGeneration(this.phClient, buildEmbeddingSuccessOptions({
1673
+ client: this.phClient,
1674
+ provider: "azure",
1675
+ baseURL: this.baseURL,
1676
+ params: openAIParams,
1677
+ monitoring: posthogParams,
1678
+ modelParametersSource: body
1679
+ }, result.usage, (Date.now() - startTime) / 1e3));
1680
+ return result;
1681
+ }, async (error) => {
1682
+ await captureAiGeneration(this.phClient, buildEmbeddingErrorOptions({
1683
+ client: this.phClient,
1684
+ provider: "azure",
1685
+ baseURL: this.baseURL,
1686
+ params: openAIParams,
1687
+ monitoring: posthogParams,
1688
+ modelParametersSource: body
1689
+ }, error, (Date.now() - startTime) / 1e3));
1690
+ throw error;
1691
+ }));
1692
+ }
1693
+ };
1694
+ //#endregion
1695
+ //#region src/openai/index.ts
2098
1696
  const Chat = openai.OpenAI.Chat;
2099
1697
  const Completions = Chat.Completions;
2100
1698
  const Responses = openai.OpenAI.Responses;
2101
1699
  const Embeddings = openai.OpenAI.Embeddings;
2102
1700
  const Audio = openai.OpenAI.Audio;
2103
1701
  const Transcriptions = openai.OpenAI.Audio.Transcriptions;
2104
- class PostHogOpenAI extends openai.OpenAI {
2105
- constructor(config) {
2106
- const {
2107
- posthog,
2108
- ...openAIConfig
2109
- } = config;
2110
- super(openAIConfig);
2111
- this.phClient = posthog;
2112
- this.chat = new WrappedChat(this, this.phClient);
2113
- this.responses = new WrappedResponses(this, this.phClient);
2114
- this.embeddings = new WrappedEmbeddings(this, this.phClient);
2115
- this.audio = new WrappedAudio(this, this.phClient);
2116
- }
2117
- }
2118
- class WrappedChat extends Chat {
2119
- constructor(parentClient, phClient) {
2120
- super(parentClient);
2121
- this.completions = new WrappedCompletions(parentClient, phClient);
2122
- }
2123
- }
2124
- class WrappedCompletions extends Completions {
2125
- constructor(client, phClient) {
2126
- super(client);
2127
- this.phClient = phClient;
2128
- this.baseURL = client.baseURL;
2129
- }
2130
-
2131
- // --- Overload #1: Non-streaming
2132
-
2133
- // --- Overload #2: Streaming
2134
-
2135
- // --- Overload #3: Generic base
2136
-
2137
- // --- Implementation Signature
2138
- create(body, options) {
2139
- const {
2140
- providerParams: openAIParams,
2141
- posthogParams
2142
- } = extractPosthogParams(body);
2143
- const startTime = Date.now();
2144
- const parentPromise = super.create(openAIParams, options);
2145
- if (openAIParams.stream) {
2146
- const wrappedPromise = parentPromise.then(value => {
2147
- if (Symbol.asyncIterator in value) {
2148
- const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
2149
- (async () => {
2150
- const accumulator = new OpenAIChatStreamAccumulator();
2151
- try {
2152
- for await (const chunk of stream1) {
2153
- accumulator.consume(chunk);
2154
- }
2155
- const accumulated = accumulator.result();
2156
- await captureAiGeneration(this.phClient, buildChatSuccessOptions({
2157
- client: this.phClient,
2158
- provider: 'openai',
2159
- baseURL: this.baseURL,
2160
- params: openAIParams,
2161
- monitoring: posthogParams,
2162
- modelParametersSource: body
2163
- }, {
2164
- ...accumulated,
2165
- latency: (Date.now() - startTime) / 1000,
2166
- timeToFirstToken: accumulated.firstTokenTime === undefined ? undefined : (accumulated.firstTokenTime - startTime) / 1000
2167
- }));
2168
- } catch (error) {
2169
- const accumulated = accumulator.result();
2170
- await captureAiGeneration(this.phClient, buildChatErrorOptions({
2171
- client: this.phClient,
2172
- provider: 'openai',
2173
- baseURL: this.baseURL,
2174
- params: openAIParams,
2175
- monitoring: posthogParams,
2176
- modelParametersSource: body
2177
- }, error, {
2178
- completionId: accumulated.completionId,
2179
- systemFingerprint: accumulated.systemFingerprint,
2180
- usage: accumulated.usage,
2181
- latency: (Date.now() - startTime) / 1000
2182
- }));
2183
- throw error;
2184
- }
2185
- })().catch(() => {
2186
- // Swallow: analytics must never crash the host process. The caller
2187
- // already receives this error via their own tee of the stream.
2188
- });
2189
-
2190
- // Return the other stream to the user
2191
- return stream2;
2192
- }
2193
- return value;
2194
- });
2195
- return preserveProviderPromise(parentPromise, wrappedPromise);
2196
- } else {
2197
- const wrappedPromise = parentPromise.then(async result => {
2198
- if ('choices' in result) {
2199
- await captureAiGenerationAfterSuccess(this.phClient, buildChatSuccessOptions({
2200
- client: this.phClient,
2201
- provider: 'openai',
2202
- baseURL: this.baseURL,
2203
- params: openAIParams,
2204
- monitoring: posthogParams,
2205
- modelParametersSource: body
2206
- }, {
2207
- output: formatResponseOpenAI(result),
2208
- model: result.model,
2209
- serviceTier: result.service_tier ?? undefined,
2210
- latency: (Date.now() - startTime) / 1000,
2211
- usage: buildChatUsage(result.usage, result),
2212
- stopReason: result.choices[0]?.finish_reason ?? undefined,
2213
- completionId: result.id,
2214
- systemFingerprint: result.system_fingerprint,
2215
- requestId: extractRequestId(result)
2216
- }));
2217
- }
2218
- return result;
2219
- }, async error => {
2220
- await captureAiGeneration(this.phClient, buildChatErrorOptions({
2221
- client: this.phClient,
2222
- provider: 'openai',
2223
- baseURL: this.baseURL,
2224
- params: openAIParams,
2225
- monitoring: posthogParams,
2226
- modelParametersSource: body
2227
- }, error, {
2228
- latency: (Date.now() - startTime) / 1000
2229
- }));
2230
- throw error;
2231
- });
2232
- return preserveProviderPromise(parentPromise, wrappedPromise);
2233
- }
2234
- }
2235
- }
2236
- class WrappedResponses extends Responses {
2237
- backgroundResponses = new BackgroundResponseTracker();
2238
- constructor(client, phClient) {
2239
- super(client);
2240
- this.phClient = phClient;
2241
- this.baseURL = client.baseURL;
2242
- }
2243
- async captureBackgroundResponse(result, context) {
2244
- const {
2245
- openAIParams,
2246
- posthogParams
2247
- } = context;
2248
- await captureAiGenerationAfterSuccess(this.phClient, buildBackgroundResponseOptions({
2249
- client: this.phClient,
2250
- provider: 'openai',
2251
- baseURL: this.baseURL,
2252
- params: openAIParams,
2253
- monitoring: posthogParams,
2254
- modelParametersSource: openAIParams
2255
- }, result));
2256
- }
2257
-
2258
- // --- Overload #1: Non-streaming
2259
-
2260
- // --- Overload #2: Streaming
2261
-
2262
- // --- Overload #3: Generic base
2263
-
2264
- // --- Implementation Signature
2265
- create(body, options) {
2266
- const {
2267
- providerParams: openAIParams,
2268
- posthogParams
2269
- } = extractPosthogParams(body);
2270
- const startTime = Date.now();
2271
- const parentPromise = super.create(openAIParams, options);
2272
- if (openAIParams.stream) {
2273
- const wrappedPromise = parentPromise.then(value => {
2274
- if (Symbol.asyncIterator in value) {
2275
- const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
2276
- (async () => {
2277
- const accumulator = new OpenAIResponsesStreamAccumulator();
2278
- try {
2279
- for await (const chunk of stream1) {
2280
- accumulator.consume(chunk);
2281
- if (openAIParams.background === true && 'response' in chunk && chunk.response && !this.backgroundResponses.get(chunk.response.id)) {
2282
- this.backgroundResponses.set(chunk.response.id, {
2283
- openAIParams,
2284
- posthogParams
2285
- });
2286
- }
2287
- }
2288
- const accumulated = accumulator.result();
2289
- if (openAIParams.background === true) {
2290
- if (accumulated.terminalResponse) {
2291
- const context = this.backgroundResponses.take(accumulated.terminalResponse.id);
2292
- if (context) {
2293
- await this.captureBackgroundResponse(accumulated.terminalResponse, context).catch(() => undefined);
2294
- }
2295
- }
2296
- return;
2297
- }
2298
- const response = accumulated.terminalResponse ?? {
2299
- id: accumulated.completionId ?? '',
2300
- model: accumulated.model ?? openAIParams.model,
2301
- status: accumulated.stopReason,
2302
- service_tier: accumulated.serviceTier
2303
- };
2304
- await captureAiGeneration(this.phClient, buildResponsesSuccessOptions({
2305
- client: this.phClient,
2306
- provider: 'openai',
2307
- baseURL: this.baseURL,
2308
- params: openAIParams,
2309
- monitoring: posthogParams,
2310
- modelParametersSource: body
2311
- }, {
2312
- response,
2313
- output: accumulated.output,
2314
- latency: (Date.now() - startTime) / 1000,
2315
- timeToFirstToken: accumulated.firstTokenTime === undefined ? undefined : (accumulated.firstTokenTime - startTime) / 1000,
2316
- usage: accumulated.usage,
2317
- includeTools: true
2318
- }));
2319
- } catch (error) {
2320
- const accumulated = accumulator.result();
2321
- if (openAIParams.background === true && accumulated.completionId && this.backgroundResponses.get(accumulated.completionId)) {
2322
- throw error;
2323
- }
2324
- await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
2325
- client: this.phClient,
2326
- provider: 'openai',
2327
- baseURL: this.baseURL,
2328
- params: openAIParams,
2329
- monitoring: posthogParams,
2330
- modelParametersSource: body
2331
- }, error, {
2332
- completionId: accumulated.completionId,
2333
- usage: accumulated.usage,
2334
- latency: (Date.now() - startTime) / 1000
2335
- }));
2336
- throw error;
2337
- }
2338
- })().catch(() => {
2339
- // Swallow: analytics must never crash the host process. The caller
2340
- // already receives this error via their own tee of the stream.
2341
- });
2342
- return stream2;
2343
- }
2344
- return value;
2345
- });
2346
- return preserveProviderPromise(parentPromise, wrappedPromise);
2347
- } else {
2348
- const wrappedPromise = parentPromise.then(async result => {
2349
- if ('output' in result) {
2350
- if (isPendingBackgroundResponse(openAIParams, result)) {
2351
- this.backgroundResponses.set(result.id, {
2352
- openAIParams,
2353
- posthogParams
2354
- });
2355
- return result;
2356
- }
2357
- await captureAiGenerationAfterSuccess(this.phClient, buildResponsesSuccessOptions({
2358
- client: this.phClient,
2359
- provider: 'openai',
2360
- baseURL: this.baseURL,
2361
- params: openAIParams,
2362
- monitoring: posthogParams,
2363
- modelParametersSource: body
2364
- }, {
2365
- response: result,
2366
- output: formatResponseOpenAI({
2367
- output: result.output
2368
- }),
2369
- latency: (Date.now() - startTime) / 1000,
2370
- includeTools: true,
2371
- includeRequestId: true
2372
- }));
2373
- }
2374
- return result;
2375
- }, async error => {
2376
- await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
2377
- client: this.phClient,
2378
- provider: 'openai',
2379
- baseURL: this.baseURL,
2380
- params: openAIParams,
2381
- monitoring: posthogParams,
2382
- modelParametersSource: body
2383
- }, error, {
2384
- latency: (Date.now() - startTime) / 1000
2385
- }));
2386
- throw error;
2387
- });
2388
- return preserveProviderPromise(parentPromise, wrappedPromise);
2389
- }
2390
- }
2391
- retrieve(responseID, query = {}, options) {
2392
- const parentPromise = super.retrieve(responseID, query, options);
2393
-
2394
- // Preserve the upstream promise and stream unchanged for responses that
2395
- // were not created through this client.
2396
- if (!this.backgroundResponses.get(responseID)) {
2397
- return parentPromise;
2398
- }
2399
- if (query.stream) {
2400
- return parentPromise._thenUnwrap(result => {
2401
- if ('controller' in result) {
2402
- return wrapBackgroundResponseStream(result, responseID, this.backgroundResponses, (response, context) => this.captureBackgroundResponse(response, context));
2403
- }
2404
- return result;
2405
- });
2406
- }
2407
- return parentPromise._thenUnwrap(async result => {
2408
- if (!('output' in result) || !isTerminalResponse(result)) {
2409
- return result;
2410
- }
2411
-
2412
- // Removing the context before capture makes concurrent or repeated
2413
- // terminal polls idempotent.
2414
- const context = this.backgroundResponses.take(responseID);
2415
- if (context) {
2416
- await this.captureBackgroundResponse(result, context).catch(() => undefined);
2417
- }
2418
- return result;
2419
- });
2420
- }
2421
- cancel(responseID, options) {
2422
- const parentPromise = super.cancel(responseID, options);
2423
-
2424
- // Avoid wrapping calls that do not belong to a background response created
2425
- // through this client, preserving the upstream APIPromise unchanged.
2426
- if (!this.backgroundResponses.get(responseID)) {
2427
- return parentPromise;
2428
- }
2429
- return parentPromise._thenUnwrap(async result => {
2430
- if (!isTerminalResponse(result)) {
2431
- return result;
2432
- }
2433
- const context = this.backgroundResponses.take(responseID);
2434
- if (context) {
2435
- await this.captureBackgroundResponse(result, context).catch(() => undefined);
2436
- }
2437
- return result;
2438
- });
2439
- }
2440
- parse(body, options) {
2441
- const {
2442
- providerParams: openAIParams,
2443
- posthogParams
2444
- } = extractPosthogParams(body);
2445
- const startTime = Date.now();
2446
- const parentPromise = callWithOriginalCreate(this, super.create.bind(this), () => super.parse(openAIParams, options));
2447
- const wrappedPromise = parentPromise.then(async result => {
2448
- if (isPendingBackgroundResponse(openAIParams, result)) {
2449
- this.backgroundResponses.set(result.id, {
2450
- openAIParams,
2451
- posthogParams
2452
- });
2453
- return result;
2454
- }
2455
- await captureAiGeneration(this.phClient, buildResponsesSuccessOptions({
2456
- client: this.phClient,
2457
- provider: 'openai',
2458
- baseURL: this.baseURL,
2459
- params: openAIParams,
2460
- monitoring: posthogParams,
2461
- modelParametersSource: body
2462
- }, {
2463
- response: result,
2464
- output: result.output,
2465
- latency: (Date.now() - startTime) / 1000,
2466
- includeRequestId: true
2467
- }));
2468
- return result;
2469
- }, async error => {
2470
- await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
2471
- client: this.phClient,
2472
- provider: 'openai',
2473
- baseURL: this.baseURL,
2474
- params: openAIParams,
2475
- monitoring: posthogParams,
2476
- modelParametersSource: body
2477
- }, error, {
2478
- latency: (Date.now() - startTime) / 1000
2479
- }));
2480
- throw error;
2481
- });
2482
- return preserveProviderPromise(parentPromise, wrappedPromise);
2483
- }
2484
- }
2485
- class WrappedEmbeddings extends Embeddings {
2486
- constructor(client, phClient) {
2487
- super(client);
2488
- this.phClient = phClient;
2489
- this.baseURL = client.baseURL;
2490
- }
2491
- create(body, options) {
2492
- const {
2493
- providerParams: openAIParams,
2494
- posthogParams
2495
- } = extractPosthogParams(body);
2496
- const startTime = Date.now();
2497
- const parentPromise = super.create(openAIParams, options);
2498
- const wrappedPromise = parentPromise.then(async result => {
2499
- await captureAiGeneration(this.phClient, buildEmbeddingSuccessOptions({
2500
- client: this.phClient,
2501
- provider: 'openai',
2502
- baseURL: this.baseURL,
2503
- params: openAIParams,
2504
- monitoring: posthogParams,
2505
- modelParametersSource: body
2506
- }, result.usage, (Date.now() - startTime) / 1000));
2507
- return result;
2508
- }, async error => {
2509
- await captureAiGeneration(this.phClient, buildEmbeddingErrorOptions({
2510
- client: this.phClient,
2511
- provider: 'openai',
2512
- baseURL: this.baseURL,
2513
- params: openAIParams,
2514
- monitoring: posthogParams,
2515
- modelParametersSource: body
2516
- }, error, (Date.now() - startTime) / 1000));
2517
- throw error;
2518
- });
2519
- return preserveProviderPromise(parentPromise, wrappedPromise);
2520
- }
2521
- }
2522
- class WrappedAudio extends Audio {
2523
- constructor(parentClient, phClient) {
2524
- super(parentClient);
2525
- this.transcriptions = new WrappedTranscriptions(parentClient, phClient);
2526
- }
2527
- }
2528
- class WrappedTranscriptions extends Transcriptions {
2529
- constructor(client, phClient) {
2530
- super(client);
2531
- this.phClient = phClient;
2532
- this.baseURL = client.baseURL;
2533
- }
2534
-
2535
- // --- Overload #1: Non-streaming
2536
-
2537
- // --- Overload #2: Non-streaming
2538
-
2539
- // --- Overload #3: Non-streaming
2540
-
2541
- // --- Overload #4: Non-streaming
2542
-
2543
- // --- Overload #5: Streaming
2544
-
2545
- // --- Overload #6: Streaming
2546
-
2547
- // --- Overload #7: Generic base
2548
-
2549
- // --- Implementation Signature
2550
- create(body, options) {
2551
- const {
2552
- providerParams: openAIParams,
2553
- posthogParams
2554
- } = extractPosthogParams(body);
2555
- const startTime = Date.now();
2556
- const parentPromise = openAIParams.stream ? super.create(openAIParams, options) : super.create(openAIParams, options);
2557
- if (openAIParams.stream) {
2558
- const wrappedPromise = parentPromise.then(value => {
2559
- if (Symbol.asyncIterator in value) {
2560
- const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
2561
- (async () => {
2562
- let usage = {};
2563
- try {
2564
- let finalContent = '';
2565
- let firstTokenTime;
2566
- const doneEvent = 'transcript.text.done';
2567
- for await (const chunk of stream1) {
2568
- // Track first token on text delta events
2569
- if (firstTokenTime === undefined && chunk.type === 'transcript.text.delta') {
2570
- firstTokenTime = Date.now();
2571
- }
2572
- if (chunk.type === doneEvent && 'text' in chunk && chunk.text && chunk.text.length > 0) {
2573
- finalContent = chunk.text;
2574
- }
2575
- if ('usage' in chunk && chunk.usage) {
2576
- usage = {
2577
- inputTokens: chunk.usage?.type === 'tokens' ? chunk.usage.input_tokens ?? 0 : 0,
2578
- outputTokens: chunk.usage?.type === 'tokens' ? chunk.usage.output_tokens ?? 0 : 0,
2579
- rawUsage: chunk.usage
2580
- };
2581
- }
2582
- }
2583
- const latency = (Date.now() - startTime) / 1000;
2584
- const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
2585
- const availableTools = extractAvailableToolCalls('openai', openAIParams);
2586
- await captureAiGeneration(this.phClient, {
2587
- ...posthogParams,
2588
- model: openAIParams.model,
2589
- provider: 'openai',
2590
- input: openAIParams.prompt,
2591
- output: sanitizeOpenAIResponse(finalContent, this.phClient),
2592
- latency,
2593
- timeToFirstToken,
2594
- baseURL: this.baseURL,
2595
- modelParameters: getModelParams(body),
2596
- httpStatus: 200,
2597
- usage,
2598
- tools: availableTools
2599
- });
2600
- } catch (error) {
2601
- await captureAiGeneration(this.phClient, {
2602
- ...posthogParams,
2603
- model: openAIParams.model,
2604
- provider: 'openai',
2605
- input: openAIParams.prompt,
2606
- output: [],
2607
- latency: (Date.now() - startTime) / 1000,
2608
- baseURL: this.baseURL,
2609
- modelParameters: getModelParams(body),
2610
- usage,
2611
- error
2612
- });
2613
- throw error;
2614
- }
2615
- })().catch(() => {
2616
- // Swallow: analytics must never crash the host process. The caller
2617
- // already receives this error via their own tee of the stream.
2618
- });
2619
- return stream2;
2620
- }
2621
- return value;
2622
- });
2623
- return preserveProviderPromise(parentPromise, wrappedPromise);
2624
- } else {
2625
- const wrappedPromise = parentPromise.then(async result => {
2626
- if (result && typeof result === 'object' && 'text' in result) {
2627
- const latency = (Date.now() - startTime) / 1000;
2628
- await captureAiGenerationAfterSuccess(this.phClient, {
2629
- ...posthogParams,
2630
- model: openAIParams.model,
2631
- provider: 'openai',
2632
- input: openAIParams.prompt,
2633
- output: sanitizeOpenAIResponse(result.text, this.phClient),
2634
- latency,
2635
- baseURL: this.baseURL,
2636
- modelParameters: getModelParams(body),
2637
- httpStatus: 200,
2638
- usage: {
2639
- inputTokens: result.usage?.type === 'tokens' ? result.usage.input_tokens ?? 0 : 0,
2640
- outputTokens: result.usage?.type === 'tokens' ? result.usage.output_tokens ?? 0 : 0,
2641
- rawUsage: result.usage
2642
- }
2643
- });
2644
- }
2645
- return result;
2646
- }, async error => {
2647
- await captureAiGeneration(this.phClient, {
2648
- ...posthogParams,
2649
- model: openAIParams.model,
2650
- provider: 'openai',
2651
- input: openAIParams.prompt,
2652
- output: [],
2653
- latency: (Date.now() - startTime) / 1000,
2654
- baseURL: this.baseURL,
2655
- modelParameters: getModelParams(body),
2656
- usage: {},
2657
- error
2658
- });
2659
- throw error;
2660
- });
2661
- return preserveProviderPromise(parentPromise, wrappedPromise);
2662
- }
2663
- }
2664
- }
2665
-
1702
+ var PostHogOpenAI = class extends openai.OpenAI {
1703
+ constructor(config) {
1704
+ const { posthog, ...openAIConfig } = config;
1705
+ super(openAIConfig);
1706
+ this.phClient = posthog;
1707
+ this.chat = new WrappedChat(this, this.phClient);
1708
+ this.responses = new WrappedResponses(this, this.phClient);
1709
+ this.embeddings = new WrappedEmbeddings(this, this.phClient);
1710
+ this.audio = new WrappedAudio(this, this.phClient);
1711
+ }
1712
+ };
1713
+ var WrappedChat = class extends Chat {
1714
+ constructor(parentClient, phClient) {
1715
+ super(parentClient);
1716
+ this.completions = new WrappedCompletions(parentClient, phClient);
1717
+ }
1718
+ };
1719
+ var WrappedCompletions = class extends Completions {
1720
+ constructor(client, phClient) {
1721
+ super(client);
1722
+ this.phClient = phClient;
1723
+ this.baseURL = client.baseURL;
1724
+ }
1725
+ create(body, options) {
1726
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
1727
+ const startTime = Date.now();
1728
+ const parentPromise = super.create(openAIParams, options);
1729
+ if (openAIParams.stream) return preserveProviderPromise(parentPromise, parentPromise.then((value) => {
1730
+ if (Symbol.asyncIterator in value) {
1731
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new openai_streaming.Stream(iterator, controller));
1732
+ (async () => {
1733
+ const accumulator = new OpenAIChatStreamAccumulator();
1734
+ try {
1735
+ for await (const chunk of stream1) accumulator.consume(chunk);
1736
+ const accumulated = accumulator.result();
1737
+ await captureAiGeneration(this.phClient, buildChatSuccessOptions({
1738
+ client: this.phClient,
1739
+ provider: "openai",
1740
+ baseURL: this.baseURL,
1741
+ params: openAIParams,
1742
+ monitoring: posthogParams,
1743
+ modelParametersSource: body
1744
+ }, {
1745
+ ...accumulated,
1746
+ latency: (Date.now() - startTime) / 1e3,
1747
+ timeToFirstToken: accumulated.firstTokenTime === void 0 ? void 0 : (accumulated.firstTokenTime - startTime) / 1e3
1748
+ }));
1749
+ } catch (error) {
1750
+ const accumulated = accumulator.result();
1751
+ await captureAiGeneration(this.phClient, buildChatErrorOptions({
1752
+ client: this.phClient,
1753
+ provider: "openai",
1754
+ baseURL: this.baseURL,
1755
+ params: openAIParams,
1756
+ monitoring: posthogParams,
1757
+ modelParametersSource: body
1758
+ }, error, {
1759
+ completionId: accumulated.completionId,
1760
+ systemFingerprint: accumulated.systemFingerprint,
1761
+ usage: accumulated.usage,
1762
+ latency: (Date.now() - startTime) / 1e3
1763
+ }));
1764
+ throw error;
1765
+ }
1766
+ })().catch(() => {});
1767
+ return stream2;
1768
+ }
1769
+ return value;
1770
+ }));
1771
+ else return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
1772
+ if ("choices" in result) await captureAiGenerationAfterSuccess(this.phClient, buildChatSuccessOptions({
1773
+ client: this.phClient,
1774
+ provider: "openai",
1775
+ baseURL: this.baseURL,
1776
+ params: openAIParams,
1777
+ monitoring: posthogParams,
1778
+ modelParametersSource: body
1779
+ }, {
1780
+ output: formatResponseOpenAI(result),
1781
+ model: result.model,
1782
+ serviceTier: result.service_tier ?? void 0,
1783
+ latency: (Date.now() - startTime) / 1e3,
1784
+ usage: buildChatUsage(result.usage, result),
1785
+ stopReason: result.choices[0]?.finish_reason ?? void 0,
1786
+ completionId: result.id,
1787
+ systemFingerprint: result.system_fingerprint,
1788
+ requestId: extractRequestId(result)
1789
+ }));
1790
+ return result;
1791
+ }, async (error) => {
1792
+ await captureAiGeneration(this.phClient, buildChatErrorOptions({
1793
+ client: this.phClient,
1794
+ provider: "openai",
1795
+ baseURL: this.baseURL,
1796
+ params: openAIParams,
1797
+ monitoring: posthogParams,
1798
+ modelParametersSource: body
1799
+ }, error, { latency: (Date.now() - startTime) / 1e3 }));
1800
+ throw error;
1801
+ }));
1802
+ }
1803
+ };
1804
+ var WrappedResponses = class extends Responses {
1805
+ constructor(client, phClient) {
1806
+ super(client);
1807
+ this.backgroundResponses = new BackgroundResponseTracker();
1808
+ this.phClient = phClient;
1809
+ this.baseURL = client.baseURL;
1810
+ }
1811
+ async captureBackgroundResponse(result, context) {
1812
+ const { openAIParams, posthogParams } = context;
1813
+ await captureAiGenerationAfterSuccess(this.phClient, buildBackgroundResponseOptions({
1814
+ client: this.phClient,
1815
+ provider: "openai",
1816
+ baseURL: this.baseURL,
1817
+ params: openAIParams,
1818
+ monitoring: posthogParams,
1819
+ modelParametersSource: openAIParams
1820
+ }, result));
1821
+ }
1822
+ create(body, options) {
1823
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
1824
+ const startTime = Date.now();
1825
+ const parentPromise = super.create(openAIParams, options);
1826
+ if (openAIParams.stream) return preserveProviderPromise(parentPromise, parentPromise.then((value) => {
1827
+ if (Symbol.asyncIterator in value) {
1828
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new openai_streaming.Stream(iterator, controller));
1829
+ (async () => {
1830
+ const accumulator = new OpenAIResponsesStreamAccumulator();
1831
+ try {
1832
+ for await (const chunk of stream1) {
1833
+ accumulator.consume(chunk);
1834
+ if (openAIParams.background === true && "response" in chunk && chunk.response && !this.backgroundResponses.get(chunk.response.id)) this.backgroundResponses.set(chunk.response.id, {
1835
+ openAIParams,
1836
+ posthogParams
1837
+ });
1838
+ }
1839
+ const accumulated = accumulator.result();
1840
+ if (openAIParams.background === true) {
1841
+ if (accumulated.terminalResponse) {
1842
+ const context = this.backgroundResponses.take(accumulated.terminalResponse.id);
1843
+ if (context) await this.captureBackgroundResponse(accumulated.terminalResponse, context).catch(() => void 0);
1844
+ }
1845
+ return;
1846
+ }
1847
+ const response = accumulated.terminalResponse ?? {
1848
+ id: accumulated.completionId ?? "",
1849
+ model: accumulated.model ?? openAIParams.model,
1850
+ service_tier: accumulated.serviceTier
1851
+ };
1852
+ await captureAiGeneration(this.phClient, buildResponsesSuccessOptions({
1853
+ client: this.phClient,
1854
+ provider: "openai",
1855
+ baseURL: this.baseURL,
1856
+ params: openAIParams,
1857
+ monitoring: posthogParams,
1858
+ modelParametersSource: body
1859
+ }, {
1860
+ response,
1861
+ output: accumulated.output,
1862
+ latency: (Date.now() - startTime) / 1e3,
1863
+ timeToFirstToken: accumulated.firstTokenTime === void 0 ? void 0 : (accumulated.firstTokenTime - startTime) / 1e3,
1864
+ usage: accumulated.usage,
1865
+ includeTools: true
1866
+ }));
1867
+ } catch (error) {
1868
+ const accumulated = accumulator.result();
1869
+ if (openAIParams.background === true && accumulated.completionId && this.backgroundResponses.get(accumulated.completionId)) throw error;
1870
+ await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
1871
+ client: this.phClient,
1872
+ provider: "openai",
1873
+ baseURL: this.baseURL,
1874
+ params: openAIParams,
1875
+ monitoring: posthogParams,
1876
+ modelParametersSource: body
1877
+ }, error, {
1878
+ completionId: accumulated.completionId,
1879
+ usage: accumulated.usage,
1880
+ latency: (Date.now() - startTime) / 1e3
1881
+ }));
1882
+ throw error;
1883
+ }
1884
+ })().catch(() => {});
1885
+ return stream2;
1886
+ }
1887
+ return value;
1888
+ }));
1889
+ else return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
1890
+ if ("output" in result) {
1891
+ if (isPendingBackgroundResponse(openAIParams, result)) {
1892
+ this.backgroundResponses.set(result.id, {
1893
+ openAIParams,
1894
+ posthogParams
1895
+ });
1896
+ return result;
1897
+ }
1898
+ await captureAiGenerationAfterSuccess(this.phClient, buildResponsesSuccessOptions({
1899
+ client: this.phClient,
1900
+ provider: "openai",
1901
+ baseURL: this.baseURL,
1902
+ params: openAIParams,
1903
+ monitoring: posthogParams,
1904
+ modelParametersSource: body
1905
+ }, {
1906
+ response: result,
1907
+ output: formatResponseOpenAI({ output: result.output }),
1908
+ latency: (Date.now() - startTime) / 1e3,
1909
+ includeTools: true,
1910
+ includeRequestId: true
1911
+ }));
1912
+ }
1913
+ return result;
1914
+ }, async (error) => {
1915
+ await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
1916
+ client: this.phClient,
1917
+ provider: "openai",
1918
+ baseURL: this.baseURL,
1919
+ params: openAIParams,
1920
+ monitoring: posthogParams,
1921
+ modelParametersSource: body
1922
+ }, error, { latency: (Date.now() - startTime) / 1e3 }));
1923
+ throw error;
1924
+ }));
1925
+ }
1926
+ retrieve(responseID, query = {}, options) {
1927
+ const parentPromise = super.retrieve(responseID, query, options);
1928
+ if (!this.backgroundResponses.get(responseID)) return parentPromise;
1929
+ if (query.stream) return parentPromise._thenUnwrap((result) => {
1930
+ if ("controller" in result) return wrapBackgroundResponseStream(result, responseID, this.backgroundResponses, (response, context) => this.captureBackgroundResponse(response, context));
1931
+ return result;
1932
+ });
1933
+ return parentPromise._thenUnwrap(async (result) => {
1934
+ if (!("output" in result) || !isTerminalResponse(result)) return result;
1935
+ const context = this.backgroundResponses.take(responseID);
1936
+ if (context) await this.captureBackgroundResponse(result, context).catch(() => void 0);
1937
+ return result;
1938
+ });
1939
+ }
1940
+ cancel(responseID, options) {
1941
+ const parentPromise = super.cancel(responseID, options);
1942
+ if (!this.backgroundResponses.get(responseID)) return parentPromise;
1943
+ return parentPromise._thenUnwrap(async (result) => {
1944
+ if (!isTerminalResponse(result)) return result;
1945
+ const context = this.backgroundResponses.take(responseID);
1946
+ if (context) await this.captureBackgroundResponse(result, context).catch(() => void 0);
1947
+ return result;
1948
+ });
1949
+ }
1950
+ parse(body, options) {
1951
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
1952
+ const startTime = Date.now();
1953
+ const parentPromise = callWithOriginalCreate(this, super.create.bind(this), () => super.parse(openAIParams, options));
1954
+ return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
1955
+ if (isPendingBackgroundResponse(openAIParams, result)) {
1956
+ this.backgroundResponses.set(result.id, {
1957
+ openAIParams,
1958
+ posthogParams
1959
+ });
1960
+ return result;
1961
+ }
1962
+ await captureAiGeneration(this.phClient, buildResponsesSuccessOptions({
1963
+ client: this.phClient,
1964
+ provider: "openai",
1965
+ baseURL: this.baseURL,
1966
+ params: openAIParams,
1967
+ monitoring: posthogParams,
1968
+ modelParametersSource: body
1969
+ }, {
1970
+ response: result,
1971
+ output: result.output,
1972
+ latency: (Date.now() - startTime) / 1e3,
1973
+ includeRequestId: true
1974
+ }));
1975
+ return result;
1976
+ }, async (error) => {
1977
+ await captureAiGeneration(this.phClient, buildResponsesErrorOptions({
1978
+ client: this.phClient,
1979
+ provider: "openai",
1980
+ baseURL: this.baseURL,
1981
+ params: openAIParams,
1982
+ monitoring: posthogParams,
1983
+ modelParametersSource: body
1984
+ }, error, { latency: (Date.now() - startTime) / 1e3 }));
1985
+ throw error;
1986
+ }));
1987
+ }
1988
+ };
1989
+ var WrappedEmbeddings = class extends Embeddings {
1990
+ constructor(client, phClient) {
1991
+ super(client);
1992
+ this.phClient = phClient;
1993
+ this.baseURL = client.baseURL;
1994
+ }
1995
+ create(body, options) {
1996
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
1997
+ const startTime = Date.now();
1998
+ const parentPromise = super.create(openAIParams, options);
1999
+ return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
2000
+ await captureAiGeneration(this.phClient, buildEmbeddingSuccessOptions({
2001
+ client: this.phClient,
2002
+ provider: "openai",
2003
+ baseURL: this.baseURL,
2004
+ params: openAIParams,
2005
+ monitoring: posthogParams,
2006
+ modelParametersSource: body
2007
+ }, result.usage, (Date.now() - startTime) / 1e3));
2008
+ return result;
2009
+ }, async (error) => {
2010
+ await captureAiGeneration(this.phClient, buildEmbeddingErrorOptions({
2011
+ client: this.phClient,
2012
+ provider: "openai",
2013
+ baseURL: this.baseURL,
2014
+ params: openAIParams,
2015
+ monitoring: posthogParams,
2016
+ modelParametersSource: body
2017
+ }, error, (Date.now() - startTime) / 1e3));
2018
+ throw error;
2019
+ }));
2020
+ }
2021
+ };
2022
+ var WrappedAudio = class extends Audio {
2023
+ constructor(parentClient, phClient) {
2024
+ super(parentClient);
2025
+ this.transcriptions = new WrappedTranscriptions(parentClient, phClient);
2026
+ }
2027
+ };
2028
+ var WrappedTranscriptions = class extends Transcriptions {
2029
+ constructor(client, phClient) {
2030
+ super(client);
2031
+ this.phClient = phClient;
2032
+ this.baseURL = client.baseURL;
2033
+ }
2034
+ create(body, options) {
2035
+ const { providerParams: openAIParams, posthogParams } = extractPosthogParams(body);
2036
+ const startTime = Date.now();
2037
+ const parentPromise = openAIParams.stream ? super.create(openAIParams, options) : super.create(openAIParams, options);
2038
+ if (openAIParams.stream) return preserveProviderPromise(parentPromise, parentPromise.then((value) => {
2039
+ if (Symbol.asyncIterator in value) {
2040
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new openai_streaming.Stream(iterator, controller));
2041
+ (async () => {
2042
+ let usage = {};
2043
+ try {
2044
+ let finalContent = "";
2045
+ let firstTokenTime;
2046
+ const doneEvent = "transcript.text.done";
2047
+ for await (const chunk of stream1) {
2048
+ if (firstTokenTime === void 0 && chunk.type === "transcript.text.delta") firstTokenTime = Date.now();
2049
+ if (chunk.type === doneEvent && "text" in chunk && chunk.text && chunk.text.length > 0) finalContent = chunk.text;
2050
+ if ("usage" in chunk && chunk.usage) usage = {
2051
+ inputTokens: chunk.usage?.type === "tokens" ? chunk.usage.input_tokens ?? 0 : 0,
2052
+ outputTokens: chunk.usage?.type === "tokens" ? chunk.usage.output_tokens ?? 0 : 0,
2053
+ rawUsage: chunk.usage
2054
+ };
2055
+ }
2056
+ const latency = (Date.now() - startTime) / 1e3;
2057
+ const timeToFirstToken = firstTokenTime !== void 0 ? (firstTokenTime - startTime) / 1e3 : void 0;
2058
+ const availableTools = extractAvailableToolCalls("openai", openAIParams);
2059
+ await captureAiGeneration(this.phClient, {
2060
+ ...posthogParams,
2061
+ model: openAIParams.model,
2062
+ provider: "openai",
2063
+ input: openAIParams.prompt,
2064
+ output: sanitizeOpenAIResponse(finalContent, this.phClient),
2065
+ latency,
2066
+ timeToFirstToken,
2067
+ baseURL: this.baseURL,
2068
+ modelParameters: getModelParams(body),
2069
+ httpStatus: 200,
2070
+ usage,
2071
+ tools: availableTools
2072
+ });
2073
+ } catch (error) {
2074
+ await captureAiGeneration(this.phClient, {
2075
+ ...posthogParams,
2076
+ model: openAIParams.model,
2077
+ provider: "openai",
2078
+ input: openAIParams.prompt,
2079
+ output: [],
2080
+ latency: (Date.now() - startTime) / 1e3,
2081
+ baseURL: this.baseURL,
2082
+ modelParameters: getModelParams(body),
2083
+ usage,
2084
+ error
2085
+ });
2086
+ throw error;
2087
+ }
2088
+ })().catch(() => {});
2089
+ return stream2;
2090
+ }
2091
+ return value;
2092
+ }));
2093
+ else return preserveProviderPromise(parentPromise, parentPromise.then(async (result) => {
2094
+ if (result && typeof result === "object" && "text" in result) {
2095
+ const latency = (Date.now() - startTime) / 1e3;
2096
+ await captureAiGenerationAfterSuccess(this.phClient, {
2097
+ ...posthogParams,
2098
+ model: openAIParams.model,
2099
+ provider: "openai",
2100
+ input: openAIParams.prompt,
2101
+ output: sanitizeOpenAIResponse(result.text, this.phClient),
2102
+ latency,
2103
+ baseURL: this.baseURL,
2104
+ modelParameters: getModelParams(body),
2105
+ httpStatus: 200,
2106
+ usage: {
2107
+ inputTokens: result.usage?.type === "tokens" ? result.usage.input_tokens ?? 0 : 0,
2108
+ outputTokens: result.usage?.type === "tokens" ? result.usage.output_tokens ?? 0 : 0,
2109
+ rawUsage: result.usage
2110
+ }
2111
+ });
2112
+ }
2113
+ return result;
2114
+ }, async (error) => {
2115
+ await captureAiGeneration(this.phClient, {
2116
+ ...posthogParams,
2117
+ model: openAIParams.model,
2118
+ provider: "openai",
2119
+ input: openAIParams.prompt,
2120
+ output: [],
2121
+ latency: (Date.now() - startTime) / 1e3,
2122
+ baseURL: this.baseURL,
2123
+ modelParameters: getModelParams(body),
2124
+ usage: {},
2125
+ error
2126
+ });
2127
+ throw error;
2128
+ }));
2129
+ }
2130
+ };
2131
+ //#endregion
2666
2132
  exports.AzureOpenAI = PostHogAzureOpenAI;
2667
2133
  exports.OpenAI = PostHogOpenAI;
2668
2134
  exports.PostHogOpenAI = PostHogOpenAI;
2135
+ exports.default = PostHogOpenAI;
2669
2136
  exports.WrappedAudio = WrappedAudio;
2670
2137
  exports.WrappedChat = WrappedChat;
2671
2138
  exports.WrappedCompletions = WrappedCompletions;
2672
2139
  exports.WrappedEmbeddings = WrappedEmbeddings;
2673
2140
  exports.WrappedResponses = WrappedResponses;
2674
2141
  exports.WrappedTranscriptions = WrappedTranscriptions;
2675
- exports.default = PostHogOpenAI;
2676
- //# sourceMappingURL=index.cjs.map
2142
+
2143
+ //# sourceMappingURL=index.cjs.map