@jaypie/llm 1.2.5 → 1.2.6

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.
@@ -1,6 +1,6 @@
1
1
  export { default as Llm } from "./Llm.js";
2
2
  export * as LLM from "./constants.js";
3
- export type { LlmHistory, LlmInputContent, LlmInputContentFile, LlmInputContentImage, LlmInputContentText, LlmInputMessage, LlmMessageOptions, LlmOperateInput, LlmOperateInputContent, LlmOperateInputFile, LlmOperateInputImage, LlmOperateOptions, LlmOperateResponse, LlmOptions, LlmProvider, } from "./types/LlmProvider.interface.js";
3
+ export type { LlmFallbackConfig, LlmHistory, LlmInputContent, LlmInputContentFile, LlmInputContentImage, LlmInputContentText, LlmInputMessage, LlmMessageOptions, LlmOperateInput, LlmOperateInputContent, LlmOperateInputFile, LlmOperateInputImage, LlmOperateOptions, LlmOperateResponse, LlmOptions, LlmProvider, } from "./types/LlmProvider.interface.js";
4
4
  export { LlmMessageRole, LlmMessageType, } from "./types/LlmProvider.interface.js";
5
5
  export { isLlmOperateInput, isLlmOperateInputContent, isLlmOperateInputFile, isLlmOperateInputImage, } from "./types/LlmOperateInput.guards.js";
6
6
  export type { LlmTool } from "./types/LlmTool.interface.js";
@@ -144,6 +144,18 @@ interface LlmItemReference {
144
144
  }
145
145
  export type LlmHistoryItem = LlmInputMessage | LlmItemReference | LlmOutputItem | LlmToolResult;
146
146
  export type LlmHistory = LlmHistoryItem[];
