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

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,268 @@ 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 = (chatMessages) => {
2550
+ let systemInstruction;
2551
+ const messages = [];
2552
+ chatMessages.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
+ if (event.candidates[0]?.finishReason) {
2694
+ finishReason = event.candidates[0].finishReason;
2695
+ }
2696
+ if (event.usageMetadata) {
2697
+ if (event.usageMetadata.promptTokenCount) {
2698
+ inputUsage = event.usageMetadata.promptTokenCount;
2699
+ }
2700
+ if (event.usageMetadata.candidatesTokenCount) {
2701
+ outputUsage = event.usageMetadata.candidatesTokenCount;
2702
+ }
2703
+ }
2704
+ const chunk = event.candidates[0].content;
2705
+ if (!chunk || !chunk.parts) {
2706
+ console.error(
2707
+ `Google response chunk is missing 'parts' field: ${JSON.stringify(
2708
+ chunk
2709
+ )}`
2710
+ );
2711
+ continue;
2712
+ }
2713
+ if (chunk.parts)
2714
+ for (const block of chunk.parts) {
2715
+ if (block.text) {
2716
+ content += block.text;
2717
+ yield block.text;
2718
+ }
2719
+ }
2720
+ }
2721
+ }
2722
+ } catch (err) {
2723
+ if (err instanceof import_vertexai.GoogleGenerativeAIError) {
2724
+ throw new ChatCompletionError(
2725
+ err.message,
2726
+ logRequestData,
2727
+ void 0,
2728
+ // always retry these errors they represent non 4xx error cases
2729
+ true
2730
+ );
2731
+ } else if (err instanceof Error) {
2732
+ const status = void 0;
2733
+ const retry = false;
2734
+ throw new ChatCompletionError(err.message, logRequestData, status, retry);
2735
+ }
2736
+ throw err;
2737
+ }
2738
+ const outputMessage = {
2739
+ role: "assistant",
2740
+ content
2741
+ };
2742
+ const tokensUsed = {
2743
+ prompt: inputUsage,
2744
+ completion: outputUsage,
2745
+ total: inputUsage + outputUsage
2746
+ };
2747
+ const cost = costFn?.(props.model, tokensUsed) ?? void 0;
2748
+ const responseData = {
2749
+ ...logRequestData,
2750
+ finishReason,
2751
+ latency: performance.now() - startTime,
2752
+ inputMessages,
2753
+ outputMessage,
2754
+ tokensUsed
2755
+ };
2756
+ logger.chatCompletionResponse("google", responseData);
2757
+ span.setAttributes({
2758
+ tokensUsed,
2759
+ output: content,
2760
+ cost,
2761
+ finishReason
2762
+ });
2763
+ }
2764
+ function cleanChatCompletionRequest3(chatCompletionRequest) {
2765
+ const { contents, ...rest } = chatCompletionRequest;
2766
+ return {
2767
+ ...rest,
2768
+ contents: contents.map((message) => {
2769
+ if (message.role !== "user") {
2770
+ return message;
2771
+ }
2772
+ return {
2773
+ ...message,
2774
+ parts: message.parts.map((part) => {
2775
+ if ("text" in part) {
2776
+ return part;
2777
+ } else if ("inlineData" in part) {
2778
+ return {
2779
+ inlineData: {
2780
+ ...part.inlineData,
2781
+ mimeType: part.inlineData?.mimeType || "",
2782
+ data: part.inlineData?.data?.slice(0, 22) + "..."
2783
+ }
2784
+ };
2785
+ }
2786
+ return part;
2787
+ })
2788
+ };
2789
+ })
2790
+ };
2791
+ }
2792
+
2793
+ // src/lib/google/index.ts
2794
+ var import_vertexai2 = require("@google-cloud/vertexai");
2530
2795
  // Annotate the CommonJS export names for ESM import in node:
