@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.
Files changed (47) hide show
  1. package/README.md +14 -0
  2. package/dist/adk/index.cjs +22 -7
  3. package/dist/adk/index.cjs.map +1 -1
  4. package/dist/adk/index.mjs +22 -7
  5. package/dist/adk/index.mjs.map +1 -1
  6. package/dist/anthropic/index.cjs +12 -5
  7. package/dist/anthropic/index.cjs.map +1 -1
  8. package/dist/anthropic/index.mjs +12 -5
  9. package/dist/anthropic/index.mjs.map +1 -1
  10. package/dist/claude-agent-sdk/index.cjs +12 -5
  11. package/dist/claude-agent-sdk/index.cjs.map +1 -1
  12. package/dist/claude-agent-sdk/index.mjs +12 -5
  13. package/dist/claude-agent-sdk/index.mjs.map +1 -1
  14. package/dist/gemini/index.cjs +403 -19
  15. package/dist/gemini/index.cjs.map +1 -1
  16. package/dist/gemini/index.d.ts +28 -0
  17. package/dist/gemini/index.mjs +403 -19
  18. package/dist/gemini/index.mjs.map +1 -1
  19. package/dist/index.cjs +12 -5
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.mjs +12 -5
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/langchain/index.cjs +12 -5
  24. package/dist/langchain/index.cjs.map +1 -1
  25. package/dist/langchain/index.mjs +12 -5
  26. package/dist/langchain/index.mjs.map +1 -1
  27. package/dist/langchain/middleware/index.cjs +12 -5
  28. package/dist/langchain/middleware/index.cjs.map +1 -1
  29. package/dist/langchain/middleware/index.mjs +12 -5
  30. package/dist/langchain/middleware/index.mjs.map +1 -1
  31. package/dist/openai/index.cjs +12 -5
  32. package/dist/openai/index.cjs.map +1 -1
  33. package/dist/openai/index.mjs +12 -5
  34. package/dist/openai/index.mjs.map +1 -1
  35. package/dist/openai-agents/index.cjs +12 -5
  36. package/dist/openai-agents/index.cjs.map +1 -1
  37. package/dist/openai-agents/index.mjs +12 -5
  38. package/dist/openai-agents/index.mjs.map +1 -1
  39. package/dist/otel/index.cjs +11 -4
  40. package/dist/otel/index.cjs.map +1 -1
  41. package/dist/otel/index.mjs +11 -4
  42. package/dist/otel/index.mjs.map +1 -1
  43. package/dist/vercel/index.cjs +12 -5
  44. package/dist/vercel/index.cjs.map +1 -1
  45. package/dist/vercel/index.mjs +12 -5
  46. package/dist/vercel/index.mjs.map +1 -1
  47. package/package.json +4 -3
@@ -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 {
@@ -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
- hasExplicitBinaryMediaType() {
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 hasExplicitBinaryMediaType = ctx.hasExplicitBinaryMediaType();
201
- const recognitionValue = hasExplicitBinaryMediaType ? value.replace(/[\r\n]/g, "") : value;
202
- const minLength = hasExplicitBinaryMediaType ? Math.min(recognitionValue.length, STRONG_CONTEXT_MIN_LENGTH) : ctx.signalsBinary() ? STRONG_CONTEXT_MIN_LENGTH : WEAK_CONTEXT_MIN_LENGTH;
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.14.4";
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
- if (chunk.text) {
797
- let lastTextItem;
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
  });