147
+ /**
148
+ * Configuration for a fallback provider.
149
+ * Used when the primary provider fails with an unrecoverable error.
150
+ */
151
+ export interface LlmFallbackConfig {
152
+ /** Provider name (e.g., "openai", "anthropic", "gemini") */
153
+ provider: string;
154
+ /** Model to use with this provider (optional, uses provider default if not specified) */
155
+ model?: string;
156
+ /** API key for this provider (optional, uses environment variable if not specified) */
157
+ apiKey?: string;
158
+ }
147
159
  export interface LlmMessageOptions {
148
160
  data?: NaturalMap;
149
161
  model?: string;
@@ -157,6 +169,8 @@ export interface LlmMessageOptions {
157
169
  export interface LlmOperateOptions {
158
170
  data?: NaturalMap;
159
171
  explain?: boolean;
172
+ /** Chain of fallback providers to try if primary fails. Set to false to disable instance-level fallback. */
173
+ fallback?: LlmFallbackConfig[] | false;
160
174
  format?: JsonObject | NaturalSchema | z.ZodType;
161
175
  history?: LlmHistory;
162
176
  hooks?: {
@@ -215,6 +229,8 @@ export interface LlmOperateOptions {
215
229
  }
216
230
  export interface LlmOptions {
217
231
  apiKey?: string;
232
+ /** Chain of fallback providers to try if primary fails */
233
+ fallback?: LlmFallbackConfig[];
218
234
  model?: string;
219
235
  }
220
236
  export interface LlmUsageItem {
@@ -229,9 +245,14 @@ export type LlmUsage = LlmUsageItem[];
229
245
  export interface LlmOperateResponse {
230
246
  content?: string | JsonObject;
231
247
  error?: LlmError;
248
+ /** Number of providers attempted (1 = primary only, >1 = fallback(s) used) */
249
+ fallbackAttempts?: number;
250
+ /** Whether a fallback provider was used instead of the primary */
251
+ fallbackUsed?: boolean;
232
252
  history: LlmHistory;
233
253
  model?: string;
234
254
  output: LlmOutput;
255
+ /** Which provider actually handled the request */
235
256
  provider?: string;
236
257
  reasoning: string[];
237
258
  responses: JsonReturn[];
package/dist/esm/Llm.d.ts CHANGED
@@ -1,14 +1,25 @@
1
1
  import { JsonObject } from "@jaypie/types";
2
2
  import { LlmProviderName } from "./constants.js";
3
- import { LlmHistory, LlmInputMessage, LlmMessageOptions, LlmOperateInput, LlmOperateOptions, LlmOperateResponse, LlmOptions, LlmProvider } from "./types/LlmProvider.interface.js";
3
+ import { LlmFallbackConfig, LlmHistory, LlmInputMessage, LlmMessageOptions, LlmOperateInput, LlmOperateOptions, LlmOperateResponse, LlmOptions, LlmProvider } from "./types/LlmProvider.interface.js";
4
4
  import { LlmStreamChunk } from "./types/LlmStreamChunk.interface.js";
5
5
  declare class Llm implements LlmProvider {
6
- private _provider;
6
+ private _fallbackConfig?;
7
7
  private _llm;
8
8
  private _options;
9
+ private _provider;
9
10
  constructor(providerName?: LlmProviderName | string, options?: LlmOptions);
10
11
  private createProvider;
11
12
  send(message: string, options?: LlmMessageOptions): Promise<string | JsonObject>;
13
+ /**
14
+ * Resolves the fallback chain from instance config and per-call options.
15
+ * Per-call options take precedence over instance config.
16
+ * Returns empty array if fallback is disabled.
17
+ */
18
+ private resolveFallbackChain;
19
+ /**
20
+ * Creates a fallback Llm instance lazily when needed.
21
+ */
22
+ private createFallbackInstance;
12
23
  operate(input: string | LlmHistory | LlmInputMessage | LlmOperateInput, options?: LlmOperateOptions): Promise<LlmOperateResponse>;
13
24
  stream(input: string | LlmHistory | LlmInputMessage | LlmOperateInput, options?: LlmOperateOptions): AsyncIterable<LlmStreamChunk>;
14
25
  static send(message: string, options?: LlmMessageOptions & {
@@ -17,8 +28,9 @@ declare class Llm implements LlmProvider {
17
28
  model?: string;
18
29
  }): Promise<string | JsonObject>;
19
30
  static operate(input: string | LlmHistory | LlmInputMessage | LlmOperateInput, options?: LlmOperateOptions & {
20
- llm?: LlmProviderName;
21
31
  apiKey?: string;
32
+ fallback?: LlmFallbackConfig[] | false;
33
+ llm?: LlmProviderName;
22
34
  model?: string;
23
35
  }): Promise<LlmOperateResponse>;
24
36
  static stream(input: string | LlmHistory | LlmInputMessage | LlmOperateInput, options?: LlmOperateOptions & {
@@ -1,6 +1,6 @@
1
1
  export { default as Llm } from "./Llm.js";
2
2
  export * as LLM from "./constants.js";
3
- export type { LlmHistory, LlmInputContent, LlmInputContentFile, LlmInputContentImage, LlmInputContentText, LlmInputMessage, LlmMessageOptions, LlmOperateInput, LlmOperateInputContent, LlmOperateInputFile, LlmOperateInputImage, LlmOperateOptions, LlmOperateResponse, LlmOptions, LlmProvider, } from "./types/LlmProvider.interface.js";
3
+ export type { LlmFallbackConfig, LlmHistory, LlmInputContent, LlmInputContentFile, LlmInputContentImage, LlmInputContentText, LlmInputMessage, LlmMessageOptions, LlmOperateInput, LlmOperateInputContent, LlmOperateInputFile, LlmOperateInputImage, LlmOperateOptions, LlmOperateResponse, LlmOptions, LlmProvider, } from "./types/LlmProvider.interface.js";
4
4
  export { LlmMessageRole, LlmMessageType, } from "./types/LlmProvider.interface.js";
5
5
  export { isLlmOperateInput, isLlmOperateInputContent, isLlmOperateInputFile, isLlmOperateInputImage, } from "./types/LlmOperateInput.guards.js";
6
6
  export type { LlmTool } from "./types/LlmTool.interface.js";
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ConfigurationError, BadGatewayError, TooManyRequestsError, NotImplementedError } from '@jaypie/errors';
2
+ import log$3, { log as log$2 } from '@jaypie/logger';
2
3
  import { z } from 'zod/v4';
3
4
  import { placeholders, JAYPIE, resolveValue, sleep } from '@jaypie/kit';
4
- import { log as log$2 } from '@jaypie/logger';
5
5
  import RandomLib from 'random';
6
6
  import { RateLimitError, APIConnectionError, APIConnectionTimeoutError, InternalServerError, APIUserAbortError, AuthenticationError, BadRequestError, ConflictError, NotFoundError, PermissionDeniedError, UnprocessableEntityError, OpenAI } from 'openai';
7
7
  import { zodResponseFormat } from 'openai/helpers/zod';
@@ -5183,7 +5183,7 @@ class OpenRouterProvider {
5183
5183
 
5184
5184
  class Llm {
5185
5185
  constructor(providerName = DEFAULT.PROVIDER.NAME, options = {}) {
5186
- const { model } = options;
5186
+ const { fallback, model } = options;
5187
5187
  let finalProvider = providerName;
5188
5188
  let finalModel = model;
5189
5189
  if (model) {
@@ -5212,6 +5212,7 @@ class Llm {
5212
5212
  finalModel = undefined;
5213
5213
  }
5214
5214
  }
5215
+ this._fallbackConfig = fallback;
5215
5216
  this._provider = finalProvider;
5216
5217
  this._options = { ...options, model: finalModel };
5217
5218
  this._llm = this.createProvider(finalProvider, this._options);
@@ -5240,11 +5241,81 @@ class Llm {
5240
5241
  async send(message, options) {
5241
5242
  return this._llm.send(message, options);
5242
5243
  }
5244
+ /**
5245
+ * Resolves the fallback chain from instance config and per-call options.
5246
+ * Per-call options take precedence over instance config.
5247
+ * Returns empty array if fallback is disabled.
5248
+ */
5249
+ resolveFallbackChain(options) {
5250
+ // Per-call `fallback: false` disables fallback entirely
5251
+ if (options.fallback === false) {
5252
+ return [];
5253
+ }
5254
+ // Per-call fallback array overrides instance config
5255
+ if (Array.isArray(options.fallback)) {
5256
+ return options.fallback;
5257
+ }
5258
+ // Use instance config if available
5259
+ return this._fallbackConfig || [];
5260
+ }
5261
+ /**
5262
+ * Creates a fallback Llm instance lazily when needed.
5263
+ */
5264
+ createFallbackInstance(config) {
5265
+ return new Llm(config.provider, {
5266
+ apiKey: config.apiKey,
5267
+ model: config.model,
5268
+ });
5269
+ }
5243
5270
  async operate(input, options = {}) {
5244
5271
  if (!this._llm.operate) {
5245
5272
  throw new NotImplementedError(`Provider ${this._provider} does not support operate method`);
5246
5273
  }
5247
- return this._llm.operate(input, options);
5274
+ const fallbackChain = this.resolveFallbackChain(options);
5275
+ const optionsWithoutFallback = { ...options, fallback: false };
5276
+ let lastError;
5277
+ let attempts = 0;
5278
+ // Try primary provider first
5279
+ attempts++;
5280
+ try {
5281
+ const response = await this._llm.operate(input, optionsWithoutFallback);
5282
+ return {
5283
+ ...response,
5284
+ fallbackAttempts: attempts,
5285
+ fallbackUsed: false,
5286
+ provider: response.provider || this._provider,
5287
+ };
5288
+ }
5289
+ catch (error) {
5290
+ lastError = error;
5291
+ log$3.warn(`Provider ${this._provider} failed`, {
5292
+ error: lastError.message,
5293
+ fallbacksRemaining: fallbackChain.length,
5294
+ });
5295
+ }
5296
+ // Try fallback providers
5297
+ for (const fallbackConfig of fallbackChain) {
5298
+ attempts++;
5299
+ try {
5300
+ const fallbackInstance = this.createFallbackInstance(fallbackConfig);
5301
+ const response = await fallbackInstance.operate(input, optionsWithoutFallback);
5302
+ return {
5303
+ ...response,
5304
+ fallbackAttempts: attempts,
5305
+ fallbackUsed: true,
5306
+ provider: response.provider || fallbackConfig.provider,
5307
+ };
5308
+ }
5309
+ catch (error) {
5310
+ lastError = error;
5311
+ log$3.warn(`Fallback provider ${fallbackConfig.provider} failed`, {
5312
+ error: lastError.message,
5313
+ fallbacksRemaining: fallbackChain.length - attempts + 1,
5314
+ });
5315
+ }
5316
+ }
5317
+ // All providers failed, throw the last error
5318
+ throw lastError;
5248
5319
  }
5249
5320
  async *stream(input, options = {}) {
5250
5321
  if (!this._llm.stream) {
@@ -5258,7 +5329,7 @@ class Llm {
5258
5329
  return instance.send(message, messageOptions);
5259
5330
  }
5260
5331
  static async operate(input, options) {
5261
- const { llm, apiKey, model, ...operateOptions } = options || {};
5332
+ const { apiKey, fallback, llm, model, ...operateOptions } = options || {};
5262
5333
  let finalLlm = llm;
5263
5334
  let finalModel = model;
5264
5335
  if (!llm && model) {
@@ -5275,8 +5346,18 @@ class Llm {
5275
5346
  finalModel = undefined;
5276
5347
  }
5277
5348
  }
5278
- const instance = new Llm(finalLlm, { apiKey, model: finalModel });
5279
- return instance.operate(input, operateOptions);
5349
+ // Resolve fallback for static method: pass to instance if array, pass to operate options if false
5350
+ const instanceFallback = Array.isArray(fallback) ? fallback : undefined;
5351
+ const operateFallback = fallback === false ? false : undefined;
5352
+ const instance = new Llm(finalLlm, {
5353
+ apiKey,
5354
+ fallback: instanceFallback,
5355
+ model: finalModel,
5356
+ });
5357
+ return instance.operate(input, {
5358
+ ...operateOptions,
5359
+ ...(operateFallback !== undefined && { fallback: operateFallback }),
5360
+ });
5280
5361
  }
5281
5362
  static stream(input, options) {
5282
5363
  const { llm, apiKey, model, ...streamOptions } = options || {};