@posthog/ai 8.6.1 → 8.6.3
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/anthropic/index.cjs +334 -108
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +335 -109
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +121 -110
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.mjs +122 -111
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +237 -183
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +238 -184
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +19 -32
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.d.ts +1 -0
- package/dist/langchain/index.mjs +19 -32
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/openai/index.cjs +351 -125
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +352 -126
- package/dist/openai/index.mjs.map +1 -1
- package/dist/openai-agents/index.cjs +24 -4
- package/dist/openai-agents/index.cjs.map +1 -1
- package/dist/openai-agents/index.d.ts +1 -1
- package/dist/openai-agents/index.mjs +24 -4
- package/dist/openai-agents/index.mjs.map +1 -1
- package/dist/otel/index.cjs +5 -3
- package/dist/otel/index.cjs.map +1 -1
- package/dist/otel/index.mjs +5 -3
- package/dist/otel/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +238 -186
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +239 -187
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/vercel/index.cjs
CHANGED
|
@@ -397,7 +397,7 @@ function sanitizeValues(obj) {
|
|
|
397
397
|
return jsonSafe;
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
-
var version = "8.6.
|
|
400
|
+
var version = "8.6.3";
|
|
401
401
|
|
|
402
402
|
const DEFAULT_MAX_DEPTH = 3;
|
|
403
403
|
const MAX_STACK_LINES = 20;
|
|
@@ -508,120 +508,131 @@ const warnIfPostHogAiGateway = baseURL => {
|
|
|
508
508
|
* so callers can re-throw the original error reference safely.
|
|
509
509
|
*/
|
|
510
510
|
const captureAiGeneration = async (client, options) => {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
warnIfPostHogAiGateway(options.baseURL);
|
|
515
|
-
const traceId = options.traceId ?? uuid.v4();
|
|
516
|
-
const eventType = options.eventType ?? AIEvent.Generation;
|
|
517
|
-
const privacyMode = options.privacyMode ?? false;
|
|
518
|
-
const usage = options.usage ?? {};
|
|
519
|
-
const safeInput = sanitizeValues(options.input);
|
|
520
|
-
const safeOutput = sanitizeValues(options.output);
|
|
521
|
-
let httpStatus = options.httpStatus;
|
|
522
|
-
let errorData = {};
|
|
523
|
-
if (options.error) {
|
|
524
|
-
if (httpStatus === undefined) {
|
|
525
|
-
if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
|
|
526
|
-
httpStatus = options.error.status;
|
|
527
|
-
} else {
|
|
528
|
-
httpStatus = 500;
|
|
529
|
-
}
|
|
511
|
+
try {
|
|
512
|
+
if (!client.capture) {
|
|
513
|
+
return;
|
|
530
514
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
515
|
+
warnIfPostHogAiGateway(options.baseURL);
|
|
516
|
+
const traceId = options.traceId ?? uuid.v4();
|
|
517
|
+
const eventType = options.eventType ?? AIEvent.Generation;
|
|
518
|
+
const privacyMode = options.privacyMode ?? false;
|
|
519
|
+
const usage = options.usage ?? {};
|
|
520
|
+
|
|
521
|
+
// Check privacy before reading or traversing input/output. Besides avoiding
|
|
522
|
+
// needless work, this ensures hostile getters/proxies cannot observe a value
|
|
523
|
+
// that the caller explicitly requested us to redact.
|
|
524
|
+
const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
|
|
525
|
+
const safeInput = shouldRedact ? null : core.toJsonSafeValue(options.input);
|
|
526
|
+
const safeOutput = shouldRedact ? null : core.toJsonSafeValue(options.output);
|
|
527
|
+
let httpStatus = options.httpStatus;
|
|
528
|
+
let errorData = {};
|
|
529
|
+
if (options.error) {
|
|
530
|
+
if (httpStatus === undefined) {
|
|
531
|
+
if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
|
|
532
|
+
httpStatus = options.error.status;
|
|
533
|
+
} else {
|
|
534
|
+
httpStatus = 500;
|
|
535
|
+
}
|
|
539
536
|
}
|
|
537
|
+
let exceptionId;
|
|
538
|
+
if (client.options?.enableExceptionAutocapture) {
|
|
539
|
+
exceptionId = core.uuidv7();
|
|
540
|
+
client.captureException(options.error, undefined, {
|
|
541
|
+
$ai_trace_id: traceId
|
|
542
|
+
}, exceptionId);
|
|
543
|
+
if (typeof options.error === 'object') {
|
|
544
|
+
;
|
|
545
|
+
options.error.__posthog_previously_captured_error = true;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
errorData = {
|
|
549
|
+
$ai_is_error: true,
|
|
550
|
+
$ai_error: stringifyError(options.error),
|
|
551
|
+
$exception_event_id: exceptionId
|
|
552
|
+
};
|
|
540
553
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
554
|
+
httpStatus = httpStatus ?? 200;
|
|
555
|
+
let costOverrideData = {};
|
|
556
|
+
if (options.costOverride) {
|
|
557
|
+
const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
|
|
558
|
+
const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
|
|
559
|
+
costOverrideData = {
|
|
560
|
+
$ai_input_cost_usd: inputCostUSD,
|
|
561
|
+
$ai_output_cost_usd: outputCostUSD,
|
|
562
|
+
$ai_total_cost_usd: inputCostUSD + outputCostUSD
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
const additionalTokenValues = {
|
|
566
|
+
...(usage.reasoningTokens ? {
|
|
567
|
+
$ai_reasoning_tokens: usage.reasoningTokens
|
|
568
|
+
} : {}),
|
|
569
|
+
...(usage.cacheReadInputTokens ? {
|
|
570
|
+
$ai_cache_read_input_tokens: usage.cacheReadInputTokens
|
|
571
|
+
} : {}),
|
|
572
|
+
...(usage.cacheCreationInputTokens ? {
|
|
573
|
+
$ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
|
|
574
|
+
} : {}),
|
|
575
|
+
...(usage.webSearchCount ? {
|
|
576
|
+
$ai_web_search_count: usage.webSearchCount
|
|
577
|
+
} : {}),
|
|
578
|
+
...(usage.rawUsage ? {
|
|
579
|
+
$ai_usage: usage.rawUsage
|
|
580
|
+
} : {})
|
|
545
581
|
};
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
$
|
|
554
|
-
$
|
|
555
|
-
$
|
|
582
|
+
const properties = {
|
|
583
|
+
$ai_lib: 'posthog-ai',
|
|
584
|
+
$ai_lib_version: version,
|
|
585
|
+
$ai_provider: options.providerOverride ?? options.provider,
|
|
586
|
+
$ai_model: options.modelOverride ?? options.model,
|
|
587
|
+
$ai_model_parameters: options.modelParameters ?? {},
|
|
588
|
+
$ai_input: safeInput,
|
|
589
|
+
$ai_output_choices: safeOutput,
|
|
590
|
+
$ai_http_status: httpStatus,
|
|
591
|
+
$ai_input_tokens: usage.inputTokens ?? 0,
|
|
592
|
+
...(usage.outputTokens !== undefined ? {
|
|
593
|
+
$ai_output_tokens: usage.outputTokens
|
|
594
|
+
} : {}),
|
|
595
|
+
...additionalTokenValues,
|
|
596
|
+
$ai_latency: options.latency ?? 0,
|
|
597
|
+
...(options.timeToFirstToken !== undefined ? {
|
|
598
|
+
$ai_time_to_first_token: options.timeToFirstToken
|
|
599
|
+
} : {}),
|
|
600
|
+
$ai_trace_id: traceId,
|
|
601
|
+
$ai_base_url: options.baseURL ?? '',
|
|
602
|
+
...options.properties,
|
|
603
|
+
$ai_tokens_source: getTokensSource(options.properties),
|
|
604
|
+
...(options.distinctId ? {} : {
|
|
605
|
+
$process_person_profile: false
|
|
606
|
+
}),
|
|
607
|
+
...(options.stopReason ? {
|
|
608
|
+
$ai_stop_reason: options.stopReason
|
|
609
|
+
} : {}),
|
|
610
|
+
...(options.tools ? {
|
|
611
|
+
$ai_tools: options.tools
|
|
612
|
+
} : {}),
|
|
613
|
+
...(options.completionId ? {
|
|
614
|
+
$ai_completion_id: options.completionId
|
|
615
|
+
} : {}),
|
|
616
|
+
...(options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? {
|
|
617
|
+
$ai_provider_metadata: options.providerMetadata
|
|
618
|
+
} : {}),
|
|
619
|
+
...errorData,
|
|
620
|
+
...costOverrideData
|
|
556
621
|
};
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
...(usage.rawUsage ? {
|
|
572
|
-
$ai_usage: usage.rawUsage
|
|
573
|
-
} : {})
|
|
574
|
-
};
|
|
575
|
-
const properties = {
|
|
576
|
-
$ai_lib: 'posthog-ai',
|
|
577
|
-
$ai_lib_version: version,
|
|
578
|
-
$ai_provider: options.providerOverride ?? options.provider,
|
|
579
|
-
$ai_model: options.modelOverride ?? options.model,
|
|
580
|
-
$ai_model_parameters: options.modelParameters ?? {},
|
|
581
|
-
$ai_input: withPrivacyMode(client, privacyMode, safeInput),
|
|
582
|
-
$ai_output_choices: withPrivacyMode(client, privacyMode, safeOutput),
|
|
583
|
-
$ai_http_status: httpStatus,
|
|
584
|
-
$ai_input_tokens: usage.inputTokens ?? 0,
|
|
585
|
-
...(usage.outputTokens !== undefined ? {
|
|
586
|
-
$ai_output_tokens: usage.outputTokens
|
|
587
|
-
} : {}),
|
|
588
|
-
...additionalTokenValues,
|
|
589
|
-
$ai_latency: options.latency ?? 0,
|
|
590
|
-
...(options.timeToFirstToken !== undefined ? {
|
|
591
|
-
$ai_time_to_first_token: options.timeToFirstToken
|
|
592
|
-
} : {}),
|
|
593
|
-
$ai_trace_id: traceId,
|
|
594
|
-
$ai_base_url: options.baseURL ?? '',
|
|
595
|
-
...options.properties,
|
|
596
|
-
$ai_tokens_source: getTokensSource(options.properties),
|
|
597
|
-
...(options.distinctId ? {} : {
|
|
598
|
-
$process_person_profile: false
|
|
599
|
-
}),
|
|
600
|
-
...(options.stopReason ? {
|
|
601
|
-
$ai_stop_reason: options.stopReason
|
|
602
|
-
} : {}),
|
|
603
|
-
...(options.tools ? {
|
|
604
|
-
$ai_tools: options.tools
|
|
605
|
-
} : {}),
|
|
606
|
-
...(options.completionId ? {
|
|
607
|
-
$ai_completion_id: options.completionId
|
|
608
|
-
} : {}),
|
|
609
|
-
...(options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? {
|
|
610
|
-
$ai_provider_metadata: options.providerMetadata
|
|
611
|
-
} : {}),
|
|
612
|
-
...errorData,
|
|
613
|
-
...costOverrideData
|
|
614
|
-
};
|
|
615
|
-
const event = {
|
|
616
|
-
distinctId: options.distinctId ?? traceId,
|
|
617
|
-
event: eventType,
|
|
618
|
-
properties,
|
|
619
|
-
groups: options.groups
|
|
620
|
-
};
|
|
621
|
-
if (options.captureImmediate) {
|
|
622
|
-
await client.captureImmediate(event);
|
|
623
|
-
} else {
|
|
624
|
-
client.capture(event);
|
|
622
|
+
const event = {
|
|
623
|
+
distinctId: options.distinctId ?? traceId,
|
|
624
|
+
event: eventType,
|
|
625
|
+
properties,
|
|
626
|
+
groups: options.groups
|
|
627
|
+
};
|
|
628
|
+
if (options.captureImmediate) {
|
|
629
|
+
await client.captureImmediate(event);
|
|
630
|
+
} else {
|
|
631
|
+
client.capture(event);
|
|
632
|
+
}
|
|
633
|
+
} catch (error) {
|
|
634
|
+
// Telemetry failures must never affect the instrumented provider call.
|
|
635
|
+
console.warn('[PostHog AI] Failed to capture generation telemetry:', error);
|
|
625
636
|
}
|
|
626
637
|
};
|
|
627
638
|
|
|
@@ -1121,86 +1132,97 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1121
1132
|
|
|
1122
1133
|
// Map to track in-progress tool calls
|
|
1123
1134
|
const toolCallsInProgress = new Map();
|
|
1135
|
+
const captureStreamGeneration = async captureOptions => {
|
|
1136
|
+
try {
|
|
1137
|
+
await captureAiGeneration(phClient, captureOptions);
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
// Telemetry must never change the provider stream's behavior.
|
|
1140
|
+
console.warn('[PostHog AI] Failed to capture Vercel stream telemetry:', error);
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1124
1143
|
try {
|
|
1125
1144
|
const {
|
|
1126
1145
|
stream,
|
|
1127
1146
|
...rest
|
|
1128
1147
|
} = await model.doStream(params);
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1148
|
+
const reader = stream.getReader();
|
|
1149
|
+
let inBandError;
|
|
1150
|
+
let hasInBandError = false;
|
|
1151
|
+
let finalizationPromise;
|
|
1152
|
+
const observeChunk = chunk => {
|
|
1153
|
+
// Handle streaming patterns - compatible with both V2 and V3
|
|
1154
|
+
if (chunk.type === 'text-delta') {
|
|
1155
|
+
if (firstTokenTime === undefined) {
|
|
1156
|
+
firstTokenTime = Date.now();
|
|
1137
1157
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1158
|
+
generatedText += chunk.delta;
|
|
1159
|
+
}
|
|
1160
|
+
if (chunk.type === 'reasoning-delta') {
|
|
1161
|
+
if (firstTokenTime === undefined) {
|
|
1162
|
+
firstTokenTime = Date.now();
|
|
1143
1163
|
}
|
|
1164
|
+
reasoningText += chunk.delta;
|
|
1165
|
+
}
|
|
1144
1166
|
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
}
|
|
1150
|
-
// Initialize a new tool call
|
|
1151
|
-
toolCallsInProgress.set(chunk.id, {
|
|
1152
|
-
toolCallId: chunk.id,
|
|
1153
|
-
toolName: chunk.toolName,
|
|
1154
|
-
input: ''
|
|
1155
|
-
});
|
|
1156
|
-
}
|
|
1157
|
-
if (chunk.type === 'tool-input-delta') {
|
|
1158
|
-
// Accumulate tool call arguments
|
|
1159
|
-
const toolCall = toolCallsInProgress.get(chunk.id);
|
|
1160
|
-
if (toolCall) {
|
|
1161
|
-
toolCall.input += chunk.delta;
|
|
1162
|
-
}
|
|
1167
|
+
// Handle tool call chunks
|
|
1168
|
+
if (chunk.type === 'tool-input-start') {
|
|
1169
|
+
if (firstTokenTime === undefined) {
|
|
1170
|
+
firstTokenTime = Date.now();
|
|
1163
1171
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1172
|
+
toolCallsInProgress.set(chunk.id, {
|
|
1173
|
+
toolCallId: chunk.id,
|
|
1174
|
+
toolName: chunk.toolName,
|
|
1175
|
+
input: ''
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
if (chunk.type === 'tool-input-delta') {
|
|
1179
|
+
const toolCall = toolCallsInProgress.get(chunk.id);
|
|
1180
|
+
if (toolCall) {
|
|
1181
|
+
toolCall.input += chunk.delta;
|
|
1166
1182
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
// Direct tool call chunk (complete tool call)
|
|
1172
|
-
toolCallsInProgress.set(chunk.toolCallId, {
|
|
1173
|
-
toolCallId: chunk.toolCallId,
|
|
1174
|
-
toolName: chunk.toolName,
|
|
1175
|
-
input: chunk.input
|
|
1176
|
-
});
|
|
1183
|
+
}
|
|
1184
|
+
if (chunk.type === 'tool-call') {
|
|
1185
|
+
if (firstTokenTime === undefined) {
|
|
1186
|
+
firstTokenTime = Date.now();
|
|
1177
1187
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1188
|
+
toolCallsInProgress.set(chunk.toolCallId, {
|
|
1189
|
+
toolCallId: chunk.toolCallId,
|
|
1190
|
+
toolName: chunk.toolName,
|
|
1191
|
+
input: chunk.input
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
if (chunk.type === 'error') {
|
|
1195
|
+
hasInBandError = true;
|
|
1196
|
+
inBandError = chunk.error;
|
|
1197
|
+
}
|
|
1198
|
+
if (chunk.type === 'finish') {
|
|
1199
|
+
providerMetadata = chunk.providerMetadata;
|
|
1200
|
+
const chunkUsage = chunk.usage || {};
|
|
1201
|
+
const additionalTokenValues = extractAdditionalTokenValues(providerMetadata, chunkUsage);
|
|
1202
|
+
usage = {
|
|
1203
|
+
inputTokens: extractTokenCount(chunk.usage?.inputTokens),
|
|
1204
|
+
outputTokens: extractTokenCount(chunk.usage?.outputTokens),
|
|
1205
|
+
reasoningTokens: extractReasoningTokens(chunkUsage),
|
|
1206
|
+
cacheReadInputTokens: extractCacheReadTokens(chunkUsage),
|
|
1207
|
+
...additionalTokenValues
|
|
1208
|
+
};
|
|
1189
1209
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
}
|
|
1210
|
+
// Extract finish reason - V2 returns a string, V3 returns an object with .unified
|
|
1211
|
+
const rawFinishReason = chunk.finishReason;
|
|
1212
|
+
if (typeof rawFinishReason === 'string') {
|
|
1213
|
+
stopReason = rawFinishReason;
|
|
1214
|
+
} else if (rawFinishReason && typeof rawFinishReason === 'object' && 'unified' in rawFinishReason) {
|
|
1215
|
+
stopReason = String(rawFinishReason.unified);
|
|
1197
1216
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
const finalize = (terminalError, isError = false) => {
|
|
1220
|
+
if (finalizationPromise) {
|
|
1221
|
+
return finalizationPromise;
|
|
1222
|
+
}
|
|
1223
|
+
finalizationPromise = (async () => {
|
|
1201
1224
|
const latency = (Date.now() - startTime) / 1000;
|
|
1202
1225
|
const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
|
|
1203
|
-
// Build content array similar to mapVercelOutput structure
|
|
1204
1226
|
const content = [];
|
|
1205
1227
|
if (reasoningText) {
|
|
1206
1228
|
content.push({
|
|
@@ -1214,8 +1236,6 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1214
1236
|
text: truncate(generatedText)
|
|
1215
1237
|
});
|
|
1216
1238
|
}
|
|
1217
|
-
|
|
1218
|
-
// Add completed tool calls to content
|
|
1219
1239
|
for (const toolCall of toolCallsInProgress.values()) {
|
|
1220
1240
|
if (toolCall.toolName) {
|
|
1221
1241
|
content.push({
|
|
@@ -1228,15 +1248,11 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1228
1248
|
});
|
|
1229
1249
|
}
|
|
1230
1250
|
}
|
|
1231
|
-
|
|
1232
|
-
// Structure output like mapVercelOutput does
|
|
1233
1251
|
const output = content.length > 0 ? [{
|
|
1234
1252
|
role: 'assistant',
|
|
1235
1253
|
content: content.length === 1 && content[0].type === 'text' ? content[0].text : content
|
|
1236
1254
|
}] : [];
|
|
1237
1255
|
const webSearchCount = extractWebSearchCount(providerMetadata, usage);
|
|
1238
|
-
|
|
1239
|
-
// Update usage with web search count and raw metadata
|
|
1240
1256
|
const finalUsage = {
|
|
1241
1257
|
...usage,
|
|
1242
1258
|
webSearchCount,
|
|
@@ -1246,29 +1262,65 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1246
1262
|
}
|
|
1247
1263
|
};
|
|
1248
1264
|
adjustAnthropicV3CacheTokens(model, modelId, provider, finalUsage);
|
|
1249
|
-
|
|
1265
|
+
const finishError = stopReason === 'error' ? new Error('Vercel AI SDK stream finished with an error') : undefined;
|
|
1266
|
+
const error = isError ? terminalError ?? new Error('Vercel AI SDK stream failed') : hasInBandError ? inBandError ?? new Error('Vercel AI SDK stream emitted an error chunk') : finishError;
|
|
1267
|
+
await captureStreamGeneration({
|
|
1250
1268
|
...baseOptions,
|
|
1251
1269
|
model: modelId,
|
|
1252
1270
|
provider: provider,
|
|
1253
1271
|
input: mergedOptions.posthogPrivacyMode ? '' : mapVercelPrompt(params.prompt),
|
|
1254
|
-
output
|
|
1272
|
+
output,
|
|
1255
1273
|
latency,
|
|
1256
1274
|
timeToFirstToken,
|
|
1257
1275
|
baseURL,
|
|
1258
1276
|
modelParameters: getModelParams(mergedParams),
|
|
1259
|
-
httpStatus: 200,
|
|
1277
|
+
httpStatus: error ? undefined : 200,
|
|
1260
1278
|
usage: finalUsage,
|
|
1261
1279
|
stopReason,
|
|
1280
|
+
error,
|
|
1262
1281
|
tools: availableTools
|
|
1263
1282
|
});
|
|
1283
|
+
})().catch(error => {
|
|
1284
|
+
// Building telemetry must not change the provider stream's behavior.
|
|
1285
|
+
console.warn('[PostHog AI] Failed to capture Vercel stream telemetry:', error);
|
|
1286
|
+
});
|
|
1287
|
+
return finalizationPromise;
|
|
1288
|
+
};
|
|
1289
|
+
const instrumentedStream = new ReadableStream({
|
|
1290
|
+
async pull(controller) {
|
|
1291
|
+
let result;
|
|
1292
|
+
try {
|
|
1293
|
+
result = await reader.read();
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
void finalize(error, true);
|
|
1296
|
+
controller.error(error);
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
if (result.done) {
|
|
1300
|
+
controller.close();
|
|
1301
|
+
void finalize();
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
try {
|
|
1305
|
+
observeChunk(result.value);
|
|
1306
|
+
} catch {
|
|
1307
|
+
// Instrumentation must not alter or suppress provider chunks.
|
|
1308
|
+
}
|
|
1309
|
+
controller.enqueue(result.value);
|
|
1310
|
+
},
|
|
1311
|
+
cancel(reason) {
|
|
1312
|
+
void finalize(reason ?? new Error('Vercel AI SDK stream was cancelled'), true);
|
|
1313
|
+
return reader.cancel(reason);
|
|
1264
1314
|
}
|
|
1315
|
+
}, {
|
|
1316
|
+
highWaterMark: 0
|
|
1265
1317
|
});
|
|
1266
1318
|
return {
|
|
1267
|
-
stream:
|
|
1319
|
+
stream: instrumentedStream,
|
|
1268
1320
|
...rest
|
|
1269
1321
|
};
|
|
1270
1322
|
} catch (error) {
|
|
1271
|
-
await
|
|
1323
|
+
await captureStreamGeneration({
|
|
1272
1324
|
...baseOptions,
|
|
1273
1325
|
model: modelId,
|
|
1274
1326
|
provider: provider,
|