@gammatech/aijsx 0.9.0-dev.2024-05-28 → 0.9.1-dev.2024-05-28

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/index.d.mts CHANGED
@@ -6,6 +6,8 @@ export { OpenAI as OpenAIClient } from 'openai';
6
6
  import { ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam, ChatCompletionAssistantMessageParam, ChatCompletionCreateParams } from 'openai/resources';
7
7
  import AnthropicClient from '@anthropic-ai/sdk';
8
8
  export { default as AnthropicClient } from '@anthropic-ai/sdk';
9
+ import { GenerateContentRequest, VertexAI } from '@google-cloud/vertexai';
10
+ export { VertexAI } from '@google-cloud/vertexai';
9
11
 
10
12
  declare class ChatCompletionError extends Error {
11
13
  readonly chatCompletionRequest: LogChatCompletionRequest;
@@ -273,4 +275,22 @@ declare function AnthropicChatCompletion(props: AnthropicChatCompletionProps, ct
273
275
 
274
276
  declare const anthropicTokenizer: TokenizerFn;
275
277
 
276
- export { AIComponent, AINode, AISpanAttributes, AISpanProcessor, AnthropicChatCompletion, type AnthropicChatCompletionRequest, AnthropicClientContext, AssistantMessage, type ChatCompletionClientAndProvider, ChatCompletionError, type ChatCompletionRequestPayloads, ChatMessage, Context, type CostFn, DebugMessage, DefaultMaxRetriesContext, EnrichingSpanProcessor, EvaluatorFn, EvaluatorResult, Fallback, FunctionChain, LogChatCompletionRequest, LogImplementation, NotAsyncGenerator, OpenAIChatCompletion, type OpenAIChatCompletionRequest, type OpenAIChatMessage, OpenAIClientContext, ParseVariablesError, ProcessedAISpanAttributes, type Prompt, PromptInvalidOutputError, PromptParsed, ReadableSpan, RenderContext, Retry, RetryCountContext, SpanAttributes, SpanExporter, SpanProcessor, StreamChain, SystemMessage, type TokenizerFn, Trace, Tracer, UserMessage, type ValidAnthropicChatModel, type ValidOpenAIChatModel, type ValidOpenAIVisionModel, anthropicTokenizer, computeUsage, createFunctionChain, createPrompt, createRenderContext, createStreamChain, evaluatePrompt, openaiTokenizer, tracing };
278
+ type GoogleChatCompletionRequest = GenerateContentRequest;
279
+ declare module '@gammatech/aijsx' {
280
+ interface ChatCompletionRequestPayloads {
281
+ google: GoogleChatCompletionRequest;
282
+ }
283
+ }
284
+ type ValidGoogleChatModel = 'gemini-1.5-pro' | 'gemini-1.5-flash';
285
+ declare const GoogleClientContext: Context<() => ChatCompletionClientAndProvider<VertexAI>>;
286
+ type GoogleChatCompletionProps = {
287
+ model: ValidGoogleChatModel;
288
+ maxTokens?: number;
289
+ temperature?: number;
290
+ stop?: string | string[];
291
+ maxRetries?: number;
292
+ children: AINode;
293
+ };
294
+ declare function GoogleChatCompletion(props: GoogleChatCompletionProps, ctx: RenderContext): JSX.Element;
295
+
296
+ export { AIComponent, AINode, AISpanAttributes, AISpanProcessor, AnthropicChatCompletion, type AnthropicChatCompletionRequest, AnthropicClientContext, AssistantMessage, type ChatCompletionClientAndProvider, ChatCompletionError, type ChatCompletionRequestPayloads, ChatMessage, Context, type CostFn, DebugMessage, DefaultMaxRetriesContext, EnrichingSpanProcessor, EvaluatorFn, EvaluatorResult, Fallback, FunctionChain, GoogleChatCompletion, type GoogleChatCompletionRequest, GoogleClientContext, LogChatCompletionRequest, LogImplementation, NotAsyncGenerator, OpenAIChatCompletion, type OpenAIChatCompletionRequest, type OpenAIChatMessage, OpenAIClientContext, ParseVariablesError, ProcessedAISpanAttributes, type Prompt, PromptInvalidOutputError, PromptParsed, ReadableSpan, RenderContext, Retry, RetryCountContext, SpanAttributes, SpanExporter, SpanProcessor, StreamChain, SystemMessage, type TokenizerFn, Trace, Tracer, UserMessage, type ValidAnthropicChatModel, type ValidGoogleChatModel, type ValidOpenAIChatModel, type ValidOpenAIVisionModel, anthropicTokenizer, computeUsage, createFunctionChain, createPrompt, createRenderContext, createStreamChain, evaluatePrompt, openaiTokenizer, tracing };
package/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@ export { OpenAI as OpenAIClient } from 'openai';
6
6
  import { ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam, ChatCompletionAssistantMessageParam, ChatCompletionCreateParams } from 'openai/resources';
7
7
  import AnthropicClient from '@anthropic-ai/sdk';
8
8
  export { default as AnthropicClient } from '@anthropic-ai/sdk';
9
+ import { GenerateContentRequest, VertexAI } from '@google-cloud/vertexai';
10
+ export { VertexAI } from '@google-cloud/vertexai';
9
11
 
10
12
  declare class ChatCompletionError extends Error {
11
13
  readonly chatCompletionRequest: LogChatCompletionRequest;
@@ -273,4 +275,22 @@ declare function AnthropicChatCompletion(props: AnthropicChatCompletionProps, ct
273
275
 
274
276
  declare const anthropicTokenizer: TokenizerFn;
275
277
 
276
- export { AIComponent, AINode, AISpanAttributes, AISpanProcessor, AnthropicChatCompletion, type AnthropicChatCompletionRequest, AnthropicClientContext, AssistantMessage, type ChatCompletionClientAndProvider, ChatCompletionError, type ChatCompletionRequestPayloads, ChatMessage, Context, type CostFn, DebugMessage, DefaultMaxRetriesContext, EnrichingSpanProcessor, EvaluatorFn, EvaluatorResult, Fallback, FunctionChain, LogChatCompletionRequest, LogImplementation, NotAsyncGenerator, OpenAIChatCompletion, type OpenAIChatCompletionRequest, type OpenAIChatMessage, OpenAIClientContext, ParseVariablesError, ProcessedAISpanAttributes, type Prompt, PromptInvalidOutputError, PromptParsed, ReadableSpan, RenderContext, Retry, RetryCountContext, SpanAttributes, SpanExporter, SpanProcessor, StreamChain, SystemMessage, type TokenizerFn, Trace, Tracer, UserMessage, type ValidAnthropicChatModel, type ValidOpenAIChatModel, type ValidOpenAIVisionModel, anthropicTokenizer, computeUsage, createFunctionChain, createPrompt, createRenderContext, createStreamChain, evaluatePrompt, openaiTokenizer, tracing };
278
+ type GoogleChatCompletionRequest = GenerateContentRequest;
279
+ declare module '@gammatech/aijsx' {
280
+ interface ChatCompletionRequestPayloads {
281
+ google: GoogleChatCompletionRequest;
282
+ }
283
+ }
284
+ type ValidGoogleChatModel = 'gemini-1.5-pro' | 'gemini-1.5-flash';
285
+ declare const GoogleClientContext: Context<() => ChatCompletionClientAndProvider<VertexAI>>;
286
+ type GoogleChatCompletionProps = {
287
+ model: ValidGoogleChatModel;
288
+ maxTokens?: number;
289
+ temperature?: number;
290
+ stop?: string | string[];
291
+ maxRetries?: number;
292
+ children: AINode;
293
+ };
294
+ declare function GoogleChatCompletion(props: GoogleChatCompletionProps, ctx: RenderContext): JSX.Element;
295
+
296
+ export { AIComponent, AINode, AISpanAttributes, AISpanProcessor, AnthropicChatCompletion, type AnthropicChatCompletionRequest, AnthropicClientContext, AssistantMessage, type ChatCompletionClientAndProvider, ChatCompletionError, type ChatCompletionRequestPayloads, ChatMessage, Context, type CostFn, DebugMessage, DefaultMaxRetriesContext, EnrichingSpanProcessor, EvaluatorFn, EvaluatorResult, Fallback, FunctionChain, GoogleChatCompletion, type GoogleChatCompletionRequest, GoogleClientContext, LogChatCompletionRequest, LogImplementation, NotAsyncGenerator, OpenAIChatCompletion, type OpenAIChatCompletionRequest, type OpenAIChatMessage, OpenAIClientContext, ParseVariablesError, ProcessedAISpanAttributes, type Prompt, PromptInvalidOutputError, PromptParsed, ReadableSpan, RenderContext, Retry, RetryCountContext, SpanAttributes, SpanExporter, SpanProcessor, StreamChain, SystemMessage, type TokenizerFn, Trace, Tracer, UserMessage, type ValidAnthropicChatModel, type ValidGoogleChatModel, type ValidOpenAIChatModel, type ValidOpenAIVisionModel, anthropicTokenizer, computeUsage, createFunctionChain, createPrompt, createRenderContext, createStreamChain, evaluatePrompt, openaiTokenizer, tracing };
package/dist/index.js CHANGED
@@ -42,6 +42,8 @@ __export(src_exports, {
42
42
  DefaultMaxRetriesContext: () => DefaultMaxRetriesContext,
43
43
  EnrichingSpanProcessor: () => EnrichingSpanProcessor,
44
44
  Fallback: () => Fallback,
45
+ GoogleChatCompletion: () => GoogleChatCompletion,
46
+ GoogleClientContext: () => GoogleClientContext,
45
47
  ImagePart: () => ImagePart,
46
48
  LogImplementation: () => LogImplementation,
47
49
  NoopLogImplementation: () => NoopLogImplementation,
@@ -55,6 +57,7 @@ __export(src_exports, {
55
57
  SystemMessage: () => SystemMessage,
56
58
  Trace: () => Trace,
57
59
  UserMessage: () => UserMessage,
60
+ VertexAI: () => import_vertexai2.VertexAI,
58
61
  anthropicTokenizer: () => anthropicTokenizer,
59
62
  attachedContextSymbol: () => attachedContextSymbol,
60
63
  computeUsage: () => computeUsage,
@@ -73,11 +76,11 @@ module.exports = __toCommonJS(src_exports);
73
76
 
74
77
  // src/chat/errors.ts
75
78
  var ChatCompletionError = class extends Error {
76
- constructor(message, chatCompletionRequest, status, shouldRetry3 = false) {
79
+ constructor(message, chatCompletionRequest, status, shouldRetry4 = false) {
77
80
  super(message);
78
81
  this.chatCompletionRequest = chatCompletionRequest;
79
82
  this.status = status;
80
- this.shouldRetry = shouldRetry3;
83
+ this.shouldRetry = shouldRetry4;
81
84
  }
82
85
  name = "ChatCompletionError";
83
86
  };
@@ -1599,7 +1602,7 @@ function renderCloseTag(element) {
1599
1602
  // src/retry.tsx
1600
1603
  var RetryCountContext = createContext(0);
1601
1604
  var DefaultMaxRetriesContext = createContext(0);
1602
- async function* Retry({ shouldRetry: shouldRetry3, retries = 0, maxRetries = 3, children }, ctx) {
1605
+ async function* Retry({ shouldRetry: shouldRetry4, retries = 0, maxRetries = 3, children }, ctx) {
1603
1606
  const { render } = ctx;
1604
1607
  let hasYieldedData = false;
1605
1608
  try {
@@ -1611,12 +1614,12 @@ async function* Retry({ shouldRetry: shouldRetry3, retries = 0, maxRetries = 3,
1611
1614
  yield value;
1612
1615
  }
1613
1616
  } catch (e) {
1614
- if (hasYieldedData || retries >= maxRetries || !shouldRetry3(e)) {
1617
+ if (hasYieldedData || retries >= maxRetries || !shouldRetry4(e)) {
1615
1618
  throw e;
1616
1619
  }
1617
1620
  await backoff(retries);
1618
1621
  yield* Retry(
1619
- { shouldRetry: shouldRetry3, retries: retries + 1, maxRetries, children },
1622
+ { shouldRetry: shouldRetry4, retries: retries + 1, maxRetries, children },
1620
1623
  ctx
1621
1624
  );
1622
1625
  }
@@ -2527,6 +2530,259 @@ function cleanChatCompletionRequest2(chatCompletionRequest) {
2527
2530
 
2528
2531
  // src/lib/anthropic/index.ts
2529
2532
  var import_sdk2 = __toESM(require("@anthropic-ai/sdk"));
2533
+
2534
+ // src/lib/google/Google.tsx
2535
+ var import_vertexai = require("@google-cloud/vertexai");
2536
+ var GoogleClientContext = createContext(() => {
2537
+ if (defaultClient3) {
2538
+ return defaultClient3;
2539
+ }
2540
+ const project = process.env.GOOGLE_PROJECT_ID || "";
2541
+ const client = new import_vertexai.VertexAI({ project });
2542
+ defaultClient3 = {
2543
+ client,
2544
+ provider: "google"
2545
+ };
2546
+ return defaultClient3;
2547
+ });
2548
+ var defaultClient3 = null;
2549
+ var buildGoogleMessages = (chatMesssages) => {
2550
+ let systemInstruction;
2551
+ const messages = [];
2552
+ chatMesssages.forEach(({ role, content }) => {
2553
+ if (role === "system") {
2554
+ systemInstruction = content;
2555
+ return;
2556
+ }
2557
+ if (role === "user") {
2558
+ const userContent = content;
2559
+ if (userContent.length === 1 && userContent[0].type === "text") {
2560
+ messages.push({
2561
+ role,
2562
+ parts: [{ text: userContent[0].text }]
2563
+ });
2564
+ return;
2565
+ }
2566
+ const c = userContent.map((part) => {
2567
+ if (part.type === "text") {
2568
+ return { text: part.text };
2569
+ } else if (part.type === "image") {
2570
+ const imagePart = {
2571
+ inlineData: {
2572
+ mimeType: part.image.mediaType,
2573
+ data: part.image.data
2574
+ }
2575
+ };
2576
+ return imagePart;
2577
+ }
2578
+ throw new Error("Invalid part");
2579
+ });
2580
+ messages.push({
2581
+ role,
2582
+ parts: c
2583
+ });
2584
+ return;
2585
+ }
2586
+ if (role === "assistant") {
2587
+ messages.push({
2588
+ role,
2589
+ parts: [{ text: content }]
2590
+ });
2591
+ return;
2592
+ }
2593
+ throw new Error(`Invalid role: ${role}`);
2594
+ });
2595
+ return {
2596
+ systemInstruction,
2597
+ messages
2598
+ };
2599
+ };
2600
+ var shouldRetry3 = (error) => {
2601
+ return error instanceof ChatCompletionError && error.shouldRetry;
2602
+ };
2603
+ function GoogleChatCompletion(props, ctx) {
2604
+ const defaultMaxRetries = ctx.getContext(DefaultMaxRetriesContext);
2605
+ return /* @__PURE__ */ jsx(
2606
+ Retry,
2607
+ {
2608
+ maxRetries: props.maxRetries || defaultMaxRetries,
2609
+ shouldRetry: shouldRetry3,
2610
+ children: /* @__PURE__ */ jsx(Trace, { name: "ai.chatCompletion", children: /* @__PURE__ */ jsx(GoogleChatCompletionInner, { ...props }) })
2611
+ }
2612
+ );
2613
+ }
2614
+ async function* GoogleChatCompletionInner(props, ctx) {
2615
+ const startTime = performance.now();
2616
+ const { logger, tracer, getContext } = ctx;
2617
+ const retryCount = getContext(RetryCountContext);
2618
+ const span = tracer.getActiveSpan();
2619
+ const { client, provider, providerRegion, costFn } = getContext(GoogleClientContext)();
2620
+ if (!client) {
2621
+ throw new Error(
2622
+ "[GoogleChatCompletion] must supply GoogleClient via context"
2623
+ );
2624
+ }
2625
+ const chatMessages = await buildChatMessages(ctx, props.children, {
2626
+ useBase64Images: true
2627
+ });
2628
+ const { systemInstruction, messages } = buildGoogleMessages(chatMessages);
2629
+ const inputMessages = chatMessages.map((m) => toDebugMessage(m));
2630
+ let stopSequences;
2631
+ if (props.stop && typeof props.stop === "string") {
2632
+ stopSequences = [props.stop];
2633
+ } else if (Array.isArray(props.stop)) {
2634
+ stopSequences = props.stop;
2635
+ }
2636
+ const googleCompletionRequest = {
2637
+ systemInstruction,
2638
+ contents: messages,
2639
+ generationConfig: {
2640
+ maxOutputTokens: props.maxTokens,
2641
+ temperature: props.temperature,
2642
+ stopSequences
2643
+ }
2644
+ };
2645
+ const chatCompletionRequestToLog = cleanChatCompletionRequest3(
2646
+ googleCompletionRequest
2647
+ );
2648
+ const logRequestData = {
2649
+ startTime,
2650
+ model: props.model,
2651
+ provider,
2652
+ providerRegion,
2653
+ inputMessages,
2654
+ request: chatCompletionRequestToLog
2655
+ };
2656
+ logger.chatCompletionRequest("google", logRequestData);
2657
+ span.setAttributes({
2658
+ model: props.model,
2659
+ provider,
2660
+ providerRegion,
2661
+ requestType: "google",
2662
+ chatCompletionRequest: chatCompletionRequestToLog,
2663
+ inputMessages,
2664
+ retryCount
2665
+ });
2666
+ const model = client.getGenerativeModel({ model: props.model });
2667
+ let response;
2668
+ try {
2669
+ response = await model.generateContentStream(googleCompletionRequest);
2670
+ } catch (err) {
2671
+ if (err instanceof import_vertexai.GoogleGenerativeAIError) {
2672
+ throw new ChatCompletionError(
2673
+ err.message,
2674
+ logRequestData,
2675
+ void 0,
2676
+ // always retry on GoogleGenerativeAIError errors, they represent non 4xx error cases
2677
+ true
2678
+ );
2679
+ } else if (err instanceof Error) {
2680
+ const status = void 0;
2681
+ const retry = false;
2682
+ throw new ChatCompletionError(err.message, logRequestData, status, retry);
2683
+ }
2684
+ throw err;
2685
+ }
2686
+ let content = "";
2687
+ let outputUsage = 0;
2688
+ let inputUsage = 0;
2689
+ let finishReason = null;
2690
+ try {
2691
+ for await (const event of response.stream) {
2692
+ if (event.candidates) {
2693
+ const chunk = event.candidates[0].content;
2694
+ if (event.candidates[0]?.finishReason) {
2695
+ finishReason = event.candidates[0].finishReason;
2696
+ }
2697
+ if (event.usageMetadata) {
2698
+ if (event.usageMetadata.promptTokenCount) {
2699
+ inputUsage = event.usageMetadata.promptTokenCount;
2700
+ }
2701
+ if (event.usageMetadata.candidatesTokenCount) {
2702
+ outputUsage = event.usageMetadata.candidatesTokenCount;
2703
+ }
2704
+ }
2705
+ for (const block of chunk.parts) {
2706
+ if (block.text) {
2707
+ content += block.text;
2708
+ yield block.text;
2709
+ }
2710
+ }
2711
+ }
2712
+ }
2713
+ } catch (err) {
2714
+ if (err instanceof import_vertexai.GoogleGenerativeAIError) {
2715
+ throw new ChatCompletionError(
2716
+ err.message,
2717
+ logRequestData,
2718
+ void 0,
2719
+ // always retry these errors they represent non 4xx error cases
2720
+ true
2721
+ );
2722
+ } else if (err instanceof Error) {
2723
+ const status = void 0;
2724
+ const retry = false;
2725
+ throw new ChatCompletionError(err.message, logRequestData, status, retry);
2726
+ }
2727
+ throw err;
2728
+ }
2729
+ const outputMessage = {
2730
+ role: "assistant",
2731
+ content
2732
+ };
2733
+ const tokensUsed = {
2734
+ prompt: inputUsage,
2735
+ completion: outputUsage,
2736
+ total: inputUsage + outputUsage
2737
+ };
2738
+ const cost = costFn?.(props.model, tokensUsed) ?? void 0;
2739
+ const responseData = {
2740
+ ...logRequestData,
2741
+ finishReason,
2742
+ latency: performance.now() - startTime,
2743
+ inputMessages,
2744
+ outputMessage,
2745
+ tokensUsed
2746
+ };
2747
+ logger.chatCompletionResponse("google", responseData);
2748
+ span.setAttributes({
2749
+ tokensUsed,
2750
+ output: content,
2751
+ cost,
2752
+ finishReason
2753
+ });
2754
+ }
2755
+ function cleanChatCompletionRequest3(chatCompletionRequest) {
2756
+ const { contents, ...rest } = chatCompletionRequest;
2757
+ return {
2758
+ ...rest,
2759
+ contents: contents.map((message) => {
2760
+ if (message.role !== "user") {
2761
+ return message;
2762
+ }
2763
+ return {
2764
+ ...message,
2765
+ parts: message.parts.map((part) => {
2766
+ if ("text" in part) {
2767
+ return part;
2768
+ } else if ("inlineData" in part) {
2769
+ return {
2770
+ inlineData: {
2771
+ ...part.inlineData,
2772
+ mimeType: part.inlineData?.mimeType || "",
2773
+ data: part.inlineData?.data?.slice(0, 22) + "..."
2774
+ }
2775
+ };
2776
+ }
2777
+ return part;
2778
+ })
2779
+ };
2780
+ })
2781
+ };
2782
+ }
2783
+
2784
+ // src/lib/google/index.ts
2785
+ var import_vertexai2 = require("@google-cloud/vertexai");
2530
2786
  // Annotate the CommonJS export names for ESM import in node:
2531
2787
  0 && (module.exports = {
2532
2788
  AIFragment,
@@ -2542,6 +2798,8 @@ var import_sdk2 = __toESM(require("@anthropic-ai/sdk"));
2542
2798
  DefaultMaxRetriesContext,
2543
2799
  EnrichingSpanProcessor,
2544
2800
  Fallback,
2801
+ GoogleChatCompletion,
2802
+ GoogleClientContext,
2545
2803
  ImagePart,
2546
2804
  LogImplementation,
2547
2805
  NoopLogImplementation,
@@ -2555,6 +2813,7 @@ var import_sdk2 = __toESM(require("@anthropic-ai/sdk"));
2555
2813
  SystemMessage,
2556
2814
  Trace,
2557
2815
  UserMessage,
2816
+ VertexAI,
2558
2817
  anthropicTokenizer,
2559
2818
  attachedContextSymbol,
2560
2819
  computeUsage,
package/dist/index.mjs CHANGED
@@ -8,11 +8,11 @@ import {
8
8
 
9
9
  // src/chat/errors.ts
10
10
  var ChatCompletionError = class extends Error {
11
- constructor(message, chatCompletionRequest, status, shouldRetry3 = false) {
11
+ constructor(message, chatCompletionRequest, status, shouldRetry4 = false) {
12
12
  super(message);
13
13
  this.chatCompletionRequest = chatCompletionRequest;
14
14
  this.status = status;
15
- this.shouldRetry = shouldRetry3;
15
+ this.shouldRetry = shouldRetry4;
16
16
  }
17
17
  name = "ChatCompletionError";
18
18
  };
@@ -1501,7 +1501,7 @@ function renderCloseTag(element) {
1501
1501
  // src/retry.tsx
1502
1502
  var RetryCountContext = createContext(0);
1503
1503
  var DefaultMaxRetriesContext = createContext(0);
1504
- async function* Retry({ shouldRetry: shouldRetry3, retries = 0, maxRetries = 3, children }, ctx) {
1504
+ async function* Retry({ shouldRetry: shouldRetry4, retries = 0, maxRetries = 3, children }, ctx) {
1505
1505
  const { render } = ctx;
1506
1506
  let hasYieldedData = false;
1507
1507
  try {
@@ -1513,12 +1513,12 @@ async function* Retry({ shouldRetry: shouldRetry3, retries = 0, maxRetries = 3,
1513
1513
  yield value;
1514
1514
  }
1515
1515
  } catch (e) {
1516
- if (hasYieldedData || retries >= maxRetries || !shouldRetry3(e)) {
1516
+ if (hasYieldedData || retries >= maxRetries || !shouldRetry4(e)) {
1517
1517
  throw e;
1518
1518
  }
1519
1519
  await backoff(retries);
1520
1520
  yield* Retry(
1521
- { shouldRetry: shouldRetry3, retries: retries + 1, maxRetries, children },
1521
+ { shouldRetry: shouldRetry4, retries: retries + 1, maxRetries, children },
1522
1522
  ctx
1523
1523
  );
1524
1524
  }
@@ -2429,6 +2429,262 @@ function cleanChatCompletionRequest2(chatCompletionRequest) {
2429
2429
 
2430
2430
  // src/lib/anthropic/index.ts
2431
2431
  import AnthropicClient2 from "@anthropic-ai/sdk";
2432
+
2433
+ // src/lib/google/Google.tsx
2434
+ import {
2435
+ VertexAI,
2436
+ GoogleGenerativeAIError
2437
+ } from "@google-cloud/vertexai";
2438
+ var GoogleClientContext = createContext(() => {
2439
+ if (defaultClient3) {
2440
+ return defaultClient3;
2441
+ }
2442
+ const project = process.env.GOOGLE_PROJECT_ID || "";
2443
+ const client = new VertexAI({ project });
2444
+ defaultClient3 = {
2445
+ client,
2446
+ provider: "google"
2447
+ };
2448
+ return defaultClient3;
2449
+ });
2450
+ var defaultClient3 = null;
2451
+ var buildGoogleMessages = (chatMesssages) => {
2452
+ let systemInstruction;
2453
+ const messages = [];
2454
+ chatMesssages.forEach(({ role, content }) => {
2455
+ if (role === "system") {
2456
+ systemInstruction = content;
2457
+ return;
2458
+ }
2459
+ if (role === "user") {
2460
+ const userContent = content;
2461
+ if (userContent.length === 1 && userContent[0].type === "text") {
2462
+ messages.push({
2463
+ role,
2464
+ parts: [{ text: userContent[0].text }]
2465
+ });
2466
+ return;
2467
+ }
2468
+ const c = userContent.map((part) => {
2469
+ if (part.type === "text") {
2470
+ return { text: part.text };
2471
+ } else if (part.type === "image") {
2472
+ const imagePart = {
2473
+ inlineData: {
2474
+ mimeType: part.image.mediaType,
2475
+ data: part.image.data
2476
+ }
2477
+ };
2478
+ return imagePart;
2479
+ }
2480
+ throw new Error("Invalid part");
2481
+ });
2482
+ messages.push({
2483
+ role,
2484
+ parts: c
2485
+ });
2486
+ return;
2487
+ }
2488
+ if (role === "assistant") {
2489
+ messages.push({
2490
+ role,
2491
+ parts: [{ text: content }]
2492
+ });
2493
+ return;
2494
+ }
2495
+ throw new Error(`Invalid role: ${role}`);
2496
+ });
2497
+ return {
2498
+ systemInstruction,
2499
+ messages
2500
+ };
2501
+ };
2502
+ var shouldRetry3 = (error) => {
2503
+ return error instanceof ChatCompletionError && error.shouldRetry;
2504
+ };
2505
+ function GoogleChatCompletion(props, ctx) {
2506
+ const defaultMaxRetries = ctx.getContext(DefaultMaxRetriesContext);
2507
+ return /* @__PURE__ */ jsx(
2508
+ Retry,
2509
+ {
2510
+ maxRetries: props.maxRetries || defaultMaxRetries,
2511
+ shouldRetry: shouldRetry3,
2512
+ children: /* @__PURE__ */ jsx(Trace, { name: "ai.chatCompletion", children: /* @__PURE__ */ jsx(GoogleChatCompletionInner, { ...props }) })
2513
+ }
2514
+ );
2515
+ }
2516
+ async function* GoogleChatCompletionInner(props, ctx) {
2517
+ const startTime = performance.now();
2518
+ const { logger, tracer, getContext } = ctx;
2519
+ const retryCount = getContext(RetryCountContext);
2520
+ const span = tracer.getActiveSpan();
2521
+ const { client, provider, providerRegion, costFn } = getContext(GoogleClientContext)();
2522
+ if (!client) {
2523
+ throw new Error(
2524
+ "[GoogleChatCompletion] must supply GoogleClient via context"
2525
+ );
2526
+ }
2527
+ const chatMessages = await buildChatMessages(ctx, props.children, {
2528
+ useBase64Images: true
2529
+ });
2530
+ const { systemInstruction, messages } = buildGoogleMessages(chatMessages);
2531
+ const inputMessages = chatMessages.map((m) => toDebugMessage(m));
2532
+ let stopSequences;
2533
+ if (props.stop && typeof props.stop === "string") {
2534
+ stopSequences = [props.stop];
2535
+ } else if (Array.isArray(props.stop)) {
2536
+ stopSequences = props.stop;
2537
+ }
2538
+ const googleCompletionRequest = {
2539
+ systemInstruction,
2540
+ contents: messages,
2541
+ generationConfig: {
2542
+ maxOutputTokens: props.maxTokens,
2543
+ temperature: props.temperature,
2544
+ stopSequences
2545
+ }
2546
+ };
2547
+ const chatCompletionRequestToLog = cleanChatCompletionRequest3(
2548
+ googleCompletionRequest
2549
+ );
2550
+ const logRequestData = {
2551
+ startTime,
2552
+ model: props.model,
2553
+ provider,
2554
+ providerRegion,
2555
+ inputMessages,
2556
+ request: chatCompletionRequestToLog
2557
+ };
2558
+ logger.chatCompletionRequest("google", logRequestData);
2559
+ span.setAttributes({
2560
+ model: props.model,
2561
+ provider,
2562
+ providerRegion,
2563
+ requestType: "google",
2564
+ chatCompletionRequest: chatCompletionRequestToLog,
2565
+ inputMessages,
2566
+ retryCount
2567
+ });
2568
+ const model = client.getGenerativeModel({ model: props.model });
2569
+ let response;
2570
+ try {
2571
+ response = await model.generateContentStream(googleCompletionRequest);
2572
+ } catch (err) {
2573
+ if (err instanceof GoogleGenerativeAIError) {
2574
+ throw new ChatCompletionError(
2575
+ err.message,
2576
+ logRequestData,
2577
+ void 0,
2578
+ // always retry on GoogleGenerativeAIError errors, they represent non 4xx error cases
2579
+ true
2580
+ );
2581
+ } else if (err instanceof Error) {
2582
+ const status = void 0;
2583
+ const retry = false;
2584
+ throw new ChatCompletionError(err.message, logRequestData, status, retry);
2585
+ }
2586
+ throw err;
2587
+ }
2588
+ let content = "";
2589
+ let outputUsage = 0;
2590
+ let inputUsage = 0;
2591
+ let finishReason = null;
2592
+ try {
2593
+ for await (const event of response.stream) {
2594
+ if (event.candidates) {
2595
+ const chunk = event.candidates[0].content;
2596
+ if (event.candidates[0]?.finishReason) {
2597
+ finishReason = event.candidates[0].finishReason;
2598
+ }
2599
+ if (event.usageMetadata) {
2600
+ if (event.usageMetadata.promptTokenCount) {
2601
+ inputUsage = event.usageMetadata.promptTokenCount;
2602
+ }
2603
+ if (event.usageMetadata.candidatesTokenCount) {
2604
+ outputUsage = event.usageMetadata.candidatesTokenCount;
2605
+ }
2606
+ }
2607
+ for (const block of chunk.parts) {
2608
+ if (block.text) {
2609
+ content += block.text;
2610
+ yield block.text;
2611
+ }
2612
+ }
2613
+ }
2614
+ }
2615
+ } catch (err) {
2616
+ if (err instanceof GoogleGenerativeAIError) {
2617
+ throw new ChatCompletionError(
2618
+ err.message,
2619
+ logRequestData,
2620
+ void 0,
2621
+ // always retry these errors they represent non 4xx error cases
2622
+ true
2623
+ );
2624
+ } else if (err instanceof Error) {
2625
+ const status = void 0;
2626
+ const retry = false;
2627
+ throw new ChatCompletionError(err.message, logRequestData, status, retry);
2628
+ }
2629
+ throw err;
2630
+ }
2631
+ const outputMessage = {
2632
+ role: "assistant",
2633
+ content
2634
+ };
2635
+ const tokensUsed = {
2636
+ prompt: inputUsage,
2637
+ completion: outputUsage,
2638
+ total: inputUsage + outputUsage
2639
+ };
2640
+ const cost = costFn?.(props.model, tokensUsed) ?? void 0;
2641
+ const responseData = {
2642
+ ...logRequestData,
2643
+ finishReason,
2644
+ latency: performance.now() - startTime,
2645
+ inputMessages,
2646
+ outputMessage,
2647
+ tokensUsed
2648
+ };
2649
+ logger.chatCompletionResponse("google", responseData);
2650
+ span.setAttributes({
2651
+ tokensUsed,
2652
+ output: content,
2653
+ cost,
2654
+ finishReason
2655
+ });
2656
+ }
2657
+ function cleanChatCompletionRequest3(chatCompletionRequest) {
2658
+ const { contents, ...rest } = chatCompletionRequest;
2659
+ return {
2660
+ ...rest,
2661
+ contents: contents.map((message) => {
2662
+ if (message.role !== "user") {
2663
+ return message;
2664
+ }
2665
+ return {
2666
+ ...message,
2667
+ parts: message.parts.map((part) => {
2668
+ if ("text" in part) {
2669
+ return part;
2670
+ } else if ("inlineData" in part) {
2671
+ return {
2672
+ inlineData: {
2673
+ ...part.inlineData,
2674
+ mimeType: part.inlineData?.mimeType || "",
2675
+ data: part.inlineData?.data?.slice(0, 22) + "..."
2676
+ }
2677
+ };
2678
+ }
2679
+ return part;
2680
+ })
2681
+ };
2682
+ })
2683
+ };
2684
+ }
2685
+
2686
+ // src/lib/google/index.ts
2687
+ import { VertexAI as VertexAI2 } from "@google-cloud/vertexai";
2432
2688
  export {
2433
2689
  AIFragment,
2434
2690
  AISpanProcessor,
@@ -2443,6 +2699,8 @@ export {
2443
2699
  DefaultMaxRetriesContext,
2444
2700
  EnrichingSpanProcessor,
2445
2701
  Fallback,
2702
+ GoogleChatCompletion,
2703
+ GoogleClientContext,
2446
2704
  ImagePart,
2447
2705
  LogImplementation,
2448
2706
  NoopLogImplementation,
@@ -2456,6 +2714,7 @@ export {
2456
2714
  SystemMessage,
2457
2715
  Trace,
2458
2716
  UserMessage,
2717
+ VertexAI2 as VertexAI,
2459
2718
  anthropicTokenizer,
2460
2719
  attachedContextSymbol,
2461
2720
  computeUsage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gammatech/aijsx",
3
- "version": "0.9.0-dev.2024-05-28",
3
+ "version": "0.9.1-dev.2024-05-28",
4
4
  "description": "Rewrite of aijsx",
5
5
  "author": "Jordan Garcia",
6
6
  "license": "MIT",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@anthropic-ai/sdk": "0.19.1",
22
22
  "@anthropic-ai/tokenizer": "^0.0.4",
23
- "exif-reader": "^2.0.1",
23
+ "@google-cloud/vertexai": "^1.2.0",
24
24
  "fast-xml-parser": "^4.3.4",
25
25
  "js-tiktoken": "^1.0.8",
26
26
  "nanoid": "^3.1.23",