@ax-llm/ax 11.0.0 → 11.0.1

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/index.cjs CHANGED
@@ -54,6 +54,7 @@ __export(index_exports, {
54
54
  AxAIMistralModel: () => AxAIMistralModel,
55
55
  AxAIOllama: () => AxAIOllama,
56
56
  AxAIOpenAI: () => AxAIOpenAI,
57
+ AxAIOpenAIBase: () => AxAIOpenAIBase,
57
58
  AxAIOpenAIEmbedModel: () => AxAIOpenAIEmbedModel,
58
59
  AxAIOpenAIModel: () => AxAIOpenAIModel,
59
60
  AxAIReka: () => AxAIReka,
@@ -750,8 +751,9 @@ var AxBaseAI = class {
750
751
  this.tracer = options.tracer;
751
752
  this.modelInfo = modelInfo;
752
753
  this.models = models;
754
+ this.id = crypto.randomUUID();
753
755
  const model = this.models?.find((v) => v.key === defaults.model)?.model ?? defaults.model;
754
- const embedModel = this.models?.find((v) => v.key === defaults.embedModel)?.model ?? defaults.embedModel;
756
+ const embedModel = defaults.embedModel;
755
757
  this.defaults = { model, embedModel };
756
758
  if (!defaults.model || typeof defaults.model !== "string" || defaults.model === "") {
757
759
  throw new Error("No model defined");
@@ -769,6 +771,7 @@ var AxBaseAI = class {
769
771
  defaults;
770
772
  apiURL;
771
773
  name;
774
+ id;
772
775
  headers;
773
776
  supportFor;
774
777
  // Add private metrics tracking properties
@@ -803,6 +806,9 @@ var AxBaseAI = class {
803
806
  setName(name) {
804
807
  this.name = name;
805
808
  }
809
+ getId() {
810
+ return this.id;
811
+ }
806
812
  setAPIURL(apiURL) {
807
813
  this.apiURL = apiURL;
808
814
  }
@@ -848,8 +854,7 @@ var AxBaseAI = class {
848
854
  }
849
855
  const mi = getModelInfo({
850
856
  model: this.defaults.embedModel,
851
- modelInfo: this.modelInfo,
852
- models: this.models
857
+ modelInfo: this.modelInfo
853
858
  });
854
859
  return {
855
860
  ...mi,
@@ -1055,7 +1060,7 @@ var AxBaseAI = class {
1055
1060
  }
1056
1061
  }
1057
1062
  async _embed1(req, options) {
1058
- const embedModel = req.embedModel ? this.models?.find((v) => v.key === req.embedModel)?.model ?? req.embedModel : this.defaults.embedModel;
1063
+ const embedModel = req.embedModel ?? this.defaults.embedModel;
1059
1064
  if (!embedModel) {
1060
1065
  throw new Error("No embed model defined");
1061
1066
  }
@@ -1066,7 +1071,7 @@ var AxBaseAI = class {
1066
1071
  kind: import_api2.SpanKind.SERVER,
1067
1072
  attributes: {
1068
1073
  [axSpanAttributes.LLM_SYSTEM]: this.name,
1069
- [axSpanAttributes.LLM_REQUEST_MODEL]: req.embedModel ?? this.defaults.embedModel
1074
+ [axSpanAttributes.LLM_REQUEST_MODEL]: embedModel
1070
1075
  }
1071
1076
  },
1072
1077
  async (span) => {
@@ -1245,13 +1250,13 @@ var AxAIAnthropicModel = /* @__PURE__ */ ((AxAIAnthropicModel2) => {
1245
1250
  AxAIAnthropicModel2["ClaudeInstant12"] = "claude-instant-1.2";
1246
1251
  return AxAIAnthropicModel2;
1247
1252
  })(AxAIAnthropicModel || {});
1248
- var AxAIAnthropicVertexModel = /* @__PURE__ */ ((AxAIAnthropicVertexModel2) => {
1249
- AxAIAnthropicVertexModel2["Claude35Haiku"] = "claude-3-5-haiku";
1250
- AxAIAnthropicVertexModel2["Claude35Sonnet"] = "claude-3-5-sonnet";
1251
- AxAIAnthropicVertexModel2["Claude35SonnetV2"] = "claude-3-5-sonnet-v2";
1252
- AxAIAnthropicVertexModel2["Claude3Haiku"] = "claude-3-haiku";
1253
- AxAIAnthropicVertexModel2["Claude3Opus"] = "claude-3-opus";
1254
- return AxAIAnthropicVertexModel2;
1253
+ var AxAIAnthropicVertexModel = /* @__PURE__ */ ((AxAIAnthropicVertexModel3) => {
1254
+ AxAIAnthropicVertexModel3["Claude35Haiku"] = "claude-3-5-haiku";
1255
+ AxAIAnthropicVertexModel3["Claude35Sonnet"] = "claude-3-5-sonnet";
1256
+ AxAIAnthropicVertexModel3["Claude35SonnetV2"] = "claude-3-5-sonnet-v2";
1257
+ AxAIAnthropicVertexModel3["Claude3Haiku"] = "claude-3-haiku";
1258
+ AxAIAnthropicVertexModel3["Claude3Opus"] = "claude-3-opus";
1259
+ return AxAIAnthropicVertexModel3;
1255
1260
  })(AxAIAnthropicVertexModel || {});
1256
1261
 
1257
1262
  // ai/anthropic/info.ts
@@ -2055,26 +2060,22 @@ function createMessages2(req) {
2055
2060
  }
2056
2061
  });
2057
2062
  }
2058
- var AxAIOpenAI = class extends AxBaseAI {
2063
+ var AxAIOpenAIBase = class extends AxBaseAI {
2059
2064
  constructor({
2060
2065
  apiKey,
2061
2066
  config,
2062
2067
  options,
2063
2068
  apiURL,
2064
- modelInfo = axModelInfoOpenAI,
2069
+ modelInfo,
2065
2070
  models
2066
2071
  }) {
2067
2072
  if (!apiKey || apiKey === "") {
2068
2073
  throw new Error("OpenAI API key not set");
2069
2074
  }
2070
- const _config = {
2071
- ...axAIOpenAIDefaultConfig(),
2072
- ...config
2073
- };
2074
2075
  const aiImpl = new AxAIOpenAIImpl(
2075
- _config,
2076
+ config,
2076
2077
  options?.streamingUsage ?? true,
2077
- config?.dimensions
2078
+ config.dimensions
2078
2079
  );
2079
2080
  super(aiImpl, {
2080
2081
  name: "OpenAI",
@@ -2082,8 +2083,8 @@ var AxAIOpenAI = class extends AxBaseAI {
2082
2083
  headers: async () => ({ Authorization: `Bearer ${apiKey}` }),
2083
2084
  modelInfo,
2084
2085
  defaults: {
2085
- model: _config.model,
2086
- embedModel: _config.embedModel
2086
+ model: config.model,
2087
+ embedModel: config.embedModel
2087
2088
  },
2088
2089
  options,
2089
2090
  supportFor: () => {
@@ -2096,10 +2097,33 @@ var AxAIOpenAI = class extends AxBaseAI {
2096
2097
  var isReasoningModel = (model) => ["o1-mini" /* O1Mini */, "o1" /* O1 */, "o3-mini" /* O3Mini */].includes(
2097
2098
  model
2098
2099
  );
2100
+ var AxAIOpenAI = class extends AxAIOpenAIBase {
2101
+ constructor({
2102
+ apiKey,
2103
+ config,
2104
+ options,
2105
+ models
2106
+ }) {
2107
+ if (!apiKey || apiKey === "") {
2108
+ throw new Error("OpenAI API key not set");
2109
+ }
2110
+ super({
2111
+ apiKey,
2112
+ config: {
2113
+ ...axAIOpenAIDefaultConfig(),
2114
+ ...config
2115
+ },
2116
+ options,
2117
+ modelInfo: axModelInfoOpenAI,
2118
+ models
2119
+ });
2120
+ super.setName("OpenAI");
2121
+ }
2122
+ };
2099
2123
 
2100
2124
  // ai/azure-openai/api.ts
2101
2125
  var axAIAzureOpenAIDefaultConfig = axAIOpenAIDefaultConfig;
2102
- var AxAIAzureOpenAI = class extends AxAIOpenAI {
2126
+ var AxAIAzureOpenAI = class extends AxAIOpenAIBase {
2103
2127
  constructor({
2104
2128
  apiKey,
2105
2129
  resourceName,
@@ -2122,7 +2146,13 @@ var AxAIAzureOpenAI = class extends AxAIOpenAI {
2122
2146
  ...axAIAzureOpenAIDefaultConfig(),
2123
2147
  ...config
2124
2148
  };
2125
- super({ apiKey, config: _config, options, models });
2149
+ super({
2150
+ apiKey,
2151
+ config: _config,
2152
+ options,
2153
+ models,
2154
+ modelInfo: axModelInfoOpenAI
2155
+ });
2126
2156
  const host = resourceName.includes("://") ? resourceName : `https://${resourceName}.openai.azure.com/`;
2127
2157
  super.setName("Azure OpenAI");
2128
2158
  super.setAPIURL(
@@ -2485,7 +2515,7 @@ var axAIDeepSeekDefaultConfig = () => structuredClone({
2485
2515
  model: "deepseek-chat" /* DeepSeekChat */,
2486
2516
  ...axBaseAIDefaultConfig()
2487
2517
  });
2488
- var AxAIDeepSeek = class extends AxAIOpenAI {
2518
+ var AxAIDeepSeek = class extends AxAIOpenAIBase {
2489
2519
  constructor({
2490
2520
  apiKey,
2491
2521
  config,
@@ -3049,7 +3079,7 @@ var axAIGroqDefaultConfig = () => structuredClone({
3049
3079
  model: "llama-3.3-70b-versatile" /* Llama33_70B */,
3050
3080
  ...axBaseAIDefaultConfig()
3051
3081
  });
3052
- var AxAIGroq = class extends AxAIOpenAI {
3082
+ var AxAIGroq = class extends AxAIOpenAIBase {
3053
3083
  constructor({
3054
3084
  apiKey,
3055
3085
  config,
@@ -3294,7 +3324,7 @@ var axAIMistralDefaultConfig = () => structuredClone({
3294
3324
  model: "mistral-small-latest" /* MistralSmall */,
3295
3325
  ...axBaseAIDefaultConfig()
3296
3326
  });
3297
- var AxAIMistral = class extends AxAIOpenAI {
3327
+ var AxAIMistral = class extends AxAIOpenAIBase {
3298
3328
  constructor({
3299
3329
  apiKey,
3300
3330
  config,
@@ -3326,7 +3356,7 @@ var axAIOllamaDefaultConfig = () => structuredClone({
3326
3356
  model: "nous-hermes2",
3327
3357
  embedModel: "all-minilm"
3328
3358
  });
3329
- var AxAIOllama = class extends AxAIOpenAI {
3359
+ var AxAIOllama = class extends AxAIOpenAIBase {
3330
3360
  constructor({
3331
3361
  apiKey = "not-set",
3332
3362
  url = "http://localhost:11434/v1",
@@ -3343,7 +3373,8 @@ var AxAIOllama = class extends AxAIOpenAI {
3343
3373
  options,
3344
3374
  config: _config,
3345
3375
  apiURL: url,
3346
- models
3376
+ models,
3377
+ modelInfo: []
3347
3378
  });
3348
3379
  super.setName("Ollama");
3349
3380
  }
@@ -3580,7 +3611,7 @@ var axAITogetherDefaultConfig = () => structuredClone({
3580
3611
  model: "mistralai/Mixtral-8x7B-Instruct-v0.1",
3581
3612
  ...axBaseAIDefaultConfig()
3582
3613
  });
3583
- var AxAITogether = class extends AxAIOpenAI {
3614
+ var AxAITogether = class extends AxAIOpenAIBase {
3584
3615
  constructor({
3585
3616
  apiKey,
3586
3617
  config,
@@ -3654,6 +3685,9 @@ var AxAI = class {
3654
3685
  getName() {
3655
3686
  return this.ai.getName();
3656
3687
  }
3688
+ getId() {
3689
+ return this.ai.getId();
3690
+ }
3657
3691
  getModelInfo() {
3658
3692
  return this.ai.getModelInfo();
3659
3693
  }
@@ -6255,6 +6289,10 @@ var AxBalancer = class _AxBalancer {
6255
6289
  currentServiceIndex = 0;
6256
6290
  currentService;
6257
6291
  debug;
6292
+ initialBackoffMs;
6293
+ maxBackoffMs;
6294
+ maxRetries;
6295
+ serviceFailures = /* @__PURE__ */ new Map();
6258
6296
  constructor(services, options) {
6259
6297
  if (services.length === 0) {
6260
6298
  throw new Error("No AI services provided.");
@@ -6268,6 +6306,9 @@ var AxBalancer = class _AxBalancer {
6268
6306
  }
6269
6307
  this.currentService = cs;
6270
6308
  this.debug = options?.debug ?? true;
6309
+ this.initialBackoffMs = options?.initialBackoffMs ?? 1e3;
6310
+ this.maxBackoffMs = options?.maxBackoffMs ?? 32e3;
6311
+ this.maxRetries = options?.maxRetries ?? 3;
6271
6312
  }
6272
6313
  /**
6273
6314
  * Service comparator that respects the input order of services.
@@ -6284,7 +6325,7 @@ var AxBalancer = class _AxBalancer {
6284
6325
  return aTotalCost - bTotalCost;
6285
6326
  };
6286
6327
  getModelList() {
6287
- throw new Error("Method not implemented.");
6328
+ return this.currentService.getModelList();
6288
6329
  }
6289
6330
  getNextService() {
6290
6331
  const cs = this.services[++this.currentServiceIndex];
@@ -6305,6 +6346,9 @@ var AxBalancer = class _AxBalancer {
6305
6346
  getName() {
6306
6347
  return this.currentService.getName();
6307
6348
  }
6349
+ getId() {
6350
+ return this.currentService.getId();
6351
+ }
6308
6352
  getModelInfo() {
6309
6353
  return this.currentService.getModelInfo();
6310
6354
  }
@@ -6317,11 +6361,56 @@ var AxBalancer = class _AxBalancer {
6317
6361
  getMetrics() {
6318
6362
  return this.currentService.getMetrics();
6319
6363
  }
6364
+ canRetryService() {
6365
+ const failure = this.serviceFailures.get(this.currentService.getId());
6366
+ if (!failure) return true;
6367
+ const { retries, lastFailureTime } = failure;
6368
+ const timeSinceLastFailure = Date.now() - lastFailureTime;
6369
+ const backoffMs = Math.min(
6370
+ this.initialBackoffMs * Math.pow(2, retries),
6371
+ this.maxBackoffMs
6372
+ );
6373
+ return timeSinceLastFailure >= backoffMs;
6374
+ }
6375
+ handleFailure() {
6376
+ const failure = this.serviceFailures.get(this.currentService.getId());
6377
+ const retries = (failure?.retries ?? 0) + 1;
6378
+ this.serviceFailures.set(this.currentService.getId(), {
6379
+ retries,
6380
+ lastFailureTime: Date.now()
6381
+ });
6382
+ if (this.debug) {
6383
+ console.warn(
6384
+ `AxBalancer: Service ${this.currentService.getName()} failed (retry ${retries}/${this.maxRetries})`
6385
+ );
6386
+ }
6387
+ if (retries >= this.maxRetries) {
6388
+ const gotNextService = this.getNextService();
6389
+ if (this.debug) {
6390
+ console.warn(
6391
+ `AxBalancer: Switching to service ${this.currentService.getName()}`
6392
+ );
6393
+ }
6394
+ return gotNextService;
6395
+ }
6396
+ return true;
6397
+ }
6398
+ handleSuccess() {
6399
+ this.serviceFailures.delete(this.currentService.getId());
6400
+ }
6320
6401
  async chat(req, options) {
6321
6402
  this.reset();
6322
6403
  while (true) {
6404
+ if (!this.canRetryService()) {
6405
+ if (!this.getNextService()) {
6406
+ throw new Error("All services exhausted");
6407
+ }
6408
+ continue;
6409
+ }
6323
6410
  try {
6324
- return await this.currentService.chat(req, options);
6411
+ const response = await this.currentService.chat(req, options);
6412
+ this.handleSuccess();
6413
+ return response;
6325
6414
  } catch (e) {
6326
6415
  if (!(e instanceof AxAIServiceError)) {
6327
6416
  throw e;
@@ -6342,38 +6431,29 @@ var AxBalancer = class _AxBalancer {
6342
6431
  default:
6343
6432
  throw e;
6344
6433
  }
6345
- if (this.debug) {
6346
- console.warn(
6347
- `AxBalancer: Service ${this.currentService.getName()} failed`,
6348
- e
6349
- );
6350
- }
6351
- if (!this.getNextService()) {
6434
+ if (!this.handleFailure()) {
6352
6435
  throw e;
6353
6436
  }
6354
- if (this.debug) {
6355
- console.warn(
6356
- `AxBalancer: Switching to service ${this.currentService.getName()}`
6357
- );
6358
- }
6359
6437
  }
6360
6438
  }
6361
6439
  }
6362
6440
  async embed(req, options) {
6363
6441
  this.reset();
6364
6442
  while (true) {
6443
+ if (!this.canRetryService()) {
6444
+ if (!this.getNextService()) {
6445
+ throw new Error("All services exhausted");
6446
+ }
6447
+ continue;
6448
+ }
6365
6449
  try {
6366
- return await this.currentService.embed(req, options);
6450
+ const response = await this.currentService.embed(req, options);
6451
+ this.handleSuccess();
6452
+ return response;
6367
6453
  } catch (e) {
6368
- if (this.debug) {
6369
- console.warn(`Service ${this.currentService.getName()} failed`);
6370
- }
6371
- if (!this.getNextService()) {
6454
+ if (!this.handleFailure()) {
6372
6455
  throw e;
6373
6456
  }
6374
- if (this.debug) {
6375
- console.warn(`Switching to service ${this.currentService.getName()}`);
6376
- }
6377
6457
  }
6378
6458
  }
6379
6459
  }
@@ -7866,6 +7946,7 @@ var AxEmbeddingAdapter = class {
7866
7946
  var AxMockAIService = class {
7867
7947
  constructor(config = {}) {
7868
7948
  this.config = config;
7949
+ this.config.id = this.config.id ?? crypto.randomUUID();
7869
7950
  }
7870
7951
  options = {};
7871
7952
  metrics = {
@@ -7881,6 +7962,9 @@ var AxMockAIService = class {
7881
7962
  getName() {
7882
7963
  return this.config.name ?? "mock-ai-service";
7883
7964
  }
7965
+ getId() {
7966
+ return this.config.id ?? "mock-ai-service-id";
7967
+ }
7884
7968
  getModelInfo() {
7885
7969
  return {
7886
7970
  name: "mock-model",
@@ -8037,6 +8121,7 @@ var AxRAG = class extends AxChainOfThought {
8037
8121
  AxAIMistralModel,
8038
8122
  AxAIOllama,
8039
8123
  AxAIOpenAI,
8124
+ AxAIOpenAIBase,
8040
8125
  AxAIOpenAIEmbedModel,
8041
8126
  AxAIOpenAIModel,
8042
8127
  AxAIReka,