@gammatech/aijsx 0.10.2-dev.2024-06-11 → 0.11.1-dev.2024-06-23

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
@@ -13,8 +13,9 @@ declare class ChatCompletionError extends Error {
13
13
  readonly chatCompletionRequest: LogChatCompletionRequest;
14
14
  readonly status: number | undefined;
15
15
  readonly shouldRetry: boolean;
16
+ readonly originalError?: Error | undefined;
16
17
  readonly name = "ChatCompletionError";
17
- constructor(message: string, chatCompletionRequest: LogChatCompletionRequest, status: number | undefined, shouldRetry?: boolean);
18
+ constructor(message: string, chatCompletionRequest: LogChatCompletionRequest, status: number | undefined, shouldRetry?: boolean, originalError?: Error | undefined);
18
19
  }
19
20
 
20
21
  declare const SystemMessage: (props: {
@@ -43,6 +44,10 @@ type ChatCompletionClientAndProvider<K> = {
43
44
  completion: number;
44
45
  }) => number;
45
46
  };
47
+ type GetChatCompletionClientAndProvider<Model, Client> = (model: Model, args: {
48
+ retryCount: number;
49
+ lastError?: Error | null;
50
+ }) => Promise<ChatCompletionClientAndProvider<Client>>;
46
51
 
