@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.
- package/dist/adk/index.cjs +908 -1198
- package/dist/adk/index.cjs.map +1 -1
- package/dist/adk/index.d.ts +109 -109
- package/dist/adk/index.mjs +907 -1196
- package/dist/adk/index.mjs.map +1 -1
- package/dist/anthropic/index.cjs +927 -1111
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.d.ts +34 -33
- package/dist/anthropic/index.mjs +899 -1102
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +863 -1108
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.d.ts +38 -35
- package/dist/gemini/index.mjs +858 -1103
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +1218 -1546
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +170 -163
- package/dist/index.mjs +1216 -1544
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +851 -1029
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.d.ts +75 -75
- package/dist/langchain/index.mjs +850 -1027
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/langchain/middleware/index.cjs +1016 -1225
- package/dist/langchain/middleware/index.cjs.map +1 -1
- package/dist/langchain/middleware/index.d.ts +29 -25
- package/dist/langchain/middleware/index.mjs +1015 -1223
- package/dist/langchain/middleware/index.mjs.map +1 -1
- package/dist/openai/index.cjs +1990 -2523
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.d.ts +106 -104
- package/dist/openai/index.mjs +1985 -2518
- package/dist/openai/index.mjs.map +1 -1
- package/dist/openai-agents/index.cjs +745 -827
- package/dist/openai-agents/index.cjs.map +1 -1
- package/dist/openai-agents/index.d.ts +48 -47
- package/dist/openai-agents/index.mjs +744 -825
- package/dist/openai-agents/index.mjs.map +1 -1
- package/dist/otel/index.cjs +427 -486
- package/dist/otel/index.cjs.map +1 -1
- package/dist/otel/index.d.ts +36 -35
- package/dist/otel/index.mjs +426 -484
- package/dist/otel/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +992 -1343
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.d.ts +21 -16
- package/dist/vercel/index.mjs +991 -1341
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +15 -14
package/dist/openai/index.cjs
CHANGED
|
@@ -1,2676 +1,2143 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
/** @internal */
|
|
19
|
-
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/captureAiEvent.ts
|
|
20
15
|
/** @internal */
|
|
21
16
|
function isFullAiCaptureEnabled(client) {
|
|
22
|
-
|
|
17
|
+
return client?.enableFullAiCapture === true;
|
|
23
18
|
}
|
|
24
|
-
|
|
25
19
|
/** @internal */
|
|
26
20
|
function captureAiEvent(client, event) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
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
|
-
|
|
202
|
-
|
|
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
|
-
|
|
230
|
+
return !!posthogProperties && Object.keys(posthogProperties).some((key) => TOKEN_PROPERTY_KEYS.has(key));
|
|
206
231
|
}
|
|
207
232
|
function getTokensSource(posthogProperties) {
|
|
208
|
-
|
|
233
|
+
return hasTokenOverrides(posthogProperties) ? "passthrough" : "sdk";
|
|
209
234
|
}
|
|
210
|
-
const STRING_FORMAT =
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
351
|
+
return client.privacy_mode || privacyMode ? null : input;
|
|
365
352
|
};
|
|
366
|
-
|
|
367
353
|
/**
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
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
|
-
|
|
473
|
-
|
|
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
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
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
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
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
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
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
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
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
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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
|
-
|
|
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
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
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
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
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
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
const
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
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
|
-
|
|
660
|
-
|
|
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
|
-
|
|
667
|
-
|
|
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
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
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
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
const INPUT_OR_CACHE_TOKEN_KEYS = [
|
|
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
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
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
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
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
|
-
|
|
898
|
-
|
|
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
|
-
|
|
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
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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
|
-
|
|
721
|
+
return result?._request_id ?? void 0;
|
|
912
722
|
}
|
|
913
|
-
|
|
914
723
|
/**
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
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
|
-
|
|
732
|
+
return details?.cache_write_tokens ?? 0;
|
|
924
733
|
}
|
|
925
|
-
|
|
926
734
|
/**
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
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
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
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([
|
|
947
|
-
|
|
748
|
+
const TERMINAL_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
|
|
749
|
+
"completed",
|
|
750
|
+
"failed",
|
|
751
|
+
"cancelled",
|
|
752
|
+
"incomplete"
|
|
753
|
+
]);
|
|
948
754
|
/**
|
|
949
|
-
|
|
950
|
-
|
|
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
|
-
|
|
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
|
-
|
|
958
|
-
|
|
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
|
-
|
|
962
|
-
|
|
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
|
-
|
|
784
|
+
return params.background === true && !!response.status && !isTerminalResponse(response);
|
|
971
785
|
}
|
|
972
|
-
|
|
973
786
|
/**
|
|
974
|
-
|
|
975
|
-
|
|
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
|
-
|
|
979
|
-
|
|
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
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
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
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
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
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
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
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
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
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
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
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
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
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
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
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
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
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
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
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
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
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
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
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
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
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1522
|
-
|
|
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
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
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
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
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
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
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
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
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
|
-
|
|
1286
|
+
return formatOpenAIResponsesInput(sanitizeOpenAIResponse(context.params.input, context.client), sanitizeOpenAIResponse(context.params.instructions, context.client));
|
|
1591
1287
|
}
|
|
1592
1288
|
function buildResponsesSuccessOptions(context, result) {
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
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
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
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
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
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
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
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
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
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
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
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
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
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
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
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
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
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
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
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
|
-
|
|
2676
|
-
//# sourceMappingURL=index.cjs.map
|
|
2142
|
+
|
|
2143
|
+
//# sourceMappingURL=index.cjs.map
|