@posthog/ai 8.14.4 → 8.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/adk/index.cjs +22 -7
- package/dist/adk/index.cjs.map +1 -1
- package/dist/adk/index.mjs +22 -7
- package/dist/adk/index.mjs.map +1 -1
- package/dist/anthropic/index.cjs +12 -5
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +12 -5
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/claude-agent-sdk/index.cjs +12 -5
- package/dist/claude-agent-sdk/index.cjs.map +1 -1
- package/dist/claude-agent-sdk/index.mjs +12 -5
- package/dist/claude-agent-sdk/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +403 -19
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.d.ts +28 -0
- package/dist/gemini/index.mjs +403 -19
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +12 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +12 -5
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +12 -5
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.mjs +12 -5
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/langchain/middleware/index.cjs +12 -5
- package/dist/langchain/middleware/index.cjs.map +1 -1
- package/dist/langchain/middleware/index.mjs +12 -5
- package/dist/langchain/middleware/index.mjs.map +1 -1
- package/dist/openai/index.cjs +12 -5
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +12 -5
- package/dist/openai/index.mjs.map +1 -1
- package/dist/openai-agents/index.cjs +12 -5
- package/dist/openai-agents/index.cjs.map +1 -1
- package/dist/openai-agents/index.mjs +12 -5
- package/dist/openai-agents/index.mjs.map +1 -1
- package/dist/otel/index.cjs +11 -4
- package/dist/otel/index.cjs.map +1 -1
- package/dist/otel/index.mjs +11 -4
- package/dist/otel/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +12 -5
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +12 -5
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/gemini/index.d.ts
CHANGED
|
@@ -22,6 +22,33 @@ interface CostOverride {
|
|
|
22
22
|
outputCost: number;
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
|
+
//#region src/gemini/interactions.d.ts
|
|
26
|
+
type Create = GoogleGenAI['interactions']['create'];
|
|
27
|
+
type CreateParams = Parameters<Create>[0];
|
|
28
|
+
type ForegroundParams = CreateParams & {
|
|
29
|
+
model: string;
|
|
30
|
+
agent?: never;
|
|
31
|
+
background?: false;
|
|
32
|
+
};
|
|
33
|
+
type CreateOptions = Parameters<Create>[1];
|
|
34
|
+
type CreateResult = Awaited<ReturnType<Create>>;
|
|
35
|
+
type Interaction = Exclude<CreateResult, AsyncIterable<unknown>>;
|
|
36
|
+
type InteractionStream = Extract<CreateResult, AsyncIterable<unknown>>;
|
|
37
|
+
type InteractionEvent = InteractionStream extends AsyncIterable<infer Event> ? Event : never;
|
|
38
|
+
declare class WrappedInteractions {
|
|
39
|
+
private readonly client;
|
|
40
|
+
private readonly phClient;
|
|
41
|
+
constructor(client: GoogleGenAI, phClient: PostHog);
|
|
42
|
+
create(params: ForegroundParams & MonitoringParams & {
|
|
43
|
+
stream: true;
|
|
44
|
+
}, options?: CreateOptions): Promise<ReadableStream<InteractionEvent> & AsyncIterable<InteractionEvent>>;
|
|
45
|
+
create(params: ForegroundParams & MonitoringParams & {
|
|
46
|
+
stream?: false;
|
|
47
|
+
}, options?: CreateOptions): Promise<Interaction>;
|
|
48
|
+
create(params: ForegroundParams & MonitoringParams, options?: CreateOptions): Promise<Interaction | (ReadableStream<InteractionEvent> & AsyncIterable<InteractionEvent>)>;
|
|
49
|
+
private wrapStream;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
25
52
|
//#region src/gemini/index.d.ts
|
|
26
53
|
interface MonitoringGeminiConfig extends GoogleGenAIOptions {
|
|
27
54
|
posthog: PostHog;
|
|
@@ -30,6 +57,7 @@ declare class PostHogGoogleGenAI {
|
|
|
30
57
|
private readonly phClient;
|
|
31
58
|
private readonly client;
|
|
32
59
|
models: WrappedModels;
|
|
60
|
+
interactions: WrappedInteractions;
|
|
33
61
|
constructor(config: MonitoringGeminiConfig);
|
|
34
62
|
}
|
|
35
63
|
declare class WrappedModels {
|
package/dist/gemini/index.mjs
CHANGED
|
@@ -92,6 +92,12 @@ const FILE_FAMILY_TYPES = /* @__PURE__ */ new Set([
|
|
|
92
92
|
"media",
|
|
93
93
|
"file-data"
|
|
94
94
|
]);
|
|
95
|
+
const TYPED_BINARY_DATA_TYPES = /* @__PURE__ */ new Set([
|
|
96
|
+
"image",
|
|
97
|
+
"audio",
|
|
98
|
+
"video",
|
|
99
|
+
"document"
|
|
100
|
+
]);
|
|
95
101
|
const KNOWN_AUDIO_FORMATS = /* @__PURE__ */ new Set([
|
|
96
102
|
"wav",
|
|
97
103
|
"mp3",
|
|
@@ -143,7 +149,8 @@ var MediaTypeContext = class MediaTypeContext {
|
|
|
143
149
|
if (key.includes("image")) return "image";
|
|
144
150
|
if (key.includes("file") || key.includes("document")) return "application/octet-stream";
|
|
145
151
|
}
|
|
146
|
-
|
|
152
|
+
hasDefiniteBinaryData() {
|
|
153
|
+
if (this.parent && this.key === "data" && typeof this.parent.type === "string" && TYPED_BINARY_DATA_TYPES.has(this.parent.type)) return true;
|
|
147
154
|
if (!this.explicitMediaType && (!this.parent || !this.key || !STRONG_CONTEXT_KEYS.has(this.key))) return false;
|
|
148
155
|
const mediaType = this.inferFromSiblingMime();
|
|
149
156
|
return mediaType !== void 0 && !mediaType.toLowerCase().startsWith("text/");
|
|
@@ -197,9 +204,9 @@ var BinaryContentRedactor = class {
|
|
|
197
204
|
return out;
|
|
198
205
|
}
|
|
199
206
|
redactString(value, ctx) {
|
|
200
|
-
const
|
|
201
|
-
const recognitionValue =
|
|
202
|
-
const minLength =
|
|
207
|
+
const hasDefiniteBinaryData = ctx.hasDefiniteBinaryData();
|
|
208
|
+
const recognitionValue = hasDefiniteBinaryData ? value.replace(/[\r\n]/g, "") : value;
|
|
209
|
+
const minLength = hasDefiniteBinaryData ? Math.min(recognitionValue.length, STRONG_CONTEXT_MIN_LENGTH) : ctx.signalsBinary() ? STRONG_CONTEXT_MIN_LENGTH : WEAK_CONTEXT_MIN_LENGTH;
|
|
203
210
|
const recognition = this.recognizer.recognize(recognitionValue, minLength);
|
|
204
211
|
switch (recognition.kind) {
|
|
205
212
|
case "data-url": return this.placeholderFor(recognition.mediaType);
|
|
@@ -331,7 +338,11 @@ const formatResponseGemini = (response, client) => {
|
|
|
331
338
|
if (response.candidates && Array.isArray(response.candidates)) {
|
|
332
339
|
for (const candidate of response.candidates) if (candidate.content && candidate.content.parts) {
|
|
333
340
|
const content = [];
|
|
334
|
-
for (const part of candidate.content.parts) if (part.text) content.push({
|
|
341
|
+
for (const part of candidate.content.parts) if (part.thought === true && part.text) content.push({
|
|
342
|
+
type: "reasoning",
|
|
343
|
+
text: part.text
|
|
344
|
+
});
|
|
345
|
+
else if (part.text) content.push({
|
|
335
346
|
type: "text",
|
|
336
347
|
text: part.text
|
|
337
348
|
});
|
|
@@ -448,7 +459,7 @@ function addDefaults(params) {
|
|
|
448
459
|
}
|
|
449
460
|
//#endregion
|
|
450
461
|
//#region package.json
|
|
451
|
-
var version = "8.
|
|
462
|
+
var version = "8.15.0";
|
|
452
463
|
//#endregion
|
|
453
464
|
//#region src/serializeError.ts
|
|
454
465
|
const DEFAULT_MAX_DEPTH = 3;
|
|
@@ -714,7 +725,385 @@ function mapGeminiUsage(metadata, additionalUsage = {}) {
|
|
|
714
725
|
};
|
|
715
726
|
}
|
|
716
727
|
//#endregion
|
|
728
|
+
//#region src/gemini/interactions.ts
|
|
729
|
+
function record(value) {
|
|
730
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
731
|
+
}
|
|
732
|
+
function string(value) {
|
|
733
|
+
return typeof value === "string" ? value : void 0;
|
|
734
|
+
}
|
|
735
|
+
function number(value) {
|
|
736
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
737
|
+
}
|
|
738
|
+
function isStream(value) {
|
|
739
|
+
return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
740
|
+
}
|
|
741
|
+
function usageFromInteraction(value, model) {
|
|
742
|
+
const usage = record(value);
|
|
743
|
+
if (!usage) return {};
|
|
744
|
+
const cached = number(usage.total_cached_tokens);
|
|
745
|
+
const searches = Array.isArray(usage.grounding_tool_count) ? usage.grounding_tool_count.reduce((total, entry) => {
|
|
746
|
+
const grounding = record(entry);
|
|
747
|
+
return total + (grounding?.type === "google_search" ? number(grounding.count) ?? 0 : 0);
|
|
748
|
+
}, 0) : void 0;
|
|
749
|
+
const modelMajor = /^(?:models\/)?gemini-(\d+)/.exec(model ?? "")?.[1];
|
|
750
|
+
const webSearchCount = modelMajor === void 0 ? void 0 : Number(modelMajor) >= 3 ? searches : searches ? 1 : 0;
|
|
751
|
+
return {
|
|
752
|
+
inputTokens: number(usage.total_input_tokens),
|
|
753
|
+
outputTokens: number(usage.total_output_tokens),
|
|
754
|
+
reasoningTokens: number(usage.total_thought_tokens),
|
|
755
|
+
cacheReadInputTokens: cached,
|
|
756
|
+
...cached !== void 0 ? { cacheReportingExclusive: false } : {},
|
|
757
|
+
webSearchCount,
|
|
758
|
+
rawUsage: usage
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
function functionArguments(value) {
|
|
762
|
+
if (typeof value !== "string") return record(value) ?? {};
|
|
763
|
+
try {
|
|
764
|
+
return record(JSON.parse(value)) ?? value;
|
|
765
|
+
} catch {
|
|
766
|
+
return value;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
function outputFromSteps(steps, fallbackText) {
|
|
770
|
+
const content = [];
|
|
771
|
+
if (Array.isArray(steps)) for (const rawStep of steps) {
|
|
772
|
+
const step = record(rawStep);
|
|
773
|
+
if (step?.type === "model_output" && Array.isArray(step.content)) content.push(...step.content);
|
|
774
|
+
else if (step?.type === "function_call" && string(step.name)) content.push({
|
|
775
|
+
type: "function",
|
|
776
|
+
id: string(step.id),
|
|
777
|
+
function: {
|
|
778
|
+
name: step.name,
|
|
779
|
+
arguments: functionArguments(step.arguments)
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
if (content.length === 0 && fallbackText) content.push({
|
|
784
|
+
type: "text",
|
|
785
|
+
text: fallbackText
|
|
786
|
+
});
|
|
787
|
+
return content.length ? [{
|
|
788
|
+
role: "assistant",
|
|
789
|
+
content
|
|
790
|
+
}] : [];
|
|
791
|
+
}
|
|
792
|
+
function inputFromRequest(input, systemInstruction) {
|
|
793
|
+
const messages = [];
|
|
794
|
+
if (typeof systemInstruction === "string") messages.push({
|
|
795
|
+
role: "system",
|
|
796
|
+
content: systemInstruction
|
|
797
|
+
});
|
|
798
|
+
let userContent = [];
|
|
799
|
+
const flushUserContent = () => {
|
|
800
|
+
if (userContent.length) messages.push({
|
|
801
|
+
role: "user",
|
|
802
|
+
content: userContent
|
|
803
|
+
});
|
|
804
|
+
userContent = [];
|
|
805
|
+
};
|
|
806
|
+
for (const part of Array.isArray(input) ? input : [input]) {
|
|
807
|
+
const step = record(part);
|
|
808
|
+
if (step?.type === "text" || step?.type === "image" || step?.type === "audio" || step?.type === "video" || step?.type === "document") {
|
|
809
|
+
userContent.push(part);
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
flushUserContent();
|
|
813
|
+
if (step?.type === "function_result") messages.push({
|
|
814
|
+
role: "tool",
|
|
815
|
+
content: [{
|
|
816
|
+
type: "tool_result",
|
|
817
|
+
tool_use_id: step.call_id,
|
|
818
|
+
content: step.result
|
|
819
|
+
}]
|
|
820
|
+
});
|
|
821
|
+
else if (step?.type === "user_input") messages.push({
|
|
822
|
+
role: "user",
|
|
823
|
+
content: step.content ?? [part]
|
|
824
|
+
});
|
|
825
|
+
else if (step?.type === "model_output") messages.push({
|
|
826
|
+
role: "assistant",
|
|
827
|
+
content: step.content ?? [part]
|
|
828
|
+
});
|
|
829
|
+
else if (step?.type === "function_call") {
|
|
830
|
+
const output = outputFromSteps([part]);
|
|
831
|
+
messages.push(...output.length ? output : [{
|
|
832
|
+
role: "assistant",
|
|
833
|
+
content: [part]
|
|
834
|
+
}]);
|
|
835
|
+
} else messages.push({
|
|
836
|
+
role: "user",
|
|
837
|
+
content: part
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
flushUserContent();
|
|
841
|
+
return messages;
|
|
842
|
+
}
|
|
843
|
+
function safeTools(tools) {
|
|
844
|
+
if (!Array.isArray(tools)) return void 0;
|
|
845
|
+
return tools.map((tool) => ({
|
|
846
|
+
type: string(record(tool)?.type),
|
|
847
|
+
name: string(record(tool)?.name)
|
|
848
|
+
}));
|
|
849
|
+
}
|
|
850
|
+
function isFailure(status) {
|
|
851
|
+
return status === "failed" || status === "cancelled" || status === "incomplete" || status === "budget_exceeded";
|
|
852
|
+
}
|
|
853
|
+
var WrappedInteractions = class {
|
|
854
|
+
constructor(client, phClient) {
|
|
855
|
+
this.client = client;
|
|
856
|
+
this.phClient = phClient;
|
|
857
|
+
}
|
|
858
|
+
async create(params, options) {
|
|
859
|
+
const { providerParams, posthogParams } = extractPosthogParams(params);
|
|
860
|
+
const request = providerParams;
|
|
861
|
+
const requestData = record(request) ?? {};
|
|
862
|
+
if (requestData.background === true || typeof requestData.model !== "string" || requestData.agent !== void 0) throw new Error("Gemini Interactions tracing supports foreground model calls only");
|
|
863
|
+
const startTime = Date.now();
|
|
864
|
+
const capture = async (interaction, error, output, firstTokenTime) => {
|
|
865
|
+
try {
|
|
866
|
+
const privateCapture = withPrivacyMode(this.phClient, posthogParams.privacyMode, false) === null;
|
|
867
|
+
const model = string(interaction?.model) ?? string(requestData.model);
|
|
868
|
+
const generationConfig = record(requestData.generation_config);
|
|
869
|
+
const modelParameters = privateCapture ? {} : {
|
|
870
|
+
...number(generationConfig?.max_output_tokens) !== void 0 ? { max_tokens: generationConfig?.max_output_tokens } : {},
|
|
871
|
+
...string(generationConfig?.thinking_level) !== void 0 ? { thinking_level: generationConfig?.thinking_level } : {}
|
|
872
|
+
};
|
|
873
|
+
await captureAiGeneration(this.phClient, {
|
|
874
|
+
...posthogParams,
|
|
875
|
+
model,
|
|
876
|
+
provider: "gemini",
|
|
877
|
+
input: privateCapture ? null : inputFromRequest(sanitizeGemini(requestData.input, this.phClient), sanitizeGemini(requestData.system_instruction, this.phClient)),
|
|
878
|
+
output: privateCapture ? null : sanitizeGemini(output ?? outputFromSteps(interaction?.steps, string(interaction?.output_text)), this.phClient),
|
|
879
|
+
latency: (Date.now() - startTime) / 1e3,
|
|
880
|
+
timeToFirstToken: firstTokenTime === void 0 ? void 0 : (firstTokenTime - startTime) / 1e3,
|
|
881
|
+
baseURL: "https://generativelanguage.googleapis.com",
|
|
882
|
+
modelParameters,
|
|
883
|
+
completionId: string(interaction?.id),
|
|
884
|
+
stopReason: string(interaction?.status),
|
|
885
|
+
servedServiceTier: string(interaction?.service_tier),
|
|
886
|
+
usage: usageFromInteraction(interaction?.usage, model),
|
|
887
|
+
tools: privateCapture ? void 0 : safeTools(requestData.tools),
|
|
888
|
+
error: privateCapture && error ? /* @__PURE__ */ new Error("Gemini interaction failed") : error
|
|
889
|
+
});
|
|
890
|
+
} catch {}
|
|
891
|
+
};
|
|
892
|
+
try {
|
|
893
|
+
if (!this.client.interactions?.create) throw new Error("Gemini Interactions requires @google/genai 2.18.0 or newer");
|
|
894
|
+
const result = await (options === void 0 ? this.client.interactions.create(request) : this.client.interactions.create(request, options));
|
|
895
|
+
if (requestData.stream === true) {
|
|
896
|
+
if (!isStream(result)) throw new Error("Gemini Interactions did not return a stream");
|
|
897
|
+
return this.wrapStream(result, capture);
|
|
898
|
+
}
|
|
899
|
+
if (isStream(result)) throw new Error("Gemini Interactions returned an unexpected stream");
|
|
900
|
+
const interaction = record(result);
|
|
901
|
+
let unsupportedSchema = false;
|
|
902
|
+
try {
|
|
903
|
+
unsupportedSchema = Array.isArray(interaction?.outputs) && !Array.isArray(interaction?.steps);
|
|
904
|
+
} catch {
|
|
905
|
+
return result;
|
|
906
|
+
}
|
|
907
|
+
if (unsupportedSchema) throw new Error("Gemini Interactions GA schema requires @google/genai 2.18.0 or newer");
|
|
908
|
+
try {
|
|
909
|
+
const status = interaction?.status;
|
|
910
|
+
if (status !== "queued" && status !== "in_progress") await capture(interaction, isFailure(status) ? /* @__PURE__ */ new Error(`Gemini interaction ${status}`) : void 0);
|
|
911
|
+
} catch {}
|
|
912
|
+
return result;
|
|
913
|
+
} catch (error) {
|
|
914
|
+
await capture(void 0, error);
|
|
915
|
+
throw error;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
wrapStream(stream, capture) {
|
|
919
|
+
const reader = "getReader" in stream && typeof stream.getReader === "function" ? stream.getReader() : void 0;
|
|
920
|
+
const iterator = reader ? void 0 : stream[Symbol.asyncIterator]();
|
|
921
|
+
let readerReleased = false;
|
|
922
|
+
let errorIterator;
|
|
923
|
+
let readError;
|
|
924
|
+
const next = async () => {
|
|
925
|
+
if (!reader) return iterator.next();
|
|
926
|
+
try {
|
|
927
|
+
return await reader.read();
|
|
928
|
+
} catch (providerError) {
|
|
929
|
+
if (closed) throw providerError;
|
|
930
|
+
readError = providerError;
|
|
931
|
+
release();
|
|
932
|
+
try {
|
|
933
|
+
errorIterator = stream[Symbol.asyncIterator]();
|
|
934
|
+
} catch {
|
|
935
|
+
throw providerError;
|
|
936
|
+
}
|
|
937
|
+
try {
|
|
938
|
+
await errorIterator.next();
|
|
939
|
+
} finally {
|
|
940
|
+
try {
|
|
941
|
+
await errorIterator.return?.();
|
|
942
|
+
} catch {}
|
|
943
|
+
}
|
|
944
|
+
throw providerError;
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
const cancelSource = async (reason) => {
|
|
948
|
+
if (reader && !readerReleased) await reader.cancel(reason);
|
|
949
|
+
else if (reader) {
|
|
950
|
+
try {
|
|
951
|
+
await errorIterator?.return?.();
|
|
952
|
+
} catch {}
|
|
953
|
+
throw readError;
|
|
954
|
+
} else await iterator?.return?.();
|
|
955
|
+
};
|
|
956
|
+
const release = () => {
|
|
957
|
+
if (readerReleased) return;
|
|
958
|
+
try {
|
|
959
|
+
reader?.releaseLock();
|
|
960
|
+
readerReleased = true;
|
|
961
|
+
} catch {}
|
|
962
|
+
};
|
|
963
|
+
let interaction;
|
|
964
|
+
let latestUsage;
|
|
965
|
+
let finalUsage;
|
|
966
|
+
let error;
|
|
967
|
+
let firstTokenTime;
|
|
968
|
+
const steps = /* @__PURE__ */ new Map();
|
|
969
|
+
let completed = false;
|
|
970
|
+
let closed = false;
|
|
971
|
+
let cancelled = false;
|
|
972
|
+
let captured = false;
|
|
973
|
+
const observe = (event) => {
|
|
974
|
+
let schemaError;
|
|
975
|
+
try {
|
|
976
|
+
const item = record(event);
|
|
977
|
+
const eventType = item?.event_type;
|
|
978
|
+
if (eventType === "interaction.start" || eventType === "interaction.complete" || eventType === "interaction.delta" || typeof eventType === "string" && eventType.startsWith("content.")) schemaError = /* @__PURE__ */ new Error("Gemini Interactions GA schema requires @google/genai 2.18.0 or newer");
|
|
979
|
+
else {
|
|
980
|
+
const usage = record(record(item?.metadata)?.total_usage) ?? (eventType === "step.stop" ? record(item?.usage) : void 0);
|
|
981
|
+
if (usage) latestUsage = { ...usage };
|
|
982
|
+
if (eventType === "interaction.created") {
|
|
983
|
+
interaction = { ...record(item?.interaction) };
|
|
984
|
+
const initialUsage = record(interaction.usage);
|
|
985
|
+
if (initialUsage) latestUsage = { ...initialUsage };
|
|
986
|
+
} else if (eventType === "step.start") {
|
|
987
|
+
const index = number(item?.index);
|
|
988
|
+
const step = record(item?.step);
|
|
989
|
+
if (index !== void 0) steps.set(index, {
|
|
990
|
+
...step,
|
|
991
|
+
content: Array.isArray(step?.content) ? step.content.map((item) => ({ ...record(item) })) : []
|
|
992
|
+
});
|
|
993
|
+
} else if (eventType === "step.delta") {
|
|
994
|
+
const index = number(item?.index);
|
|
995
|
+
const delta = record(item?.delta);
|
|
996
|
+
const step = index === void 0 ? void 0 : steps.get(index);
|
|
997
|
+
if (step && delta?.type === "text" && typeof delta.text === "string") {
|
|
998
|
+
const last = step.content?.at(-1);
|
|
999
|
+
const text = record(last);
|
|
1000
|
+
if (text?.type === "text") text.text = `${text.text ?? ""}${delta.text}`;
|
|
1001
|
+
else step.content?.push({
|
|
1002
|
+
type: "text",
|
|
1003
|
+
text: delta.text
|
|
1004
|
+
});
|
|
1005
|
+
firstTokenTime ??= Date.now();
|
|
1006
|
+
} else if (step && (delta?.type === "image" || delta?.type === "audio" || delta?.type === "video" || delta?.type === "document")) {
|
|
1007
|
+
step.content?.push({ ...delta });
|
|
1008
|
+
firstTokenTime ??= Date.now();
|
|
1009
|
+
} else if (step && delta?.type === "arguments_delta" && typeof delta.arguments === "string") {
|
|
1010
|
+
step.argumentChunks = `${step.argumentChunks ?? ""}${delta.arguments}`;
|
|
1011
|
+
firstTokenTime ??= Date.now();
|
|
1012
|
+
}
|
|
1013
|
+
} else if (eventType === "interaction.completed") {
|
|
1014
|
+
const result = record(item?.interaction);
|
|
1015
|
+
interaction = {
|
|
1016
|
+
...interaction,
|
|
1017
|
+
...result
|
|
1018
|
+
};
|
|
1019
|
+
completed = interaction.status !== "queued" && interaction.status !== "in_progress";
|
|
1020
|
+
const reportedUsage = record(result?.usage);
|
|
1021
|
+
if (reportedUsage) {
|
|
1022
|
+
latestUsage = { ...reportedUsage };
|
|
1023
|
+
if (completed) finalUsage = latestUsage;
|
|
1024
|
+
}
|
|
1025
|
+
if (isFailure(interaction.status)) error = /* @__PURE__ */ new Error(`Gemini interaction ${interaction.status}`);
|
|
1026
|
+
if (!completed) error = /* @__PURE__ */ new Error("Gemini interaction stream ended without a terminal result");
|
|
1027
|
+
} else if (eventType === "error") error = /* @__PURE__ */ new Error("Gemini interaction stream failed");
|
|
1028
|
+
}
|
|
1029
|
+
} catch {}
|
|
1030
|
+
if (schemaError) throw schemaError;
|
|
1031
|
+
};
|
|
1032
|
+
const finish = async (status, providerError) => {
|
|
1033
|
+
if (captured) return;
|
|
1034
|
+
captured = true;
|
|
1035
|
+
try {
|
|
1036
|
+
const streamedSteps = [...steps.entries()].sort(([left], [right]) => left - right).map(([, step]) => ({
|
|
1037
|
+
...step,
|
|
1038
|
+
arguments: step.argumentChunks === void 0 ? step.arguments : functionArguments(step.argumentChunks)
|
|
1039
|
+
}));
|
|
1040
|
+
const output = outputFromSteps(Array.isArray(interaction?.steps) && interaction.steps.length > 0 ? interaction.steps : streamedSteps);
|
|
1041
|
+
await capture({
|
|
1042
|
+
...interaction,
|
|
1043
|
+
usage: finalUsage ?? latestUsage,
|
|
1044
|
+
...completed ? {} : { status }
|
|
1045
|
+
}, providerError ?? error ?? (!completed && status === "incomplete" ? /* @__PURE__ */ new Error("Gemini interaction stream ended without completion") : void 0), output, firstTokenTime);
|
|
1046
|
+
} catch {}
|
|
1047
|
+
};
|
|
1048
|
+
return new ReadableStream({
|
|
1049
|
+
async pull(controller) {
|
|
1050
|
+
try {
|
|
1051
|
+
const result = await next();
|
|
1052
|
+
if (closed) return;
|
|
1053
|
+
if (result.done) {
|
|
1054
|
+
closed = true;
|
|
1055
|
+
await finish("incomplete");
|
|
1056
|
+
release();
|
|
1057
|
+
if (!cancelled) controller.close();
|
|
1058
|
+
} else {
|
|
1059
|
+
observe(result.value);
|
|
1060
|
+
controller.enqueue(result.value);
|
|
1061
|
+
}
|
|
1062
|
+
} catch (providerError) {
|
|
1063
|
+
if (closed) return;
|
|
1064
|
+
closed = true;
|
|
1065
|
+
try {
|
|
1066
|
+
await cancelSource(providerError);
|
|
1067
|
+
} catch {}
|
|
1068
|
+
await finish("failed", providerError);
|
|
1069
|
+
release();
|
|
1070
|
+
if (!cancelled) controller.error(providerError);
|
|
1071
|
+
}
|
|
1072
|
+
},
|
|
1073
|
+
async cancel(reason) {
|
|
1074
|
+
cancelled = true;
|
|
1075
|
+
if (closed) return;
|
|
1076
|
+
closed = true;
|
|
1077
|
+
let cancellationError;
|
|
1078
|
+
try {
|
|
1079
|
+
await cancelSource(reason);
|
|
1080
|
+
} catch (providerError) {
|
|
1081
|
+
cancellationError = providerError;
|
|
1082
|
+
throw providerError;
|
|
1083
|
+
} finally {
|
|
1084
|
+
await finish("cancelled", cancellationError);
|
|
1085
|
+
release();
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
};
|
|
1091
|
+
//#endregion
|
|
717
1092
|
//#region src/gemini/index.ts
|
|
1093
|
+
/** Append streamed text to the last block of the same type, or start a new one. */
|
|
1094
|
+
function appendStreamedText(content, type, text) {
|
|
1095
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
1096
|
+
const item = content[i];
|
|
1097
|
+
if (item.type === type) {
|
|
1098
|
+
item.text += text;
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
content.push({
|
|
1103
|
+
type,
|
|
1104
|
+
text
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
718
1107
|
const TOOL_RESULT_MAX_BYTES = 5e3;
|
|
719
1108
|
function geminiFunctionResponseContent(response) {
|
|
720
1109
|
return response.parts !== void 0 ? {
|
|
@@ -728,6 +1117,7 @@ var PostHogGoogleGenAI = class {
|
|
|
728
1117
|
this.phClient = posthog;
|
|
729
1118
|
this.client = new GoogleGenAI(geminiConfig);
|
|
730
1119
|
this.models = new WrappedModels(this.client, this.phClient);
|
|
1120
|
+
this.interactions = new WrappedInteractions(this.client, this.phClient);
|
|
731
1121
|
}
|
|
732
1122
|
};
|
|
733
1123
|
var WrappedModels = class {
|
|
@@ -793,18 +1183,8 @@ var WrappedModels = class {
|
|
|
793
1183
|
if (firstTokenTime === void 0 && chunk.text) firstTokenTime = Date.now();
|
|
794
1184
|
const chunkWebSearchCount = calculateGoogleWebSearchCount(chunk);
|
|
795
1185
|
if (chunkWebSearchCount > 0 && chunkWebSearchCount > (usage.webSearchCount ?? 0)) usage.webSearchCount = chunkWebSearchCount;
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
for (let i = accumulatedContent.length - 1; i >= 0; i--) if (accumulatedContent[i].type === "text") {
|
|
799
|
-
lastTextItem = accumulatedContent[i];
|
|
800
|
-
break;
|
|
801
|
-
}
|
|
802
|
-
if (lastTextItem && lastTextItem.type === "text") lastTextItem.text += chunk.text;
|
|
803
|
-
else accumulatedContent.push({
|
|
804
|
-
type: "text",
|
|
805
|
-
text: chunk.text
|
|
806
|
-
});
|
|
807
|
-
}
|
|
1186
|
+
for (const part of chunk.candidates?.[0]?.content?.parts ?? []) if (part.thought === true && part.text) appendStreamedText(accumulatedContent, "reasoning", part.text);
|
|
1187
|
+
if (chunk.text) appendStreamedText(accumulatedContent, "text", chunk.text);
|
|
808
1188
|
if (chunk.candidates?.[0]?.finishReason) stopReason = chunk.candidates[0].finishReason;
|
|
809
1189
|
if (chunk.candidates && Array.isArray(chunk.candidates)) {
|
|
810
1190
|
for (const candidate of chunk.candidates) if (candidate.content && candidate.content.parts) {
|
|
@@ -913,7 +1293,11 @@ var WrappedModels = class {
|
|
|
913
1293
|
}
|
|
914
1294
|
formatPartsAsContentBlocks(parts) {
|
|
915
1295
|
const blocks = [];
|
|
916
|
-
for (const part of parts) if (part && typeof part === "object" && "text" in part && part.text) blocks.push({
|
|
1296
|
+
for (const part of parts) if (part && typeof part === "object" && "thought" in part && part.thought === true && "text" in part && part.text) blocks.push({
|
|
1297
|
+
type: "reasoning",
|
|
1298
|
+
text: String(part.text)
|
|
1299
|
+
});
|
|
1300
|
+
else if (part && typeof part === "object" && "text" in part && part.text) blocks.push({
|
|
917
1301
|
type: "text",
|
|
918
1302
|
text: String(part.text)
|
|
919
1303
|
});
|