47
52
  type CreateRenderContextOptions = {
48
53
  logger?: LogImplementation;
@@ -52,15 +57,25 @@ type CreateRenderContextOptions = {
52
57
  };
53
58
  declare function createRenderContext({ logger, traceId, processor, contextValues, }?: CreateRenderContextOptions): RenderContext;
54
59
 
55
- declare const RetryCountContext: Context<number>;
60
+ type ExcludeNumber<E extends number, T = number> = T extends E ? never : T;
61
+ type RetryCountContextValue = {
62
+ retryCount: 0;
63
+ lastError: null;
64
+ } | {
65
+ retryCount: ExcludeNumber<0>;
66
+ lastError: Error;
67
+ };
68
+ declare const RetryCountContext: Context<RetryCountContextValue>;
69
+ declare const RetryLastErrorContext: Context<Error | null>;
56
70
  declare const DefaultMaxRetriesContext: Context<number>;
57
71
  type RetryProps = {
58
72
  shouldRetry: (error: Error) => boolean;
59
73
  retries?: number;
74
+ lastError?: Error;
60
75
  maxRetries?: number;
61
76
  children: AINode;
62
77
  };
63
- declare function Retry({ shouldRetry, retries, maxRetries, children }: RetryProps, ctx: RenderContext): AsyncGenerator<string, void, unknown>;
78
+ declare function Retry({ shouldRetry, retries, maxRetries, lastError, children }: RetryProps, ctx: RenderContext): AsyncGenerator<string, void, unknown>;
64
79
 
65
80
  type FallbackProps = {
66
81
  fallback: AINode;
@@ -241,7 +256,7 @@ declare module '@gammatech/aijsx' {
241
256
  }
242
257
  type ValidOpenAIVisionModel = 'gpt-4o' | 'gpt-4o-2024-05-13' | 'gpt-4-turbo-2024-04-09' | 'gpt-4-turbo' | 'gpt-4-vision-preview';
243
258
  type ValidOpenAIChatModel = ValidOpenAIVisionModel | 'gpt-4' | 'gpt-4-0314' | 'gpt-4-0613' | 'gpt-4-32k' | 'gpt-4-32k-0314' | 'gpt-4-32k-0613' | 'gpt-4-1106-preview' | 'gpt-4-0125-preview' | 'gpt-3.5-turbo' | 'gpt-3.5-turbo-0301' | 'gpt-3.5-turbo-0613' | 'gpt-3.5-turbo-16k' | 'gpt-3.5-turbo-16k-0613' | 'gpt-3.5-turbo-1106' | 'gpt-3.5-turbo-0125';
244
- declare const OpenAIClientContext: Context<() => ChatCompletionClientAndProvider<OpenAI>>;
259
+ declare const OpenAIClientContext: Context<GetChatCompletionClientAndProvider<ValidOpenAIChatModel, OpenAI>>;
245
260
  type OpenAIChatCompletionProps = {
246
261
  model: ValidOpenAIChatModel;
247
262
  maxTokens?: number;
@@ -265,8 +280,8 @@ declare module '@gammatech/aijsx' {
265
280
  * The set of valid Claude models.
266
281
  * @see https://docs.anthropic.com/claude/reference/selecting-a-model
267
282
  */
268
- type ValidAnthropicChatModel = 'claude-instant-1.2' | 'claude-2.1' | 'claude-3-opus-20240229' | 'claude-3-sonnet-20240229' | 'claude-3-haiku-20240307';
269
- declare const AnthropicClientContext: Context<() => ChatCompletionClientAndProvider<AnthropicClient>>;
283
+ type ValidAnthropicChatModel = 'claude-instant-1.2' | 'claude-2.1' | 'claude-3-opus-20240229' | 'claude-3-sonnet-20240229' | 'claude-3-haiku-20240307' | 'claude-3-5-sonnet-20240620';
284
+ declare const AnthropicClientContext: Context<GetChatCompletionClientAndProvider<ValidAnthropicChatModel, AnthropicClient>>;
270
285
  type AnthropicChatCompletionProps = {
271
286
  model: ValidAnthropicChatModel;
272
287
  maxTokens?: number;
@@ -291,7 +306,7 @@ declare module '@gammatech/aijsx' {
291
306
  }
292
307
  }
293
308
  type ValidGoogleChatModel = 'gemini-1.5-pro' | 'gemini-1.5-flash';
294
- declare const GoogleClientContext: Context<() => ChatCompletionClientAndProvider<VertexAI>>;
309
+ declare const GoogleClientContext: Context<GetChatCompletionClientAndProvider<ValidGoogleChatModel, VertexAI>>;
295
310
  type GoogleChatCompletionProps = {
296
311
  model: ValidGoogleChatModel;
297
312
  maxTokens?: number;
@@ -306,4 +321,4 @@ type GoogleChatCompletionProps = {
306
321
  };
307
322
  declare function GoogleChatCompletion(props: GoogleChatCompletionProps, ctx: RenderContext): JSX.Element;
308
323
 
309
- 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, GoogleChatCompletion, type GoogleChatCompletionRequest, GoogleClientContext, LogChatCompletionRequest, LogImplementation, OpenAIChatCompletion, type OpenAIChatCompletionRequest, type OpenAIChatMessage, OpenAIClientContext, ParseVariablesError, ProcessedAISpanAttributes, type Prompt, PromptInvalidOutputError, PromptParsed, ReadableSpan, RenderContext, Retry, RetryCountContext, SpanAttributes, SpanExporter, SpanProcessor, SystemMessage, type TokenizerFn, Trace, Tracer, UserMessage, type ValidAnthropicChatModel, type ValidGoogleChatModel, type ValidOpenAIChatModel, type ValidOpenAIVisionModel, anthropicTokenizer, computeUsage, createPrompt, createRenderContext, evaluatePrompt, isPromptParsed, openaiTokenizer, tracing };
324
+ 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, type GetChatCompletionClientAndProvider, GoogleChatCompletion, type GoogleChatCompletionRequest, GoogleClientContext, LogChatCompletionRequest, LogImplementation, OpenAIChatCompletion, type OpenAIChatCompletionRequest, type OpenAIChatMessage, OpenAIClientContext, ParseVariablesError, ProcessedAISpanAttributes, type Prompt, PromptInvalidOutputError, PromptParsed, ReadableSpan, RenderContext, Retry, RetryCountContext, RetryLastErrorContext, SpanAttributes, SpanExporter, SpanProcessor, SystemMessage, type TokenizerFn, Trace, Tracer, UserMessage, type ValidAnthropicChatModel, type ValidGoogleChatModel, type ValidOpenAIChatModel, type ValidOpenAIVisionModel, anthropicTokenizer, computeUsage, createPrompt, createRenderContext, evaluatePrompt, isPromptParsed, openaiTokenizer, tracing };
package/dist/index.d.ts CHANGED
@@ -13,8 +13,9 @@ declare class ChatCompletionError extends Error {
13
13
  readonly chatCompletionRequest: LogChatCompletionRequest;
14
14
  readonly status: number | undefined;
15
15
  readonly shouldRetry: boolean;
16
+ readonly originalError?: Error | undefined;
16
17
  readonly name = "ChatCompletionError";
17
- constructor(message: string, chatCompletionRequest: LogChatCompletionRequest, status: number | undefined, shouldRetry?: boolean);
18
+ constructor(message: string, chatCompletionRequest: LogChatCompletionRequest, status: number | undefined, shouldRetry?: boolean, originalError?: Error | undefined);
18
19
  }
19
20
 
20
21
  declare const SystemMessage: (props: {
@@ -43,6 +44,10 @@ type ChatCompletionClientAndProvider<K> = {
43
44
  completion: number;
44
45
  }) => number;
45
46
  };
47
+ type GetChatCompletionClientAndProvider<Model, Client> = (model: Model, args: {
48
+ retryCount: number;
49
+ lastError?: Error | null;
50
+ }) => Promise<ChatCompletionClientAndProvider<Client>>;
46
51
 
47
52
  type CreateRenderContextOptions = {
48
53
  logger?: LogImplementation;
@@ -52,15 +57,25 @@ type CreateRenderContextOptions = {
52
57
  };
53
58
  declare function createRenderContext({ logger, traceId, processor, contextValues, }?: CreateRenderContextOptions): RenderContext;
54
59
 
55
- declare const RetryCountContext: Context<number>;
60
+ type ExcludeNumber<E extends number, T = number> = T extends E ? never : T;
61
+ type RetryCountContextValue = {
62
+ retryCount: 0;
63
+ lastError: null;
64
+ } | {
65
+ retryCount: ExcludeNumber<0>;
66
+ lastError: Error;
67
+ };
68
+ declare const RetryCountContext: Context<RetryCountContextValue>;
69
+ declare const RetryLastErrorContext: Context<Error | null>;
56
70
  declare const DefaultMaxRetriesContext: Context<number>;
57
71
  type RetryProps = {
58
72
  shouldRetry: (error: Error) => boolean;
59
73
  retries?: number;
74
+ lastError?: Error;
60
75
  maxRetries?: number;
61
76
  children: AINode;
62
77
  };
63
- declare function Retry({ shouldRetry, retries, maxRetries, children }: RetryProps, ctx: RenderContext): AsyncGenerator<string, void, unknown>;
78
+ declare function Retry({ shouldRetry, retries, maxRetries, lastError, children }: RetryProps, ctx: RenderContext): AsyncGenerator<string, void, unknown>;
64
79
 
65
80
  type FallbackProps = {
66
81
  fallback: AINode;
@@ -241,7 +256,7 @@ declare module '@gammatech/aijsx' {
241
256
  }
242
257
  type ValidOpenAIVisionModel = 'gpt-4o' | 'gpt-4o-2024-05-13' | 'gpt-4-turbo-2024-04-09' | 'gpt-4-turbo' | 'gpt-4-vision-preview';
243
258
  type ValidOpenAIChatModel = ValidOpenAIVisionModel | 'gpt-4' | 'gpt-4-0314' | 'gpt-4-0613' | 'gpt-4-32k' | 'gpt-4-32k-0314' | 'gpt-4-32k-0613' | 'gpt-4-1106-preview' | 'gpt-4-0125-preview' | 'gpt-3.5-turbo' | 'gpt-3.5-turbo-0301' | 'gpt-3.5-turbo-0613' | 'gpt-3.5-turbo-16k' | 'gpt-3.5-turbo-16k-0613' | 'gpt-3.5-turbo-1106' | 'gpt-3.5-turbo-0125';
244
- declare const OpenAIClientContext: Context<() => ChatCompletionClientAndProvider<OpenAI>>;
259
+ declare const OpenAIClientContext: Context<GetChatCompletionClientAndProvider<ValidOpenAIChatModel, OpenAI>>;
245
260
  type OpenAIChatCompletionProps = {
246
261
  model: ValidOpenAIChatModel;
247
262
  maxTokens?: number;
@@ -265,8 +280,8 @@ declare module '@gammatech/aijsx' {
265
280
  * The set of valid Claude models.
266
281
  * @see https://docs.anthropic.com/claude/reference/selecting-a-model
267
282
  */
268
- type ValidAnthropicChatModel = 'claude-instant-1.2' | 'claude-2.1' | 'claude-3-opus-20240229' | 'claude-3-sonnet-20240229' | 'claude-3-haiku-20240307';
269
- declare const AnthropicClientContext: Context<() => ChatCompletionClientAndProvider<AnthropicClient>>;
283
+ type ValidAnthropicChatModel = 'claude-instant-1.2' | 'claude-2.1' | 'claude-3-opus-20240229' | 'claude-3-sonnet-20240229' | 'claude-3-haiku-20240307' | 'claude-3-5-sonnet-20240620';
284
+ declare const AnthropicClientContext: Context<GetChatCompletionClientAndProvider<ValidAnthropicChatModel, AnthropicClient>>;
270
285
  type AnthropicChatCompletionProps = {
271
286
  model: ValidAnthropicChatModel;
272
287
  maxTokens?: number;
@@ -291,7 +306,7 @@ declare module '@gammatech/aijsx' {
291
306
  }
292
307
  }
293
308
  type ValidGoogleChatModel = 'gemini-1.5-pro' | 'gemini-1.5-flash';
294
- declare const GoogleClientContext: Context<() => ChatCompletionClientAndProvider<VertexAI>>;
309
+ declare const GoogleClientContext: Context<GetChatCompletionClientAndProvider<ValidGoogleChatModel, VertexAI>>;
295
310
  type GoogleChatCompletionProps = {
296
311
  model: ValidGoogleChatModel;
297
312
  maxTokens?: number;
@@ -306,4 +321,4 @@ type GoogleChatCompletionProps = {
306
321
  };
307
322
  declare function GoogleChatCompletion(props: GoogleChatCompletionProps, ctx: RenderContext): JSX.Element;
308
323
 
309
- 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, GoogleChatCompletion, type GoogleChatCompletionRequest, GoogleClientContext, LogChatCompletionRequest, LogImplementation, OpenAIChatCompletion, type OpenAIChatCompletionRequest, type OpenAIChatMessage, OpenAIClientContext, ParseVariablesError, ProcessedAISpanAttributes, type Prompt, PromptInvalidOutputError, PromptParsed, ReadableSpan, RenderContext, Retry, RetryCountContext, SpanAttributes, SpanExporter, SpanProcessor, SystemMessage, type TokenizerFn, Trace, Tracer, UserMessage, type ValidAnthropicChatModel, type ValidGoogleChatModel, type ValidOpenAIChatModel, type ValidOpenAIVisionModel, anthropicTokenizer, computeUsage, createPrompt, createRenderContext, evaluatePrompt, isPromptParsed, openaiTokenizer, tracing };
324
+ 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, type GetChatCompletionClientAndProvider, GoogleChatCompletion, type GoogleChatCompletionRequest, GoogleClientContext, LogChatCompletionRequest, LogImplementation, OpenAIChatCompletion, type OpenAIChatCompletionRequest, type OpenAIChatMessage, OpenAIClientContext, ParseVariablesError, ProcessedAISpanAttributes, type Prompt, PromptInvalidOutputError, PromptParsed, ReadableSpan, RenderContext, Retry, RetryCountContext, RetryLastErrorContext, SpanAttributes, SpanExporter, SpanProcessor, SystemMessage, type TokenizerFn, Trace, Tracer, UserMessage, type ValidAnthropicChatModel, type ValidGoogleChatModel, type ValidOpenAIChatModel, type ValidOpenAIVisionModel, anthropicTokenizer, computeUsage, createPrompt, createRenderContext, evaluatePrompt, isPromptParsed, openaiTokenizer, tracing };
package/dist/index.js CHANGED
@@ -56,6 +56,7 @@ __export(src_exports, {
56
56
  PromptInvalidOutputError: () => PromptInvalidOutputError,
57
57
  Retry: () => Retry,
58
58
  RetryCountContext: () => RetryCountContext,
59
+ RetryLastErrorContext: () => RetryLastErrorContext,
59
60
  SystemMessage: () => SystemMessage,
60
61
  Trace: () => Trace,
61
62
  UserMessage: () => UserMessage,
@@ -77,11 +78,12 @@ module.exports = __toCommonJS(src_exports);
77
78
 
78
79
  // src/chat/errors.ts
79
80
  var ChatCompletionError = class extends Error {
80
- constructor(message, chatCompletionRequest, status, shouldRetry4 = false) {
81
+ constructor(message, chatCompletionRequest, status, shouldRetry4 = false, originalError) {
81
82
  super(message);
82
83
  this.chatCompletionRequest = chatCompletionRequest;
83
84
  this.status = status;
84
85
  this.shouldRetry = shouldRetry4;
86
+ this.originalError = originalError;
85
87
  }
86
88
  name = "ChatCompletionError";
87
89
  };
@@ -1537,27 +1539,67 @@ function renderCloseTag(element) {
1537
1539
  return `</${element.tag.name}>`;
1538
1540
  }
1539
1541
 
1542
+ // src/utils.ts
1543
+ function getEnvVar(name, shouldThrow = true) {
1544
+ let env = globalThis.process?.env ?? void 0;
1545
+ if (env === void 0) {
1546
+ try {
1547
+ env = process.env;
1548
+ } catch {
1549
+ }
1550
+ }
1551
+ const result = env?.[name];
1552
+ if (result === void 0 && shouldThrow) {
1553
+ throw new Error(`Please specify env var '${name}'`);
1554
+ }
1555
+ return result;
1556
+ }
1557
+ var castToError = (e) => {
1558
+ if (e instanceof Error) {
1559
+ return e;
1560
+ }
1561
+ if (typeof e === "string") {
1562
+ return new Error(e);
1563
+ }
1564
+ return new Error("Unknown error");
1565
+ };
1566
+
1540
1567
  // src/retry.tsx
1541
- var RetryCountContext = createContext(0);
1568
+ var RetryCountContext = createContext({
1569
+ retryCount: 0,
1570
+ lastError: null
1571
+ });
1572
+ var RetryLastErrorContext = createContext(null);
1542
1573
  var DefaultMaxRetriesContext = createContext(0);
1543
- async function* Retry({ shouldRetry: shouldRetry4, retries = 0, maxRetries = 3, children }, ctx) {
1574
+ async function* Retry({ shouldRetry: shouldRetry4, retries = 0, maxRetries = 3, lastError, children }, ctx) {
1544
1575
  const { render } = ctx;
1545
1576
  let hasYieldedData = false;
1546
1577
  try {
1578
+ const ctxValue = retries === 0 ? { retryCount: 0, lastError: null } : {
1579
+ retryCount: retries,
1580
+ lastError
1581
+ };
1547
1582
  const result = render(
1548
- /* @__PURE__ */ jsx(RetryCountContext.Provider, { value: retries, children })
1583
+ /* @__PURE__ */ jsx(RetryCountContext.Provider, { value: ctxValue, children })
1549
1584
  );
1550
1585
  for await (const value of result) {
1551
1586
  hasYieldedData = true;
1552
1587
  yield value;
1553
1588
  }
1554
1589
  } catch (e) {
1555
- if (hasYieldedData || retries >= maxRetries || !shouldRetry4(e)) {
1590
+ const err = castToError(e);
1591
+ if (hasYieldedData || retries >= maxRetries || !shouldRetry4(err)) {
1556
1592
  throw e;
1557
1593
  }
1558
1594
  await backoff(retries);
1559
1595
  yield* Retry(
1560
- { shouldRetry: shouldRetry4, retries: retries + 1, maxRetries, children },
1596
+ {
1597
+ shouldRetry: shouldRetry4,
1598
+ retries: retries + 1,
1599
+ maxRetries,
1600
+ lastError: err,
1601
+ children
1602
+ },
1561
1603
  ctx
1562
1604
  );
1563
1605
  }
@@ -1903,25 +1945,6 @@ function isPromptParsed2(prompt) {
1903
1945
  // src/lib/openai/OpenAI.tsx
1904
1946
  var import_openai2 = require("openai");
1905
1947
 
1906
- // src/lib/openai/shouldRetryOpenAI.ts
1907
- var import_openai = require("openai");
1908
- var shouldRetryOpenAI = (error) => {
1909
- if (error instanceof import_openai.OpenAI.APIConnectionError) {
1910
- return true;
1911
- }
1912
- if (error instanceof import_openai.OpenAI.APIError) {
1913
- if ("status" in error && typeof error.status === "number") {
1914
- if (error.status === 409)
1915
- return true;
1916
- if (error.status === 429)
1917
- return true;
1918
- if (error.status >= 500)
1919
- return true;
1920
- }
1921
- }
1922
- return false;
1923
- };
1924
-
1925
1948
  // src/lib/openai/tokenizer.ts
1926
1949
  var import_js_tiktoken = require("js-tiktoken");
1927
1950
  var cl100kTokenizer = (0, import_js_tiktoken.getEncoding)("cl100k_base");
@@ -2033,25 +2056,39 @@ async function buildChatMessages(ctx, children, opts) {
2033
2056
  });
2034
2057
  }
2035
2058
 
2036
- // src/utils.ts
2037
- function getEnvVar(name, shouldThrow = true) {
2038
- let env = globalThis.process?.env ?? void 0;
2039
- if (env === void 0) {
2040
- try {
2041
- env = process.env;
2042
- } catch {
2043
- }
2059
+ // src/lib/openai/errors.ts
2060
+ var import_openai = require("openai");
2061
+ var extractStatusFromError = (error) => {
2062
+ if (error instanceof import_openai.OpenAI.APIError) {
2063
+ return error.status;
2064
+ } else if (error instanceof import_openai.OpenAI.APIConnectionError) {
2065
+ return void 0;
2066
+ } else {
2067
+ return void 0;
2044
2068
  }
2045
- const result = env?.[name];
2046
- if (result === void 0 && shouldThrow) {
2047
- throw new Error(`Please specify env var '${name}'`);
2069
+ };
2070
+ var errorToChatCompletionError = (error, requestData) => {
2071
+ const castError = castToError(error);
2072
+ const status = extractStatusFromError(castError);
2073
+ let messagePrefix = "";
2074
+ if (error instanceof import_openai.OpenAI.APIError) {
2075
+ messagePrefix = "OpenAIClient.APIError: ";
2076
+ } else if (error instanceof import_openai.OpenAI.APIConnectionError) {
2077
+ messagePrefix = "OpenAIClient.APIConnectionError: ";
2048
2078
  }
2049
- return result;
2050
- }
2079
+ const shouldRetry4 = status !== 400;
2080
+ return new ChatCompletionError(
2081
+ `${messagePrefix}${castError.message}`,
2082
+ requestData,
2083
+ status,
2084
+ shouldRetry4,
2085
+ error instanceof Error ? error : void 0
2086
+ );
2087
+ };
2051
2088
 
2052
2089
  // src/lib/openai/OpenAI.tsx
2053
2090
  var defaultClient = null;
2054
- var OpenAIClientContext = createContext(() => {
2091
+ var OpenAIClientContext = createContext(async () => {
2055
2092
  if (defaultClient) {
2056
2093
  return defaultClient;
2057
2094
  }
@@ -2123,9 +2160,16 @@ function OpenAIChatCompletion(props, ctx) {
2123
2160
  async function* OpenAIChatCompletionInner(props, ctx) {
2124
2161
  const startTime = performance.now();
2125
2162
  const { logger, tracer, getContext } = ctx;
2126
- const retryCount = getContext(RetryCountContext);
2163
+ const { retryCount, lastError } = getContext(RetryCountContext);
2127
2164
  const span = tracer.getActiveSpan();
2128
- const { client, provider, providerRegion, costFn } = getContext(OpenAIClientContext)();
2165
+ const getClientFn = getContext(OpenAIClientContext);
2166
+ const { client, provider, providerRegion, costFn } = await getClientFn(
2167
+ props.model,
2168
+ {
2169
+ retryCount,
2170
+ lastError
2171
+ }
2172
+ );
2129
2173
  if (!client) {
2130
2174
  throw new Error("[OpenAI] must supply OpenAI model via context");
2131
2175
  }
@@ -2170,38 +2214,32 @@ async function* OpenAIChatCompletionInner(props, ctx) {
2170
2214
  try {
2171
2215
  chatResponse = await client.chat.completions.create(chatCompletionRequest);
2172
2216
  } catch (ex) {
2173
- const retry = shouldRetryOpenAI(ex);
2174
- if (ex instanceof import_openai2.OpenAI.APIError) {
2175
- throw new ChatCompletionError(
2176
- `OpenAIClient.APIError: ${ex.message}`,
2177
- logRequestData,
2178
- ex.status,
2179
- retry
2180
- );
2181
- } else if (ex instanceof Error) {
2182
- throw new ChatCompletionError(
2183
- ex.message,
2184
- logRequestData,
2185
- void 0,
2186
- retry
2187
- );
2188
- }
2189
- throw ex;
2217
+ throw errorToChatCompletionError(ex, logRequestData);
2190
2218
  }
2191
2219
  let finishReason = void 0;
2192
2220
  let content = "";
2193
- for await (const message of chatResponse) {
2194
- if (!message.choices || !message.choices[0]) {
2195
- continue;
2196
- }
2197
- const delta = message.choices[0].delta;
2198
- if (message.choices[0].finish_reason) {
2199
- finishReason = message.choices[0].finish_reason;
2200
- }
2201
- if (delta.content) {
2202
- content += delta.content;
2203
- yield delta.content;
2221
+ try {
2222
+ for await (const message of chatResponse) {
2223
+ if (!message.choices || !message.choices[0]) {
2224
+ continue;
2225
+ }
2226
+ const delta = message.choices[0].delta;
2227
+ if (message.choices[0].finish_reason) {
2228
+ finishReason = message.choices[0].finish_reason;
2229
+ span.setAttributes({
2230
+ finishReason
2231
+ });
2232
+ }
2233
+ if (delta.content) {
2234
+ content += delta.content;
2235
+ yield delta.content;
2236
+ }
2204
2237
  }
2238
+ } catch (e) {
2239
+ span.setAttributes({
2240
+ output: content
2241
+ });
2242
+ throw errorToChatCompletionError(e, logRequestData);
2205
2243
  }
2206
2244
  const outputMessage = {
2207
2245
  role: "assistant",
@@ -2295,7 +2333,7 @@ var anthropicTokenizer = (message) => {
2295
2333
 
2296
2334
  // src/lib/anthropic/Anthropic.tsx
2297
2335
  var defaultClient2 = null;
2298
- var AnthropicClientContext = createContext(() => {
2336
+ var AnthropicClientContext = createContext(async () => {
2299
2337
  if (defaultClient2) {
2300
2338
  return defaultClient2;
2301
2339
  }
@@ -2374,7 +2412,7 @@ var shouldRetry2 = (error) => {
2374
2412
  var shouldRetryFromStatus = (status) => Boolean(status && [424, 429, 500].includes(status));
2375
2413
  var RE_INTERNAL_SERVER_MESSASGE = /The system encountered an unexpected error during processing/i;
2376
2414
  var RE_RATE_LIMIT_MESSAGE = /Too many requests, please wait before trying again/;
2377
- var extractStatusFromError = (error) => {
2415
+ var extractStatusFromError2 = (error) => {
2378
2416
  if (typeof error !== "object" || !(error instanceof Error)) {
2379
2417
  return;
2380
2418
  }
@@ -2413,11 +2451,16 @@ function AnthropicChatCompletion(props, ctx) {
2413
2451
  async function* AnthropicChatCompletionInner(props, ctx) {
2414
2452
  const startTime = performance.now();
2415
2453
  const { logger, tracer, getContext } = ctx;
2416
- const retryCount = getContext(RetryCountContext);
2454
+ const { retryCount, lastError } = getContext(RetryCountContext);
2417
2455
  const span = tracer.getActiveSpan();
2418
- const { client, provider, providerRegion, costFn } = getContext(
2419
- AnthropicClientContext
2420
- )();
2456
+ const getClientFn = getContext(AnthropicClientContext);
2457
+ const { client, provider, providerRegion, costFn } = await getClientFn(
2458
+ props.model,
2459
+ {
2460
+ retryCount,
2461
+ lastError
2462
+ }
2463
+ );
2421
2464
  if (!client) {
2422
2465
  throw new Error(
2423
2466
  "[AnthropicChatCompletion] must supply AnthropicClient via context"
@@ -2468,7 +2511,7 @@ async function* AnthropicChatCompletionInner(props, ctx) {
2468
2511
  response = client.messages.stream(anthropicCompletionRequest);
2469
2512
  } catch (err) {
2470
2513
  if (err instanceof import_sdk.default.APIError) {
2471
- const status = extractStatusFromError(err);
2514
+ const status = extractStatusFromError2(err);
2472
2515
  const retry = shouldRetryFromStatus(status);
2473
2516
  throw new ChatCompletionError(
2474
2517
  `AnthropicClient.APIError: ${err.message}`,
@@ -2477,7 +2520,7 @@ async function* AnthropicChatCompletionInner(props, ctx) {
2477
2520
  retry
2478
2521
  );
2479
2522
  } else if (err instanceof Error) {
2480
- const status = extractStatusFromError(err);
2523
+ const status = extractStatusFromError2(err);
2481
2524
  const retry = shouldRetryFromStatus(status);
2482
2525
  throw new ChatCompletionError(err.message, logRequestData, status, retry);
2483
2526
  }
@@ -2500,10 +2543,16 @@ async function* AnthropicChatCompletionInner(props, ctx) {
2500
2543
  if (event.type === "message_delta") {
2501
2544
  finishReason = event.delta.stop_reason;
2502
2545
  outputUsage = event.usage?.output_tokens;
2546
+ span.setAttributes({
2547
+ finishReason
2548
+ });
2503
2549
  }
2504
2550
  }
2505
2551
  } catch (e) {
2506
- const status = extractStatusFromError(e);
2552
+ span.setAttributes({
2553
+ output: content
2554
+ });
2555
+ const status = extractStatusFromError2(e);
2507
2556
  const retry = shouldRetryFromStatus(status);
2508
2557
  throw new ChatCompletionError(e.message, logRequestData, status, retry);
2509
2558
  }
@@ -2590,14 +2639,15 @@ var extractStatusFromMessage = (message) => {
2590
2639
  }
2591
2640
  return 500;
2592
2641
  };
2593
- var errorToChatCompletionError = (error, requestData) => {
2642
+ var errorToChatCompletionError2 = (error, requestData) => {
2594
2643
  const status = extractStatusFromMessage(error.message);
2595
2644
  const shouldRetry4 = status !== 400;
2596
2645
  return new ChatCompletionError(
2597
2646
  error.message,
2598
2647
  requestData,
2599
2648
  status,
2600
- shouldRetry4
2649
+ shouldRetry4,
2650
+ error
2601
2651
  );
2602
2652
  };
2603
2653
 
@@ -2624,7 +2674,7 @@ var DEFAULT_SAFETY_SETTINGS = [
2624
2674
  threshold: import_vertexai.HarmBlockThreshold.BLOCK_ONLY_HIGH
2625
2675
  }
2626
2676
  ];
2627
- var GoogleClientContext = createContext(() => {
2677
+ var GoogleClientContext = createContext(async () => {
2628
2678
  if (defaultClient3) {
2629
2679
  return defaultClient3;
2630
2680
  }
@@ -2705,9 +2755,16 @@ function GoogleChatCompletion(props, ctx) {
2705
2755
  async function* GoogleChatCompletionInner(props, ctx) {
2706
2756
  const startTime = performance.now();
2707
2757
  const { logger, tracer, getContext } = ctx;
2708
- const retryCount = getContext(RetryCountContext);
2758
+ const { retryCount, lastError } = getContext(RetryCountContext);
2709
2759
  const span = tracer.getActiveSpan();
2710
- const { client, provider, providerRegion, costFn } = getContext(GoogleClientContext)();
2760
+ const getClientFn = getContext(GoogleClientContext);
2761
+ const { client, provider, providerRegion, costFn } = await getClientFn(
2762
+ props.model,
2763
+ {
2764
+ retryCount,
2765
+ lastError
2766
+ }
2767
+ );
2711
2768
  if (!client) {
2712
2769
  throw new Error(
2713
2770
  "[GoogleChatCompletion] must supply GoogleClient via context"
@@ -2762,7 +2819,7 @@ async function* GoogleChatCompletionInner(props, ctx) {
2762
2819
  try {
2763
2820
  response = await model.generateContentStream(googleCompletionRequest);
2764
2821
  } catch (err) {
2765
- throw errorToChatCompletionError(err, logRequestData);
2822
+ throw errorToChatCompletionError2(err, logRequestData);
2766
2823
  }
2767
2824
  let content = "";
2768
2825
  let outputUsage = 0;
@@ -2773,6 +2830,9 @@ async function* GoogleChatCompletionInner(props, ctx) {
2773
2830
  if (event.candidates) {
2774
2831
  if (event.candidates[0]?.finishReason) {
2775
2832
  finishReason = event.candidates[0].finishReason;
2833
+ span.setAttributes({
2834
+ finishReason
2835
+ });
2776
2836
  }
2777
2837
  if (event.usageMetadata) {
2778
2838
  if (event.usageMetadata.promptTokenCount) {
@@ -2808,7 +2868,10 @@ async function* GoogleChatCompletionInner(props, ctx) {
2808
2868
  }
2809
2869
  }
2810
2870
  } catch (err) {
2811
- throw errorToChatCompletionError(err, logRequestData);
2871
+ span.setAttributes({
2872
+ output: content
2873
+ });
2874
+ throw errorToChatCompletionError2(err, logRequestData);
2812
2875
  }
2813
2876
  const outputMessage = {
2814
2877
  role: "assistant",
@@ -2832,8 +2895,7 @@ async function* GoogleChatCompletionInner(props, ctx) {
2832
2895
  span.setAttributes({
2833
2896
  tokensUsed,
2834
2897
  output: content,
2835
- cost,
2836
- finishReason
2898
+ cost
2837
2899
  });
2838
2900
  }
2839
2901
  function cleanChatCompletionRequest3(chatCompletionRequest) {
@@ -2896,6 +2958,7 @@ var import_vertexai2 = require("@google-cloud/vertexai");
2896
2958
  PromptInvalidOutputError,
2897
2959
  Retry,
2898
2960
  RetryCountContext,
2961
+ RetryLastErrorContext,
2899
2962
  SystemMessage,
2900
2963
  Trace,
2901
2964
  UserMessage,
package/dist/index.mjs CHANGED
@@ -8,11 +8,12 @@ import {
8
8
 
9
9
  // src/chat/errors.ts
10
10
  var ChatCompletionError = class extends Error {
11
- constructor(message, chatCompletionRequest, status, shouldRetry4 = false) {
11
+ constructor(message, chatCompletionRequest, status, shouldRetry4 = false, originalError) {
12
12
  super(message);
13
13
  this.chatCompletionRequest = chatCompletionRequest;
14
14
  this.status = status;
15
15
  this.shouldRetry = shouldRetry4;
16
+ this.originalError = originalError;
16
17
  }
17
18
  name = "ChatCompletionError";
18
19
  };
@@ -1435,27 +1436,67 @@ function renderCloseTag(element) {
1435
1436
  return `</${element.tag.name}>`;
1436
1437
  }
1437
1438
 
1439
+ // src/utils.ts
1440
+ function getEnvVar(name, shouldThrow = true) {
1441
+ let env = globalThis.process?.env ?? void 0;
1442
+ if (env === void 0) {
1443
+ try {
1444
+ env = process.env;
1445
+ } catch {
1446
+ }
1447
+ }
1448
+ const result = env?.[name];
1449
+ if (result === void 0 && shouldThrow) {
1450
+ throw new Error(`Please specify env var '${name}'`);
1451
+ }
1452
+ return result;
1453
+ }
1454
+ var castToError = (e) => {
1455
+ if (e instanceof Error) {
1456
+ return e;
1457
+ }
1458
+ if (typeof e === "string") {
1459
+ return new Error(e);
1460
+ }
1461
+ return new Error("Unknown error");
1462
+ };
1463
+
1438
1464
  // src/retry.tsx
1439
- var RetryCountContext = createContext(0);
1465
+ var RetryCountContext = createContext({
1466
+ retryCount: 0,
1467
+ lastError: null
1468
+ });
1469
+ var RetryLastErrorContext = createContext(null);
1440
1470
  var DefaultMaxRetriesContext = createContext(0);
1441
- async function* Retry({ shouldRetry: shouldRetry4, retries = 0, maxRetries = 3, children }, ctx) {
1471
+ async function* Retry({ shouldRetry: shouldRetry4, retries = 0, maxRetries = 3, lastError, children }, ctx) {
1442
1472
  const { render } = ctx;
1443
1473
  let hasYieldedData = false;
1444
1474
  try {
1475
+ const ctxValue = retries === 0 ? { retryCount: 0, lastError: null } : {
1476
+ retryCount: retries,
1477
+ lastError
1478
+ };
1445
1479
  const result = render(
1446
- /* @__PURE__ */ jsx(RetryCountContext.Provider, { value: retries, children })
1480
+ /* @__PURE__ */ jsx(RetryCountContext.Provider, { value: ctxValue, children })
1447
1481
  );
1448
1482
  for await (const value of result) {
1449
1483
  hasYieldedData = true;
1450
1484
  yield value;
1451
1485
  }
1452
1486
  } catch (e) {
1453
- if (hasYieldedData || retries >= maxRetries || !shouldRetry4(e)) {
1487
+ const err = castToError(e);
1488
+ if (hasYieldedData || retries >= maxRetries || !shouldRetry4(err)) {
1454
1489
  throw e;
1455
1490
  }
1456
1491
  await backoff(retries);
1457
1492
  yield* Retry(
1458
- { shouldRetry: shouldRetry4, retries: retries + 1, maxRetries, children },
1493
+ {
1494
+ shouldRetry: shouldRetry4,
1495
+ retries: retries + 1,
1496
+ maxRetries,
1497
+ lastError: err,
1498
+ children
1499
+ },
1459
1500
  ctx
1460
1501
  );
1461
1502
  }
@@ -1801,25 +1842,6 @@ function isPromptParsed2(prompt) {
1801
1842
  // src/lib/openai/OpenAI.tsx
1802
1843
  import { OpenAI as OpenAIClient2 } from "openai";
1803
1844
 
1804
- // src/lib/openai/shouldRetryOpenAI.ts
1805
- import { OpenAI as OpenAIClient } from "openai";
1806
- var shouldRetryOpenAI = (error) => {
1807
- if (error instanceof OpenAIClient.APIConnectionError) {
1808
- return true;
1809
- }
1810
- if (error instanceof OpenAIClient.APIError) {
1811
- if ("status" in error && typeof error.status === "number") {
1812
- if (error.status === 409)
1813
- return true;
1814
- if (error.status === 429)
1815
- return true;
1816
- if (error.status >= 500)
1817
- return true;
1818
- }
1819
- }
1820
- return false;
1821
- };
1822
-
1823
1845
  // src/lib/openai/tokenizer.ts
1824
1846
  import { getEncoding } from "js-tiktoken";
1825
1847
  var cl100kTokenizer = getEncoding("cl100k_base");
@@ -1931,25 +1953,39 @@ async function buildChatMessages(ctx, children, opts) {
1931
1953
  });
1932
1954
  }
1933
1955
 
1934
- // src/utils.ts
1935
- function getEnvVar(name, shouldThrow = true) {
1936
- let env = globalThis.process?.env ?? void 0;
1937
- if (env === void 0) {
1938
- try {
1939
- env = process.env;
1940
- } catch {
1941
- }
1956
+ // src/lib/openai/errors.ts
1957
+ import { OpenAI as OpenAIClient } from "openai";
1958
+ var extractStatusFromError = (error) => {
1959
+ if (error instanceof OpenAIClient.APIError) {
1960
+ return error.status;
1961
+ } else if (error instanceof OpenAIClient.APIConnectionError) {
1962
+ return void 0;
1963
+ } else {
1964
+ return void 0;
1942
1965
  }
1943
- const result = env?.[name];
1944
- if (result === void 0 && shouldThrow) {
1945
- throw new Error(`Please specify env var '${name}'`);
1966
+ };
1967
+ var errorToChatCompletionError = (error, requestData) => {
1968
+ const castError = castToError(error);
1969
+ const status = extractStatusFromError(castError);
1970
+ let messagePrefix = "";
1971
+ if (error instanceof OpenAIClient.APIError) {
1972
+ messagePrefix = "OpenAIClient.APIError: ";
1973
+ } else if (error instanceof OpenAIClient.APIConnectionError) {
1974
+ messagePrefix = "OpenAIClient.APIConnectionError: ";
1946
1975
  }
1947
- return result;
1948
- }
1976
+ const shouldRetry4 = status !== 400;
1977
+ return new ChatCompletionError(
1978
+ `${messagePrefix}${castError.message}`,
1979
+ requestData,
1980
+ status,
1981
+ shouldRetry4,
1982
+ error instanceof Error ? error : void 0
1983
+ );
1984
+ };
1949
1985
 
1950
1986
  // src/lib/openai/OpenAI.tsx
1951
1987
  var defaultClient = null;
1952
- var OpenAIClientContext = createContext(() => {
1988
+ var OpenAIClientContext = createContext(async () => {
1953
1989
  if (defaultClient) {
1954
1990
  return defaultClient;
1955
1991
  }
@@ -2021,9 +2057,16 @@ function OpenAIChatCompletion(props, ctx) {
2021
2057
  async function* OpenAIChatCompletionInner(props, ctx) {
2022
2058
  const startTime = performance.now();
2023
2059
  const { logger, tracer, getContext } = ctx;
2024
- const retryCount = getContext(RetryCountContext);
2060
+ const { retryCount, lastError } = getContext(RetryCountContext);
2025
2061
  const span = tracer.getActiveSpan();
2026
- const { client, provider, providerRegion, costFn } = getContext(OpenAIClientContext)();
2062
+ const getClientFn = getContext(OpenAIClientContext);
2063
+ const { client, provider, providerRegion, costFn } = await getClientFn(
2064
+ props.model,
2065
+ {
2066
+ retryCount,
2067
+ lastError
2068
+ }
2069
+ );
2027
2070
  if (!client) {
2028
2071
  throw new Error("[OpenAI] must supply OpenAI model via context");
2029
2072
  }
@@ -2068,38 +2111,32 @@ async function* OpenAIChatCompletionInner(props, ctx) {
2068
2111
  try {
2069
2112
  chatResponse = await client.chat.completions.create(chatCompletionRequest);
2070
2113
  } catch (ex) {
2071
- const retry = shouldRetryOpenAI(ex);
2072
- if (ex instanceof OpenAIClient2.APIError) {
2073
- throw new ChatCompletionError(
2074
- `OpenAIClient.APIError: ${ex.message}`,
2075
- logRequestData,
2076
- ex.status,
2077
- retry
2078
- );
2079
- } else if (ex instanceof Error) {
2080
- throw new ChatCompletionError(
2081
- ex.message,
2082
- logRequestData,
2083
- void 0,
2084
- retry
2085
- );
2086
- }
2087
- throw ex;
2114
+ throw errorToChatCompletionError(ex, logRequestData);
2088
2115
  }
2089
2116
  let finishReason = void 0;
2090
2117
  let content = "";
2091
- for await (const message of chatResponse) {
2092
- if (!message.choices || !message.choices[0]) {
2093
- continue;
2094
- }
2095
- const delta = message.choices[0].delta;
2096
- if (message.choices[0].finish_reason) {
2097
- finishReason = message.choices[0].finish_reason;
2098
- }
2099
- if (delta.content) {
2100
- content += delta.content;
2101
- yield delta.content;
2118
+ try {
2119
+ for await (const message of chatResponse) {
2120
+ if (!message.choices || !message.choices[0]) {
2121
+ continue;
2122
+ }
2123
+ const delta = message.choices[0].delta;
2124
+ if (message.choices[0].finish_reason) {
2125
+ finishReason = message.choices[0].finish_reason;
2126
+ span.setAttributes({
2127
+ finishReason
2128
+ });
2129
+ }
2130
+ if (delta.content) {
2131
+ content += delta.content;
2132
+ yield delta.content;
2133
+ }
2102
2134
  }
2135
+ } catch (e) {
2136
+ span.setAttributes({
2137
+ output: content
2138
+ });
2139
+ throw errorToChatCompletionError(e, logRequestData);
2103
2140
  }
2104
2141
  const outputMessage = {
2105
2142
  role: "assistant",
@@ -2193,7 +2230,7 @@ var anthropicTokenizer = (message) => {
2193
2230
 
2194
2231
  // src/lib/anthropic/Anthropic.tsx
2195
2232
  var defaultClient2 = null;
2196
- var AnthropicClientContext = createContext(() => {
2233
+ var AnthropicClientContext = createContext(async () => {
2197
2234
  if (defaultClient2) {
2198
2235
  return defaultClient2;
2199
2236
  }
@@ -2272,7 +2309,7 @@ var shouldRetry2 = (error) => {
2272
2309
  var shouldRetryFromStatus = (status) => Boolean(status && [424, 429, 500].includes(status));
2273
2310
  var RE_INTERNAL_SERVER_MESSASGE = /The system encountered an unexpected error during processing/i;
2274
2311
  var RE_RATE_LIMIT_MESSAGE = /Too many requests, please wait before trying again/;
2275
- var extractStatusFromError = (error) => {
2312
+ var extractStatusFromError2 = (error) => {
2276
2313
  if (typeof error !== "object" || !(error instanceof Error)) {
2277
2314
  return;
2278
2315
  }
@@ -2311,11 +2348,16 @@ function AnthropicChatCompletion(props, ctx) {
2311
2348
  async function* AnthropicChatCompletionInner(props, ctx) {
2312
2349
  const startTime = performance.now();
2313
2350
  const { logger, tracer, getContext } = ctx;
2314
- const retryCount = getContext(RetryCountContext);
2351
+ const { retryCount, lastError } = getContext(RetryCountContext);
2315
2352
  const span = tracer.getActiveSpan();
2316
- const { client, provider, providerRegion, costFn } = getContext(
2317
- AnthropicClientContext
2318
- )();
2353
+ const getClientFn = getContext(AnthropicClientContext);
2354
+ const { client, provider, providerRegion, costFn } = await getClientFn(
2355
+ props.model,
2356
+ {
2357
+ retryCount,
2358
+ lastError
2359
+ }
2360
+ );
2319
2361
  if (!client) {
2320
2362
  throw new Error(
2321
2363
  "[AnthropicChatCompletion] must supply AnthropicClient via context"
@@ -2366,7 +2408,7 @@ async function* AnthropicChatCompletionInner(props, ctx) {
2366
2408
  response = client.messages.stream(anthropicCompletionRequest);
2367
2409
  } catch (err) {
2368
2410
  if (err instanceof AnthropicClient.APIError) {
2369
- const status = extractStatusFromError(err);
2411
+ const status = extractStatusFromError2(err);
2370
2412
  const retry = shouldRetryFromStatus(status);
2371
2413
  throw new ChatCompletionError(
2372
2414
  `AnthropicClient.APIError: ${err.message}`,
@@ -2375,7 +2417,7 @@ async function* AnthropicChatCompletionInner(props, ctx) {
2375
2417
  retry
2376
2418
  );
2377
2419
  } else if (err instanceof Error) {
2378
- const status = extractStatusFromError(err);
2420
+ const status = extractStatusFromError2(err);
2379
2421
  const retry = shouldRetryFromStatus(status);
2380
2422
  throw new ChatCompletionError(err.message, logRequestData, status, retry);
2381
2423
  }
@@ -2398,10 +2440,16 @@ async function* AnthropicChatCompletionInner(props, ctx) {
2398
2440
  if (event.type === "message_delta") {
2399
2441
  finishReason = event.delta.stop_reason;
2400
2442
  outputUsage = event.usage?.output_tokens;
2443
+ span.setAttributes({
2444
+ finishReason
2445
+ });
2401
2446
  }
2402
2447
  }
2403
2448
  } catch (e) {
2404
- const status = extractStatusFromError(e);
2449
+ span.setAttributes({
2450
+ output: content
2451
+ });
2452
+ const status = extractStatusFromError2(e);
2405
2453
  const retry = shouldRetryFromStatus(status);
2406
2454
  throw new ChatCompletionError(e.message, logRequestData, status, retry);
2407
2455
  }
@@ -2492,14 +2540,15 @@ var extractStatusFromMessage = (message) => {
2492
2540
  }
2493
2541
  return 500;
2494
2542
  };
2495
- var errorToChatCompletionError = (error, requestData) => {
2543
+ var errorToChatCompletionError2 = (error, requestData) => {
2496
2544
  const status = extractStatusFromMessage(error.message);
2497
2545
  const shouldRetry4 = status !== 400;
2498
2546
  return new ChatCompletionError(
2499
2547
  error.message,
2500
2548
  requestData,
2501
2549
  status,
2502
- shouldRetry4
2550
+ shouldRetry4,
2551
+ error
2503
2552
  );
2504
2553
  };
2505
2554
 
@@ -2526,7 +2575,7 @@ var DEFAULT_SAFETY_SETTINGS = [
2526
2575
  threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH
2527
2576
  }
2528
2577
  ];
2529
- var GoogleClientContext = createContext(() => {
2578
+ var GoogleClientContext = createContext(async () => {
2530
2579
  if (defaultClient3) {
2531
2580
  return defaultClient3;
2532
2581
  }
@@ -2607,9 +2656,16 @@ function GoogleChatCompletion(props, ctx) {
2607
2656
  async function* GoogleChatCompletionInner(props, ctx) {
2608
2657
  const startTime = performance.now();
2609
2658
  const { logger, tracer, getContext } = ctx;
2610
- const retryCount = getContext(RetryCountContext);
2659
+ const { retryCount, lastError } = getContext(RetryCountContext);
2611
2660
  const span = tracer.getActiveSpan();
2612
- const { client, provider, providerRegion, costFn } = getContext(GoogleClientContext)();
2661
+ const getClientFn = getContext(GoogleClientContext);
2662
+ const { client, provider, providerRegion, costFn } = await getClientFn(
2663
+ props.model,
2664
+ {
2665
+ retryCount,
2666
+ lastError
2667
+ }
2668
+ );
2613
2669
  if (!client) {
2614
2670
  throw new Error(
2615
2671
  "[GoogleChatCompletion] must supply GoogleClient via context"
@@ -2664,7 +2720,7 @@ async function* GoogleChatCompletionInner(props, ctx) {
2664
2720
  try {
2665
2721
  response = await model.generateContentStream(googleCompletionRequest);
2666
2722
  } catch (err) {
2667
- throw errorToChatCompletionError(err, logRequestData);
2723
+ throw errorToChatCompletionError2(err, logRequestData);
2668
2724
  }
2669
2725
  let content = "";
2670
2726
  let outputUsage = 0;
@@ -2675,6 +2731,9 @@ async function* GoogleChatCompletionInner(props, ctx) {
2675
2731
  if (event.candidates) {
2676
2732
  if (event.candidates[0]?.finishReason) {
2677
2733
  finishReason = event.candidates[0].finishReason;
2734
+ span.setAttributes({
2735
+ finishReason
2736
+ });
2678
2737
  }
2679
2738
  if (event.usageMetadata) {
2680
2739
  if (event.usageMetadata.promptTokenCount) {
@@ -2710,7 +2769,10 @@ async function* GoogleChatCompletionInner(props, ctx) {
2710
2769
  }
2711
2770
  }
2712
2771
  } catch (err) {
2713
- throw errorToChatCompletionError(err, logRequestData);
2772
+ span.setAttributes({
2773
+ output: content
2774
+ });
2775
+ throw errorToChatCompletionError2(err, logRequestData);
2714
2776
  }
2715
2777
  const outputMessage = {
2716
2778
  role: "assistant",
@@ -2734,8 +2796,7 @@ async function* GoogleChatCompletionInner(props, ctx) {
2734
2796
  span.setAttributes({
2735
2797
  tokensUsed,
2736
2798
  output: content,
2737
- cost,
2738
- finishReason
2799
+ cost
2739
2800
  });
2740
2801
  }
2741
2802
  function cleanChatCompletionRequest3(chatCompletionRequest) {
@@ -2801,6 +2862,7 @@ export {
2801
2862
  PromptInvalidOutputError,
2802
2863
  Retry,
2803
2864
  RetryCountContext,
2865
+ RetryLastErrorContext,
2804
2866
  SystemMessage,
2805
2867
  Trace,
2806
2868
  UserMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gammatech/aijsx",
3
- "version": "0.10.2-dev.2024-06-11",
3
+ "version": "0.11.1-dev.2024-06-23",
4
4
  "description": "Rewrite of aijsx",
5
5
  "author": "Jordan Garcia",
6
6
  "license": "MIT",