2531
2796
  0 && (module.exports = {
2532
2797
  AIFragment,
@@ -2542,6 +2807,8 @@ var import_sdk2 = __toESM(require("@anthropic-ai/sdk"));
2542
2807
  DefaultMaxRetriesContext,
2543
2808
  EnrichingSpanProcessor,
2544
2809
  Fallback,
2810
+ GoogleChatCompletion,
2811
+ GoogleClientContext,
2545
2812
  ImagePart,
2546
2813
  LogImplementation,
2547
2814
  NoopLogImplementation,
@@ -2555,6 +2822,7 @@ var import_sdk2 = __toESM(require("@anthropic-ai/sdk"));
2555
2822
  SystemMessage,
2556
2823
  Trace,
2557
2824
  UserMessage,
2825
+ VertexAI,
2558
2826
  anthropicTokenizer,
2559
2827
  attachedContextSymbol,
2560
2828
  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,271 @@ 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 = (chatMessages) => {
2452
+ let systemInstruction;
2453
+ const messages = [];
2454
+ chatMessages.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
+ if (event.candidates[0]?.finishReason) {
2596
+ finishReason = event.candidates[0].finishReason;
2597
+ }
2598
+ if (event.usageMetadata) {
2599
+ if (event.usageMetadata.promptTokenCount) {
2600
+ inputUsage = event.usageMetadata.promptTokenCount;
2601
+ }
2602
+ if (event.usageMetadata.candidatesTokenCount) {
2603
+ outputUsage = event.usageMetadata.candidatesTokenCount;
2604
+ }
2605
+ }
2606
+ const chunk = event.candidates[0].content;
2607
+ if (!chunk || !chunk.parts) {
2608
+ console.error(
2609
+ `Google response chunk is missing 'parts' field: ${JSON.stringify(
2610
+ chunk
2611
+ )}`
2612
+ );
2613
+ continue;
2614
+ }
2615
+ if (chunk.parts)
2616
+ for (const block of chunk.parts) {
2617
+ if (block.text) {
2618
+ content += block.text;
2619
+ yield block.text;
2620
+ }
2621
+ }
2622
+ }
2623
+ }
2624
+ } catch (err) {
2625
+ if (err instanceof GoogleGenerativeAIError) {
2626
+ throw new ChatCompletionError(
2627
+ err.message,
2628
+ logRequestData,
2629
+ void 0,
2630
+ // always retry these errors they represent non 4xx error cases
2631
+ true
2632
+ );
2633
+ } else if (err instanceof Error) {
2634
+ const status = void 0;
2635
+ const retry = false;
2636
+ throw new ChatCompletionError(err.message, logRequestData, status, retry);
2637
+ }
2638
+ throw err;
2639
+ }
2640
+ const outputMessage = {
2641
+ role: "assistant",
2642
+ content
2643
+ };
2644
+ const tokensUsed = {
2645
+ prompt: inputUsage,
2646
+ completion: outputUsage,
2647
+ total: inputUsage + outputUsage
2648
+ };
2649
+ const cost = costFn?.(props.model, tokensUsed) ?? void 0;
2650
+ const responseData = {
2651
+ ...logRequestData,
2652
+ finishReason,
2653
+ latency: performance.now() - startTime,
2654
+ inputMessages,
2655
+ outputMessage,
2656
+ tokensUsed
2657
+ };
2658
+ logger.chatCompletionResponse("google", responseData);
2659
+ span.setAttributes({
2660
+ tokensUsed,
2661
+ output: content,
2662
+ cost,
2663
+ finishReason
2664
+ });
2665
+ }
2666
+ function cleanChatCompletionRequest3(chatCompletionRequest) {
2667
+ const { contents, ...rest } = chatCompletionRequest;
2668
+ return {
2669
+ ...rest,
2670
+ contents: contents.map((message) => {
2671
+ if (message.role !== "user") {
2672
+ return message;
2673
+ }
2674
+ return {
2675
+ ...message,
2676
+ parts: message.parts.map((part) => {
2677
+ if ("text" in part) {
2678
+ return part;
2679
+ } else if ("inlineData" in part) {
2680
+ return {
2681
+ inlineData: {
2682
+ ...part.inlineData,
2683
+ mimeType: part.inlineData?.mimeType || "",
2684
+ data: part.inlineData?.data?.slice(0, 22) + "..."
2685
+ }
2686
+ };
2687
+ }
2688
+ return part;
2689
+ })
2690
+ };
2691
+ })
2692
+ };
2693
+ }
2694
+
2695
+ // src/lib/google/index.ts
2696
+ import { VertexAI as VertexAI2 } from "@google-cloud/vertexai";
2432
2697
  export {
2433
2698
  AIFragment,
2434
2699
  AISpanProcessor,
@@ -2443,6 +2708,8 @@ export {
2443
2708
  DefaultMaxRetriesContext,
2444
2709
  EnrichingSpanProcessor,
2445
2710
  Fallback,
2711
+ GoogleChatCompletion,
2712
+ GoogleClientContext,
2446
2713
  ImagePart,
2447
2714
  LogImplementation,
2448
2715
  NoopLogImplementation,
@@ -2456,6 +2723,7 @@ export {
2456
2723
  SystemMessage,
2457
2724
  Trace,
2458
2725
  UserMessage,
2726
+ VertexAI2 as VertexAI,
2459
2727
  anthropicTokenizer,
2460
2728
  attachedContextSymbol,
2461
2729
  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.2-dev.2024-05-30",
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",